///|
/// Builtin function helpers and dispatch for the moonpython runtime.
///
/// Builtin implementations are split across runtime_builtins_*.mbt.
/// This file centralizes builtin dispatch so `moonpython.mbt` can focus on
/// expression evaluation and general call semantics.

///|
fn unexpected_keywords_error(name : String) -> RuntimeError {
  make_runtime_error(
    RuntimeErrorKind::Type,
    name + "() got unexpected keyword arguments".to_string(),
  )
}

///|
fn ensure_no_keywords(
  name : String,
  keywords : Array[(String, Value)],
) -> Result[Unit, RuntimeError] {
  if keywords.length() > 0 {
    Err(unexpected_keywords_error(name))
  } else {
    Ok(())
  }
}

///|
fn touch_env(
  locals : Array[(String, Value)],
  globals : Array[(String, Value)],
  builtins : Array[(String, Value)],
  io : MockIO,
) -> Unit {
  let _ = locals
  let _ = globals
  let _ = builtins
  let _ = io
}

///|
fn unexpected_keyword_argument_error(
  name : String,
  key : String,
) -> RuntimeError {
  make_runtime_error(
    RuntimeErrorKind::Type,
    name + "() got an unexpected keyword argument '" + key + "'",
  )
}

///|
fn multiple_values_error(name : String, key : String) -> RuntimeError {
  make_runtime_error(
    RuntimeErrorKind::Type,
    name + "() got multiple values for argument '" + key + "'",
  )
}

///|
fn missing_required_argument_error(
  name : String,
  arg_name : String,
) -> RuntimeError {
  make_runtime_error(
    RuntimeErrorKind::Type,
    name + "() missing required argument '" + arg_name + "'",
  )
}

///|
fn too_many_arguments_error(name : String, given : Int32) -> RuntimeError {
  make_runtime_error(
    RuntimeErrorKind::Type,
    name + "() takes at most 3 arguments (" + given.to_string() + " given)",
  )
}

///|
fn dict_env_from_value(
  name : String,
  kind : String,
  value : Value,
) -> Result[(Array[(String, Value)], Array[(Value, Value)]?), RuntimeError] {
  match value {
    Value::Instance(inst) =>
      if inst.class.name == "module_globals_dict" {
        match get_named_value(inst.dict, "$__env_id__") {
          Some(Value::Int(id)) =>
            match lookup_env_mapping(id) {
              Some(env) => Ok((env, None))
              None =>
                Err(
                  make_runtime_error(
                    RuntimeErrorKind::Runtime,
                    name + "() " + kind + ": stale globals mapping".to_string(),
                  ),
                )
            }
          _ =>
            Err(
              make_runtime_error(
                RuntimeErrorKind::Type,
                name + "() " + kind + ": invalid globals mapping".to_string(),
              ),
            )
        }
      } else if class_includes_dict(inst.class) {
        let pairs = match get_named_value(inst.dict, dict_storage_name) {
          Some(Value::Dict(pairs)) => pairs
          Some(_) =>
            return Err(
              make_runtime_error(
                RuntimeErrorKind::Type,
                name + "() " + kind + " must be a dict".to_string(),
              ),
            )
          None => {
            let pairs : Array[(Value, Value)] = []
            set_named_value(inst.dict, dict_storage_name, Value::Dict(pairs))
            pairs
          }
        }
        let env : Array[(String, Value)] = []
        for pair in pairs {
          match pair.0 {
            Value::Str(key) => set_global_value(env, key, pair.1)
            _ =>
              return Err(
                make_runtime_error(
                  RuntimeErrorKind::Type,
                  name + "() " + kind + " keys must be str".to_string(),
                ),
              )
          }
        }
        Ok((env, Some(pairs)))
      } else {
        Err(
          make_runtime_error(
            RuntimeErrorKind::Type,
            name + "() " + kind + " must be a dict".to_string(),
          ),
        )
      }
    Value::Dict(pairs) => {
      let env : Array[(String, Value)] = []
      for pair in pairs {
        match pair.0 {
          Value::Str(key) => set_global_value(env, key, pair.1)
          _ =>
            return Err(
              make_runtime_error(
                RuntimeErrorKind::Type,
                name + "() " + kind + " keys must be str".to_string(),
              ),
            )
        }
      }
      Ok((env, Some(pairs)))
    }
    _ =>
      Err(
        make_runtime_error(
          RuntimeErrorKind::Type,
          name + "() " + kind + " must be a dict".to_string(),
        ),
      )
  }
}

///|
fn dict_pairs_from_value(
  name : String,
  value : Value,
) -> Result[Array[(Value, Value)], RuntimeError] {
  match value {
    Value::Dict(pairs) => Ok(pairs)
    Value::Instance(inst) =>
      if class_includes_dict(inst.class) {
        match get_named_value(inst.dict, dict_storage_name) {
          Some(Value::Dict(pairs)) => Ok(pairs)
          Some(_) =>
            Err(
              make_runtime_error(
                RuntimeErrorKind::Type,
                name + "() expects a dict".to_string(),
              ),
            )
          None => {
            let pairs : Array[(Value, Value)] = []
            set_named_value(inst.dict, dict_storage_name, Value::Dict(pairs))
            Ok(pairs)
          }
        }
      } else {
        Err(
          make_runtime_error(
            RuntimeErrorKind::Type,
            name + "() expects a dict".to_string(),
          ),
        )
      }
    _ =>
      Err(
        make_runtime_error(
          RuntimeErrorKind::Type,
          name + "() expects a dict".to_string(),
        ),
      )
  }
}

///|
fn sync_env_to_dict(
  env : Array[(String, Value)],
  pairs : Array[(Value, Value)],
) -> Unit {
  while pairs.length() > 0 {
    let _ = pairs.pop()
  }
  for pair in env {
    pairs.push((Value::Str(pair.0), pair.1))
  }
}

///|
fn normalize_exec_eval_arg(value_opt : Value?) -> Value? {
  match value_opt {
    Some(Value::None) => None
    _ => value_opt
  }
}

///|
fn resolve_exec_eval_env(
  name : String,
  globals_arg : Value?,
  locals_arg : Value?,
  locals : Array[(String, Value)],
  globals : Array[(String, Value)],
) -> Result[
  (
    Array[(String, Value)],
    Array[(String, Value)],
    Array[(Value, Value)]?,
    Array[(Value, Value)]?,
  ),
  RuntimeError,
] {
  let globals_value = normalize_exec_eval_arg(globals_arg)
  let locals_value = normalize_exec_eval_arg(locals_arg)
  let mut globals_env = globals
  let mut locals_env = locals
  let mut globals_pairs : Array[(Value, Value)]? = None
  let mut locals_pairs : Array[(Value, Value)]? = None
  match globals_value {
    Some(value) => {
      let (env, pairs) = match dict_env_from_value(name, "globals", value) {
        Ok(v) => v
        Err(err) => return Err(err)
      }
      globals_env = env
      globals_pairs = pairs
    }
    None => ()
  }
  match locals_value {
    Some(value) => {
      let (env, pairs) = match dict_env_from_value(name, "locals", value) {
        Ok(v) => v
        Err(err) => return Err(err)
      }
      locals_env = env
      locals_pairs = pairs
    }
    None => ()
  }
  if globals_value is Some(_) && locals_value is None {
    locals_env = globals_env
    locals_pairs = globals_pairs
  }
  Ok((locals_env, globals_env, locals_pairs, globals_pairs))
}

///|
fn parse_exec_eval_args(
  name : String,
  positional : Array[Value],
  keywords : Array[(String, Value)],
  required_label : String,
) -> Result[(Value, Value?, Value?), RuntimeError] {
  if positional.length() == 0 {
    return Err(missing_required_argument_error(name, required_label))
  }
  if positional.length() > 3 {
    return Err(too_many_arguments_error(name, positional.length()))
  }
  let mut globals_arg : Value? = None
  let mut locals_arg : Value? = None
  if positional.length() > 1 {
    globals_arg = Some(positional[1])
  }
  if positional.length() > 2 {
    locals_arg = Some(positional[2])
  }
  for pair in keywords {
    let key = pair.0
    let value = pair.1
    match key {
      "globals" =>
        if globals_arg is Some(_) {
          return Err(multiple_values_error(name, "globals"))
        } else {
          globals_arg = Some(value)
        }
      "locals" =>
        if locals_arg is Some(_) {
          return Err(multiple_values_error(name, "locals"))
        } else {
          locals_arg = Some(value)
        }
      _ => return Err(unexpected_keyword_argument_error(name, key))
    }
  }
  Ok((positional[0], globals_arg, locals_arg))
}

///|
fn reverse_values(items : Array[Value]) -> Array[Value] {
  let out : Array[Value] = []
  let mut i = items.length()
  while i > 0 {
    i = i - 1
    out.push(items[i])
  }
  out
}

///|
fn collect_items_from_iterable(
  value : Value,
  globals : Array[(String, Value)],
  builtins : Array[(String, Value)],
  io : MockIO,
) -> Result[Array[Value], RuntimeError] {
  let iterator = match iter_value_to_iterator(value, globals, builtins, io) {
    Ok(v) => v
    Err(err) => return Err(err)
  }
  let out : Array[Value] = []
  while true {
    match iterator_next(iterator, None, globals, builtins, io) {
      Ok(item) => out.push(item)
      Err(err) =>
        if err.exc_type == "StopIteration" {
          break
        } else {
          return Err(err)
        }
    }
  }
  Ok(out)
}

///|
priv enum SortKind {
  Number
  String
  Tuple
  List
} derive(Eq)

///|
fn sort_kind_for_sorted(value : Value) -> SortKind? {
  match value {
    Value::Int(_) | Value::Float(_) | Value::Bool(_) => Some(SortKind::Number)
    Value::Str(_) => Some(SortKind::String)
    Value::Tuple(_) => Some(SortKind::Tuple)
    Value::List(_) => Some(SortKind::List)
    _ => None
  }
}

///|
fn cmp_string_for_sorted(a : String, b : String) -> Int32 {
  let aa = a.to_array()
  let bb = b.to_array()
  let mut i = 0
  while i < aa.length() && i < bb.length() {
    let ca = aa[i]
    let cb = bb[i]
    if ca < cb {
      return -1
    }
    if ca > cb {
      return 1
    }
    i = i + 1
  }
  if aa.length() < bb.length() {
    -1
  } else if aa.length() > bb.length() {
    1
  } else {
    0
  }
}

///|
fn cmp_value_for_sorted_dynamic(
  a : Value,
  b : Value,
) -> Result[Int32, RuntimeError] {
  match (sort_kind_for_sorted(a), sort_kind_for_sorted(b)) {
    (Some(kind_a), Some(kind_b)) =>
      if kind_a == kind_b {
        cmp_value_for_sorted(kind_a, a, b)
      } else {
        Ok(cmp_string_for_sorted(value_to_string(a), value_to_string(b)))
      }
    _ => Ok(cmp_string_for_sorted(value_to_string(a), value_to_string(b)))
  }
}

///|
fn cmp_value_for_sorted(
  kind : SortKind,
  a : Value,
  b : Value,
) -> Result[Int32, RuntimeError] {
  match kind {
    SortKind::Number => {
      let (_, an) = match number_value(a) {
        Ok(v) => v
        Err(err) => return Err(err)
      }
      let (_, bn) = match number_value(b) {
        Ok(v) => v
        Err(err) => return Err(err)
      }
      if an < bn {
        Ok(-1)
      } else if an > bn {
        Ok(1)
      } else {
        Ok(0)
      }
    }
    SortKind::String =>
      match (a, b) {
        (Value::Str(aa), Value::Str(bb)) => Ok(cmp_string_for_sorted(aa, bb))
        _ =>
          Err(
            make_runtime_error(
              RuntimeErrorKind::Type,
              "sorted() cannot compare values".to_string(),
            ),
          )
      }
    SortKind::Tuple => {
      let values_a = match a {
        Value::Tuple(values) => values
        _ =>
          return Err(
            make_runtime_error(
              RuntimeErrorKind::Type,
              "sorted() cannot compare values".to_string(),
            ),
          )
      }
      let values_b = match b {
        Value::Tuple(values) => values
        _ =>
          return Err(
            make_runtime_error(
              RuntimeErrorKind::Type,
              "sorted() cannot compare values".to_string(),
            ),
          )
      }
      let mut i = 0
      while i < values_a.length() && i < values_b.length() {
        let cmp = match cmp_value_for_sorted_dynamic(values_a[i], values_b[i]) {
          Ok(v) => v
          Err(err) => return Err(err)
        }
        if cmp != 0 {
          return Ok(cmp)
        }
        i += 1
      }
      if values_a.length() < values_b.length() {
        Ok(-1)
      } else if values_a.length() > values_b.length() {
        Ok(1)
      } else {
        Ok(0)
      }
    }
    SortKind::List => {
      let values_a = match a {
        Value::List(values) => values
        _ =>
          return Err(
            make_runtime_error(
              RuntimeErrorKind::Type,
              "sorted() cannot compare values".to_string(),
            ),
          )
      }
      let values_b = match b {
        Value::List(values) => values
        _ =>
          return Err(
            make_runtime_error(
              RuntimeErrorKind::Type,
              "sorted() cannot compare values".to_string(),
            ),
          )
      }
      let mut i = 0
      while i < values_a.length() && i < values_b.length() {
        let cmp = match cmp_value_for_sorted_dynamic(values_a[i], values_b[i]) {
          Ok(v) => v
          Err(err) => return Err(err)
        }
        if cmp != 0 {
          return Ok(cmp)
        }
        i += 1
      }
      if values_a.length() < values_b.length() {
        Ok(-1)
      } else if values_a.length() > values_b.length() {
        Ok(1)
      } else {
        Ok(0)
      }
    }
  }
}

///|
fn stable_sort_for_sorted(
  items : Array[Value],
  kind : SortKind,
) -> Result[Array[Value], RuntimeError] {
  let mut out : Array[Value] = []
  for item in items {
    let mut inserted = false
    let next : Array[Value] = []
    for existing in out {
      if !inserted {
        let cmp = match cmp_value_for_sorted(kind, item, existing) {
          Ok(v) => v
          Err(err) => return Err(err)
        }
        if cmp < 0 {
          next.push(item)
          inserted = true
        }
      }
      next.push(existing)
    }
    if !inserted {
      next.push(item)
    }
    out = next
  }
  Ok(out)
}

///|
fn stable_sort_pairs_by_key(
  pairs : Array[(Value, Value)],
  kind : SortKind,
) -> Result[Array[(Value, Value)], RuntimeError] {
  let mut out : Array[(Value, Value)] = []
  for pair in pairs {
    let mut inserted = false
    let next : Array[(Value, Value)] = []
    for existing in out {
      if !inserted {
        let cmp = match cmp_value_for_sorted(kind, pair.0, existing.0) {
          Ok(v) => v
          Err(err) => return Err(err)
        }
        if cmp < 0 {
          next.push(pair)
          inserted = true
        }
      }
      next.push(existing)
    }
    if !inserted {
      next.push(pair)
    }
    out = next
  }
  Ok(out)
}

///|
fn builtin_reduce_ex(
  positional : Array[Value],
  keywords : Array[(String, Value)],
  locals : Array[(String, Value)],
  globals : Array[(String, Value)],
  builtins : Array[(String, Value)],
  io : MockIO,
) -> Result[Value, RuntimeError] {
  touch_env(locals, globals, builtins, io)
  let _ = match ensure_no_keywords("__reduce_ex__", keywords) {
    Ok(v) => v
    Err(err) => return Err(err)
  }
  if positional.length() != 2 {
    return Err(
      make_runtime_error(
        RuntimeErrorKind::Type,
        "__reduce_ex__() takes exactly 2 arguments".to_string(),
      ),
    )
  }
  let target = positional[0]
  let proto = positional[1]
  match proto {
    Value::Int(_) => ()
    _ =>
      return Err(
        make_runtime_error(
          RuntimeErrorKind::Type,
          "__reduce_ex__() proto must be int".to_string(),
        ),
      )
  }
  let inst = match target {
    Value::Instance(v) => v
    _ =>
      return Err(
        make_runtime_error(
          RuntimeErrorKind::Type,
          "__reduce_ex__() expects an instance".to_string(),
        ),
      )
  }
  let copyreg_value = match
    import_module("copyreg", globals, builtins, io, current_config()) {
    Ok(v) => v
    Err(err) => return Err(err)
  }
  let newobj_value = match copyreg_value {
    Value::Instance(mod_inst) =>
      match get_named_value(mod_inst.dict, "__newobj__") {
        Some(v) => v
        None =>
          return Err(
            make_runtime_error(
              RuntimeErrorKind::Runtime,
              "RuntimeError: copyreg.__newobj__ is not available".to_string(),
            ),
          )
      }
    _ =>
      return Err(
        make_runtime_error(
          RuntimeErrorKind::Runtime,
          "RuntimeError: copyreg is not a module".to_string(),
        ),
      )
  }
  let args_tuple = Value::Tuple([Value::Class(inst.class)])
  let state_pairs : Array[(Value, Value)] = []
  for pair in inst.dict {
    let key = pair.0
    let value = pair.1
    if key == "hashvalue" {
      continue
    }
    state_pairs.push((Value::Str(key), value))
  }
  let state_dict = Value::Dict(state_pairs)
  Ok(Value::Tuple([newobj_value, args_tuple, state_dict]))
}

///|
priv struct BuiltinDef {
  name : String
  run : (
    Array[Value],
    Array[(String, Value)],
    Array[(String, Value)],
    Array[(String, Value)],
    Array[(String, Value)],
    MockIO,
  ) -> Result[Value, RuntimeError]
}

///|
let builtin_defs_ref : Ref[Array[BuiltinDef]] = { val: [], }

///|
let builtin_defs_ready : Ref[Bool] = { val: false, }

///|
fn ensure_builtin_defs_ready() -> Unit {
  if builtin_defs_ready.val {
    return
  }
  builtin_defs_ref.val = [
    BuiltinDef::{ name: "__mpython_run", run: builtin_mpython_run, },
    BuiltinDef::{
      name: "__mpython_levenshtein_distance",
      run: builtin_mpython_levenshtein_distance,
    },
    BuiltinDef::{
      name: "__mpython_asyncgenexp_next",
      run: builtin_mpython_asyncgenexp_next,
    },
    BuiltinDef::{
      name: "__mpython_asyncgen_next",
      run: builtin_mpython_asyncgen_next,
    },
    BuiltinDef::{
      name: "__mpython_asyncgen_send",
      run: builtin_mpython_asyncgen_send,
    },
    BuiltinDef::{
      name: "__mpython_asyncgen_throw",
      run: builtin_mpython_asyncgen_throw,
    },
    BuiltinDef::{
      name: "__mpython_asyncgen_close",
      run: builtin_mpython_asyncgen_close,
    },
    BuiltinDef::{
      name: "__mpython_posix_open",
      run: builtin_mpython_posix_open,
    },
    BuiltinDef::{
      name: "__mpython_posix_read",
      run: builtin_mpython_posix_read,
    },
    BuiltinDef::{
      name: "__mpython_posix_lseek",
      run: builtin_mpython_posix_lseek,
    },
    BuiltinDef::{
      name: "__mpython_posix_write",
      run: builtin_mpython_posix_write,
    },
    BuiltinDef::{
      name: "__mpython_posix_close",
      run: builtin_mpython_posix_close,
    },
    BuiltinDef::{
      name: "__mpython_posix_fstat",
      run: builtin_mpython_posix_fstat,
    },
    BuiltinDef::{
      name: "__mpython_posix_unlink",
      run: builtin_mpython_posix_unlink,
    },
    BuiltinDef::{
      name: "__mpython_posix_mkdir",
      run: builtin_mpython_posix_mkdir,
    },
    BuiltinDef::{
      name: "__mpython_posix_rmdir",
      run: builtin_mpython_posix_rmdir,
    },
    BuiltinDef::{
      name: "__mpython_posix_utime",
      run: builtin_mpython_posix_utime,
    },
    BuiltinDef::{
      name: "__mpython_posix_stat",
      run: builtin_mpython_posix_stat,
    },
    BuiltinDef::{
      name: "__mpython_posix_getcwd",
      run: builtin_mpython_posix_getcwd,
    },
    BuiltinDef::{
      name: "__mpython_posix_chdir",
      run: builtin_mpython_posix_chdir,
    },
    BuiltinDef::{
      name: "__mpython_posix_listdir",
      run: builtin_mpython_posix_listdir,
    },
    BuiltinDef::{ name: "__mpython.internal_iter", run: builtin_internal_iter, },
    BuiltinDef::{ name: "__mpython.internal_next", run: builtin_internal_next, },
    BuiltinDef::{
      name: "rangeiter.__setstate__",
      run: builtin_rangeiter_setstate,
    },
    BuiltinDef::{ name: "asyncio.run", run: builtin_asyncio_run, },
    BuiltinDef::{ name: "asyncio.gather", run: builtin_asyncio_gather, },
    BuiltinDef::{
      name: "asyncio.iscoroutinefunction",
      run: builtin_asyncio_iscoroutinefunction,
    },
    BuiltinDef::{ name: "platform.system", run: builtin_platform_system, },
    BuiltinDef::{ name: "enum.global_enum", run: builtin_enum_global_enum, },
    BuiltinDef::{ name: "platform.machine", run: builtin_platform_machine, },
    BuiltinDef::{ name: "time.time", run: builtin_time_time, },
    BuiltinDef::{ name: "time.ctime", run: builtin_time_ctime, },
    BuiltinDef::{ name: "time.monotonic", run: builtin_time_monotonic, },
    BuiltinDef::{ name: "time.perf_counter", run: builtin_time_perf_counter, },
    BuiltinDef::{
      name: "time.perf_counter_ns",
      run: builtin_time_perf_counter_ns,
    },
    BuiltinDef::{ name: "time.process_time", run: builtin_time_process_time, },
    BuiltinDef::{
      name: "time.process_time_ns",
      run: builtin_time_process_time_ns,
    },
    BuiltinDef::{ name: "time.localtime", run: builtin_time_localtime, },
    BuiltinDef::{ name: "time.gmtime", run: builtin_time_gmtime, },
    BuiltinDef::{ name: "time.sleep", run: builtin_time_sleep, },
    BuiltinDef::{ name: "time.strftime", run: builtin_time_strftime, },
    BuiltinDef::{
      name: "time.get_clock_info",
      run: builtin_time_get_clock_info,
    },
    BuiltinDef::{ name: "enum.auto", run: builtin_enum_auto, },
    BuiltinDef::{ name: "enum._simple_enum", run: builtin_enum_simple_enum, },
    BuiltinDef::{
      name: "enum._simple_enum_decorator",
      run: builtin_enum_simple_enum_decorator,
    },
    BuiltinDef::{
      name: "enum._simple_enum_decorator_call",
      run: builtin_enum_simple_enum_decorator_call,
    },
    BuiltinDef::{ name: "atexit.register", run: builtin_atexit_register, },
    BuiltinDef::{
      name: "socket.socket.__init__",
      run: builtin_socket_socket_init,
    },
    BuiltinDef::{
      name: "socket.socket.connect",
      run: builtin_socket_socket_connect,
    },
    BuiltinDef::{
      name: "socket.socket.close",
      run: builtin_socket_socket_close,
    },
    BuiltinDef::{ name: "socket.socket.send", run: builtin_socket_socket_send, },
    BuiltinDef::{
      name: "socket.socket.sendall",
      run: builtin_socket_socket_sendall,
    },
    BuiltinDef::{
      name: "socket.socket.sendto",
      run: builtin_socket_socket_sendto,
    },
    BuiltinDef::{ name: "socket.socket.recv", run: builtin_socket_socket_recv, },
    BuiltinDef::{
      name: "socket.socket.settimeout",
      run: builtin_socket_socket_settimeout,
    },
    BuiltinDef::{
      name: "socket.create_connection",
      run: builtin_socket_create_connection,
    },
    BuiltinDef::{ name: "socket.getaddrinfo", run: builtin_socket_getaddrinfo, },
    BuiltinDef::{ name: "faulthandler.enable", run: builtin_faulthandler_noop, },
    BuiltinDef::{
      name: "faulthandler.disable",
      run: builtin_faulthandler_noop,
    },
    BuiltinDef::{
      name: "faulthandler.register",
      run: builtin_faulthandler_noop,
    },
    BuiltinDef::{
      name: "faulthandler.unregister",
      run: builtin_faulthandler_noop,
    },
    BuiltinDef::{
      name: "faulthandler.dump_traceback",
      run: builtin_faulthandler_noop,
    },
    BuiltinDef::{
      name: "faulthandler.dump_traceback_later",
      run: builtin_faulthandler_noop,
    },
    BuiltinDef::{
      name: "faulthandler.cancel_dump_traceback_later",
      run: builtin_faulthandler_noop,
    },
    BuiltinDef::{
      name: "faulthandler.is_enabled",
      run: builtin_faulthandler_is_enabled,
    },
    BuiltinDef::{ name: "select.select", run: builtin_select_select, },
    BuiltinDef::{ name: "_struct.calcsize", run: builtin_struct_calcsize, },
    BuiltinDef::{ name: "_struct.pack", run: builtin_struct_pack, },
    BuiltinDef::{ name: "_struct.pack_into", run: builtin_struct_pack_into, },
    BuiltinDef::{ name: "_struct.unpack", run: builtin_struct_unpack, },
    BuiltinDef::{
      name: "_struct.unpack_from",
      run: builtin_struct_unpack_from,
    },
    BuiltinDef::{
      name: "_struct.iter_unpack",
      run: builtin_struct_iter_unpack,
    },
    BuiltinDef::{ name: "_struct._clearcache", run: builtin_struct_clearcache, },
    BuiltinDef::{
      name: "_struct.Struct.__init__",
      run: builtin_struct_struct_init,
    },
    BuiltinDef::{
      name: "_struct.Struct.pack",
      run: builtin_struct_struct_pack,
    },
    BuiltinDef::{
      name: "_struct.Struct.unpack",
      run: builtin_struct_struct_unpack,
    },
    BuiltinDef::{
      name: "_struct.Struct.calcsize",
      run: builtin_struct_struct_calcsize,
    },
    BuiltinDef::{ name: "gc.enable", run: builtin_gc_enable, },
    BuiltinDef::{ name: "gc.disable", run: builtin_gc_disable, },
    BuiltinDef::{ name: "gc.isenabled", run: builtin_gc_isenabled, },
    BuiltinDef::{ name: "gc.collect", run: builtin_gc_collect, },
    BuiltinDef::{ name: "gc.get_threshold", run: builtin_gc_get_threshold, },
    BuiltinDef::{ name: "gc.set_threshold", run: builtin_gc_set_threshold, },
    BuiltinDef::{ name: "gc.get_count", run: builtin_gc_get_count, },
    BuiltinDef::{ name: "binascii.crc32", run: builtin_binascii_crc32, },
    BuiltinDef::{
      name: "binascii.b2a_base64",
      run: builtin_binascii_b2a_base64,
    },
    BuiltinDef::{
      name: "binascii.a2b_base64",
      run: builtin_binascii_a2b_base64,
    },
    BuiltinDef::{ name: "binascii.hexlify", run: builtin_binascii_hexlify, },
    BuiltinDef::{ name: "binascii.unhexlify", run: builtin_binascii_unhexlify, },
    BuiltinDef::{ name: "binascii.b2a_hex", run: builtin_binascii_b2a_hex, },
    BuiltinDef::{ name: "binascii.a2b_hex", run: builtin_binascii_a2b_hex, },
    BuiltinDef::{ name: "binascii.a2b_qp", run: builtin_binascii_a2b_qp, },
    BuiltinDef::{ name: "binascii.b2a_qp", run: builtin_binascii_b2a_qp, },
    BuiltinDef::{ name: "binascii.a2b_uu", run: builtin_binascii_a2b_uu, },
    BuiltinDef::{ name: "binascii.b2a_uu", run: builtin_binascii_b2a_uu, },
    BuiltinDef::{ name: "binascii.crc_hqx", run: builtin_binascii_crc_hqx, },
    BuiltinDef::{
      name: "_string.formatter_parser",
      run: builtin_string_formatter_parser,
    },
    BuiltinDef::{
      name: "_string.formatter_field_name_split",
      run: builtin_string_formatter_field_name_split,
    },
    BuiltinDef::{
      name: "_warnings._filters_mutated",
      run: builtin_warnings_filters_mutated,
    },
    BuiltinDef::{ name: "_warnings.warn", run: builtin_warnings_warn, },
    BuiltinDef::{
      name: "_warnings.warn_explicit",
      run: builtin_warnings_warn_explicit,
    },
    BuiltinDef::{ name: "_thread.get_ident", run: builtin_thread_get_ident, },
    BuiltinDef::{
      name: "_thread.allocate_lock",
      run: builtin_thread_allocate_lock,
    },
    BuiltinDef::{
      name: "_thread.start_new_thread",
      run: builtin_thread_start_new_thread,
    },
    BuiltinDef::{
      name: "_thread._set_sentinel",
      run: builtin_thread_set_sentinel,
    },
    BuiltinDef::{ name: "_thread._count", run: builtin_thread_count, },
    BuiltinDef::{ name: "_thread.stack_size", run: builtin_thread_stack_size, },
    BuiltinDef::{
      name: "_thread.RLock.__enter__",
      run: builtin_thread_rlock_enter,
    },
    BuiltinDef::{
      name: "_thread.RLock.__exit__",
      run: builtin_thread_rlock_exit,
    },
    BuiltinDef::{
      name: "_thread.RLock.acquire",
      run: builtin_thread_rlock_acquire,
    },
    BuiltinDef::{
      name: "_thread.RLock.release",
      run: builtin_thread_rlock_release,
    },
    BuiltinDef::{
      name: "_thread.RLock.locked",
      run: builtin_thread_rlock_locked,
    },
    BuiltinDef::{
      name: "_thread.RLock._at_fork_reinit",
      run: builtin_thread_rlock_at_fork_reinit,
    },
    BuiltinDef::{ name: "_weakref.ref", run: builtin_weakref_ref, },
    BuiltinDef::{ name: "_weakref.proxy", run: builtin_weakref_proxy, },
    BuiltinDef::{
      name: "_weakref.getweakrefcount",
      run: builtin_weakref_getweakrefcount,
    },
    BuiltinDef::{
      name: "_weakref.getweakrefs",
      run: builtin_weakref_getweakrefs,
    },
    BuiltinDef::{
      name: "_weakref._remove_dead_weakref",
      run: builtin_weakref_remove_dead_weakref,
    },
    BuiltinDef::{ name: "weakref.__hash__", run: builtin_weakref_hash, },
    BuiltinDef::{ name: "code.replace", run: builtin_code_replace, },
    BuiltinDef::{ name: "coroutine.close", run: builtin_coroutine_close, },
    BuiltinDef::{ name: "itertools.chain", run: builtin_itertools_chain, },
    BuiltinDef::{
      name: "itertools.chain.from_iterable",
      run: builtin_itertools_chain_from_iterable,
    },
    BuiltinDef::{
      name: "itertools.filterfalse",
      run: builtin_itertools_filterfalse,
    },
    BuiltinDef::{
      name: "itertools.accumulate",
      run: builtin_itertools_accumulate,
    },
    BuiltinDef::{ name: "itertools.groupby", run: builtin_itertools_groupby, },
    BuiltinDef::{ name: "itertools.count", run: builtin_itertools_count, },
    BuiltinDef::{ name: "itertools.cycle", run: builtin_itertools_cycle, },
    BuiltinDef::{ name: "itertools.repeat", run: builtin_itertools_repeat, },
    BuiltinDef::{ name: "itertools.starmap", run: builtin_itertools_starmap, },
    BuiltinDef::{ name: "itertools.islice", run: builtin_itertools_islice, },
    BuiltinDef::{
      name: "itertools.permutations",
      run: builtin_itertools_permutations,
    },
    BuiltinDef::{
      name: "itertools.combinations",
      run: builtin_itertools_combinations,
    },
    BuiltinDef::{ name: "itertools.product", run: builtin_itertools_product, },
    BuiltinDef::{ name: "print", run: builtin_print, },
    BuiltinDef::{ name: "len", run: builtin_len, },
    BuiltinDef::{ name: "range", run: builtin_range, },
    BuiltinDef::{ name: "range.__iter__", run: builtin_range_iter, },
    BuiltinDef::{ name: "range.__len__", run: builtin_range_len, },
    BuiltinDef::{ name: "range.__bool__", run: builtin_range_bool, },
    BuiltinDef::{ name: "range.__contains__", run: builtin_range_contains, },
    BuiltinDef::{ name: "range.__getitem__", run: builtin_range_getitem, },
    BuiltinDef::{ name: "range.count", run: builtin_range_count, },
    BuiltinDef::{ name: "range.index", run: builtin_range_index, },
    BuiltinDef::{ name: "sum", run: builtin_sum, },
    BuiltinDef::{ name: "max", run: builtin_max, },
    BuiltinDef::{ name: "min", run: builtin_min, },
    BuiltinDef::{ name: "any", run: builtin_any, },
    BuiltinDef::{ name: "all", run: builtin_all, },
    BuiltinDef::{ name: "enumerate", run: builtin_enumerate, },
    BuiltinDef::{ name: "zip", run: builtin_zip, },
    BuiltinDef::{ name: "map", run: builtin_map, },
    BuiltinDef::{ name: "filter", run: builtin_filter, },
    BuiltinDef::{ name: "reversed", run: builtin_reversed, },
    BuiltinDef::{ name: "sorted", run: builtin_sorted, },
    BuiltinDef::{ name: "input", run: builtin_input, },
    BuiltinDef::{ name: "breakpoint", run: builtin_breakpoint, },
    BuiltinDef::{ name: "open", run: builtin_open, },
    BuiltinDef::{ name: "str", run: builtin_str, },
    BuiltinDef::{ name: "str.join", run: builtin_str_join, },
    BuiltinDef::{ name: "str.maketrans", run: builtin_str_maketrans, },
    BuiltinDef::{ name: "str.casefold", run: builtin_str_casefold, },
    BuiltinDef::{ name: "bytes", run: builtin_bytes, },
    BuiltinDef::{ name: "bytes.fromhex", run: builtin_bytes_fromhex, },
    BuiltinDef::{ name: "bytes.maketrans", run: builtin_bytes_maketrans, },
    BuiltinDef::{ name: "bytes.translate", run: builtin_bytes_translate, },
    BuiltinDef::{ name: "bytes.upper", run: builtin_bytes_upper, },
    BuiltinDef::{ name: "bytes.rstrip", run: builtin_bytes_rstrip, },
    BuiltinDef::{ name: "bytes.join", run: builtin_bytes_join, },
    BuiltinDef::{ name: "bytearray", run: builtin_bytearray, },
    BuiltinDef::{ name: "bytearray.fromhex", run: builtin_bytearray_fromhex, },
    BuiltinDef::{ name: "bytearray.copy", run: builtin_bytearray_copy, },
    BuiltinDef::{ name: "bytearray.upper", run: builtin_bytearray_upper, },
    BuiltinDef::{ name: "bytearray.rstrip", run: builtin_bytearray_rstrip, },
    BuiltinDef::{
      name: "bytearray.translate",
      run: builtin_bytearray_translate,
    },
    BuiltinDef::{
      name: "bytearray.__setitem__",
      run: builtin_bytearray_setitem,
    },
    BuiltinDef::{
      name: "bytearray.__delitem__",
      run: builtin_bytearray_delitem,
    },
    BuiltinDef::{ name: "memoryview", run: builtin_memoryview, },
    BuiltinDef::{ name: "memoryview.tobytes", run: builtin_memoryview_tobytes, },
    BuiltinDef::{ name: "memoryview.cast", run: builtin_memoryview_cast, },
    BuiltinDef::{ name: "int", run: builtin_int, },
    BuiltinDef::{ name: "int.__new__", run: builtin_int_new, },
    BuiltinDef::{ name: "int.__bool__", run: builtin_int_bool, },
    BuiltinDef::{ name: "int.__index__", run: builtin_int_index, },
    BuiltinDef::{ name: "int.__repr__", run: builtin_int_repr, },
    BuiltinDef::{ name: "int.from_bytes", run: builtin_int_from_bytes, },
    BuiltinDef::{ name: "int.to_bytes", run: builtin_int_to_bytes, },
    BuiltinDef::{ name: "int.bit_length", run: builtin_int_bit_length, },
    BuiltinDef::{ name: "int.conjugate", run: builtin_int_conjugate, },
    BuiltinDef::{ name: "float", run: builtin_float, },
    BuiltinDef::{ name: "float.__repr__", run: builtin_float_repr, },
    BuiltinDef::{ name: "float.__getformat__", run: builtin_float_getformat, },
    BuiltinDef::{ name: "float.conjugate", run: builtin_float_conjugate, },
    BuiltinDef::{
      name: "float.as_integer_ratio",
      run: builtin_float_as_integer_ratio,
    },
    BuiltinDef::{ name: "complex", run: builtin_complex, },
    BuiltinDef::{ name: "complex.conjugate", run: builtin_complex_conjugate, },
    BuiltinDef::{ name: "list", run: builtin_list, },
    BuiltinDef::{ name: "list.copy", run: builtin_list_copy, },
    BuiltinDef::{ name: "tuple", run: builtin_tuple, },
    BuiltinDef::{ name: "tuple.__new__", run: builtin_tuple_new, },
    BuiltinDef::{ name: "slice", run: builtin_slice, },
    BuiltinDef::{ name: "slice.__new__", run: builtin_slice_new, },
    BuiltinDef::{ name: "slice.indices", run: builtin_slice_indices, },
    BuiltinDef::{ name: "set", run: builtin_set, },
    BuiltinDef::{ name: "set.copy", run: builtin_set_copy, },
    BuiltinDef::{ name: "frozenset", run: builtin_frozenset, },
    BuiltinDef::{ name: "dict", run: builtin_dict, },
    BuiltinDef::{ name: "dict.copy", run: builtin_dict_copy, },
    BuiltinDef::{ name: "dict.fromkeys", run: builtin_dict_fromkeys, },
    BuiltinDef::{ name: "dict.get", run: builtin_dict_get, },
    BuiltinDef::{ name: "dict.pop", run: builtin_dict_pop, },
    BuiltinDef::{ name: "dict.popitem", run: builtin_dict_popitem, },
    BuiltinDef::{ name: "dict.setdefault", run: builtin_dict_setdefault, },
    BuiltinDef::{ name: "dict.keys", run: builtin_dict_keys, },
    BuiltinDef::{ name: "dict.values", run: builtin_dict_values, },
    BuiltinDef::{ name: "dict.items", run: builtin_dict_items, },
    BuiltinDef::{ name: "dict.update", run: builtin_dict_update, },
    BuiltinDef::{ name: "dict.clear", run: builtin_dict_clear, },
    BuiltinDef::{ name: "dict.__contains__", run: builtin_dict_contains, },
    BuiltinDef::{ name: "dict.__getitem__", run: builtin_dict_getitem, },
    BuiltinDef::{ name: "dict.__setitem__", run: builtin_dict_setitem, },
    BuiltinDef::{ name: "dict.__delitem__", run: builtin_dict_delitem, },
    BuiltinDef::{ name: "dict.__iter__", run: builtin_dict_iter, },
    BuiltinDef::{ name: "dict.__len__", run: builtin_dict_len, },
    BuiltinDef::{ name: "file.read", run: builtin_file_read, },
    BuiltinDef::{ name: "file.readline", run: builtin_file_readline, },
    BuiltinDef::{ name: "file.readlines", run: builtin_file_readlines, },
    BuiltinDef::{ name: "file.close", run: builtin_file_close, },
    BuiltinDef::{ name: "file.write", run: builtin_file_write, },
    BuiltinDef::{ name: "file.flush", run: builtin_file_flush, },
    BuiltinDef::{ name: "file.seek", run: builtin_file_seek, },
    BuiltinDef::{ name: "file.tell", run: builtin_file_tell, },
    BuiltinDef::{ name: "file.__iter__", run: builtin_file_iter, },
    BuiltinDef::{ name: "file.__next__", run: builtin_file_next, },
    BuiltinDef::{ name: "file.__enter__", run: builtin_file_enter, },
    BuiltinDef::{ name: "file.__exit__", run: builtin_file_exit, },
    BuiltinDef::{ name: "iter", run: builtin_iter, },
    BuiltinDef::{ name: "next", run: builtin_next, },
    BuiltinDef::{ name: "bool", run: builtin_bool, },
    BuiltinDef::{ name: "bool.from_bytes", run: builtin_bool_from_bytes, },
    BuiltinDef::{ name: "bool.__new__", run: builtin_bool_new, },
    BuiltinDef::{ name: "property", run: builtin_property, },
    BuiltinDef::{ name: "property.__init__", run: builtin_property_init, },
    BuiltinDef::{ name: "property.__get__", run: builtin_property_dunder_get, },
    BuiltinDef::{ name: "property.getter", run: builtin_property_getter, },
    BuiltinDef::{ name: "property.setter", run: builtin_property_setter, },
    BuiltinDef::{ name: "property.deleter", run: builtin_property_deleter, },
    BuiltinDef::{ name: "staticmethod", run: builtin_staticmethod, },
    BuiltinDef::{
      name: "staticmethod.__init__",
      run: builtin_staticmethod_init,
    },
    BuiltinDef::{ name: "classmethod", run: builtin_classmethod, },
    BuiltinDef::{ name: "classmethod.__init__", run: builtin_classmethod_init, },
    BuiltinDef::{ name: "register", run: builtin_register, },
    BuiltinDef::{
      name: "__mpython_abc_cache_token",
      run: builtin_mpython_abc_cache_token,
    },
    BuiltinDef::{
      name: "__mpython_abc_cache_token_bump",
      run: builtin_mpython_abc_cache_token_bump,
    },
    BuiltinDef::{ name: "repr", run: builtin_repr, },
    BuiltinDef::{ name: "ascii", run: builtin_ascii, },
    BuiltinDef::{ name: "abs", run: builtin_abs, },
    BuiltinDef::{ name: "round", run: builtin_round, },
    BuiltinDef::{ name: "pow", run: builtin_pow, },
    BuiltinDef::{ name: "math.sqrt", run: builtin_math_sqrt, },
    BuiltinDef::{ name: "math.copysign", run: builtin_math_copysign, },
    BuiltinDef::{ name: "math.pow", run: builtin_math_pow, },
    BuiltinDef::{ name: "math.log", run: builtin_math_log, },
    BuiltinDef::{ name: "math.log2", run: builtin_math_log2, },
    BuiltinDef::{ name: "math.exp", run: builtin_math_exp, },
    BuiltinDef::{ name: "math.floor", run: builtin_math_floor, },
    BuiltinDef::{ name: "math.ceil", run: builtin_math_ceil, },
    BuiltinDef::{ name: "math.trunc", run: builtin_math_trunc, },
    BuiltinDef::{ name: "math.modf", run: builtin_math_modf, },
    BuiltinDef::{ name: "math.frexp", run: builtin_math_frexp, },
    BuiltinDef::{ name: "math.ldexp", run: builtin_math_ldexp, },
    BuiltinDef::{ name: "math.acos", run: builtin_math_acos, },
    BuiltinDef::{ name: "math.cos", run: builtin_math_cos, },
    BuiltinDef::{ name: "math.sin", run: builtin_math_sin, },
    BuiltinDef::{ name: "math.hypot", run: builtin_math_hypot, },
    BuiltinDef::{ name: "math.fabs", run: builtin_math_fabs, },
    BuiltinDef::{ name: "math.erf", run: builtin_math_erf, },
    BuiltinDef::{ name: "math.lgamma", run: builtin_math_lgamma, },
    BuiltinDef::{ name: "math.fsum", run: builtin_math_fsum, },
    BuiltinDef::{ name: "math.sumprod", run: builtin_math_sumprod, },
    BuiltinDef::{ name: "math.isfinite", run: builtin_math_isfinite, },
    BuiltinDef::{ name: "math.isnan", run: builtin_math_isnan, },
    BuiltinDef::{ name: "math.isinf", run: builtin_math_isinf, },
    BuiltinDef::{ name: "math.isclose", run: builtin_math_isclose, },
    BuiltinDef::{ name: "math.gcd", run: builtin_math_gcd, },
    BuiltinDef::{ name: "math.isqrt", run: builtin_math_isqrt, },
    BuiltinDef::{ name: "divmod", run: builtin_divmod, },
    BuiltinDef::{ name: "chr", run: builtin_chr, },
    BuiltinDef::{ name: "ord", run: builtin_ord, },
    BuiltinDef::{ name: "bin", run: builtin_bin, },
    BuiltinDef::{ name: "oct", run: builtin_oct, },
    BuiltinDef::{ name: "hex", run: builtin_hex, },
    BuiltinDef::{ name: "callable", run: builtin_callable, },
    BuiltinDef::{ name: "isinstance", run: builtin_isinstance, },
    BuiltinDef::{ name: "issubclass", run: builtin_issubclass, },
    BuiltinDef::{ name: "type", run: builtin_type, },
    BuiltinDef::{ name: "type.__new__", run: builtin_type_new, },
    BuiltinDef::{ name: "id", run: builtin_id, },
    BuiltinDef::{ name: "hash", run: builtin_hash, },
    BuiltinDef::{ name: "globals", run: builtin_globals, },
    BuiltinDef::{
      name: "module_globals.__getitem__",
      run: builtin_module_globals_getitem,
    },
    BuiltinDef::{
      name: "module_globals.__setitem__",
      run: builtin_module_globals_setitem,
    },
    BuiltinDef::{
      name: "module_globals.__delitem__",
      run: builtin_module_globals_delitem,
    },
    BuiltinDef::{
      name: "module_globals.__iter__",
      run: builtin_module_globals_iter,
    },
    BuiltinDef::{
      name: "module_globals.__len__",
      run: builtin_module_globals_len,
    },
    BuiltinDef::{
      name: "module_globals.__contains__",
      run: builtin_module_globals_contains,
    },
    BuiltinDef::{ name: "module_globals.get", run: builtin_module_globals_get, },
    BuiltinDef::{
      name: "module_globals.keys",
      run: builtin_module_globals_keys,
    },
    BuiltinDef::{
      name: "module_globals.values",
      run: builtin_module_globals_values,
    },
    BuiltinDef::{
      name: "module_globals.items",
      run: builtin_module_globals_items,
    },
    BuiltinDef::{ name: "module_globals.pop", run: builtin_module_globals_pop, },
    BuiltinDef::{
      name: "module_globals.update",
      run: builtin_module_globals_update,
    },
    BuiltinDef::{
      name: "module_globals.copy",
      run: builtin_module_globals_copy,
    },
    BuiltinDef::{ name: "vars", run: builtin_vars, },
    BuiltinDef::{ name: "locals", run: builtin_locals, },
    BuiltinDef::{ name: "compile", run: builtin_compile, },
    BuiltinDef::{ name: "eval", run: builtin_eval, },
    BuiltinDef::{ name: "exec", run: builtin_exec, },
    BuiltinDef::{ name: "__import__", run: builtin_import, },
    BuiltinDef::{ name: "sys.intern", run: builtin_sys_intern, },
    BuiltinDef::{ name: "sys.exc_info", run: builtin_sys_exc_info, },
    BuiltinDef::{ name: "sys.exception", run: builtin_sys_exception, },
    BuiltinDef::{ name: "sys.getrefcount", run: builtin_sys_getrefcount, },
    BuiltinDef::{ name: "sys._getframe", run: builtin_sys_getframe, },
    BuiltinDef::{ name: "sys.excepthook", run: builtin_sys_excepthook, },
    BuiltinDef::{
      name: "sys.__breakpointhook__",
      run: builtin_sys_breakpointhook,
    },
    BuiltinDef::{ name: "pdb.set_trace", run: builtin_pdb_set_trace, },
    BuiltinDef::{
      name: "sys.getdefaultencoding",
      run: builtin_sys_getdefaultencoding,
    },
    BuiltinDef::{
      name: "sys.getfilesystemencoding",
      run: builtin_sys_getfilesystemencoding,
    },
    BuiltinDef::{
      name: "sys.getfilesystemencodeerrors",
      run: builtin_sys_getfilesystemencodeerrors,
    },
    BuiltinDef::{
      name: "sys.getrecursionlimit",
      run: builtin_sys_getrecursionlimit,
    },
    BuiltinDef::{
      name: "sys.setrecursionlimit",
      run: builtin_sys_setrecursionlimit,
    },
    BuiltinDef::{ name: "sys.exit", run: builtin_sys_exit, },
    BuiltinDef::{ name: "sys.audit", run: builtin_sys_audit, },
    BuiltinDef::{ name: "sys.stdin.readline", run: builtin_sys_stdin_readline, },
    BuiltinDef::{ name: "sys.stdin.isatty", run: builtin_sys_stdin_isatty, },
    BuiltinDef::{ name: "sys.stdout.write", run: builtin_sys_stdout_write, },
    BuiltinDef::{ name: "sys.stdout.flush", run: builtin_sys_stdout_flush, },
    BuiltinDef::{
      name: "sys.stdout.reconfigure",
      run: builtin_sys_stdout_reconfigure,
    },
    BuiltinDef::{ name: "sys.stdout.isatty", run: builtin_sys_stdout_isatty, },
    BuiltinDef::{ name: "sys.stderr.write", run: builtin_sys_stderr_write, },
    BuiltinDef::{ name: "sys.stderr.flush", run: builtin_sys_stderr_flush, },
    BuiltinDef::{
      name: "sys.stderr.reconfigure",
      run: builtin_sys_stderr_reconfigure,
    },
    BuiltinDef::{ name: "sys.stderr.isatty", run: builtin_sys_stderr_isatty, },
    BuiltinDef::{ name: "dir", run: builtin_dir, },
    BuiltinDef::{ name: "getattr", run: builtin_getattr, },
    BuiltinDef::{ name: "hasattr", run: builtin_hasattr, },
    BuiltinDef::{ name: "setattr", run: builtin_setattr, },
    BuiltinDef::{ name: "delattr", run: builtin_delattr, },
    BuiltinDef::{ name: "__reduce_ex__", run: builtin_reduce_ex, },
    BuiltinDef::{ name: "super", run: builtin_super, },
    BuiltinDef::{ name: "staticmethod.__get__", run: builtin_staticmethod_get, },
  ]
  builtin_defs_ready.val = true
}

///|
/// Evaluate a builtin call `name(args...)` with pre-evaluated arguments.
///
/// Returns `Ok(Some(value))` if handled as a builtin, `Ok(None)` if not a builtin.
fn eval_builtin_call(
  name : String,
  positional : Array[Value],
  keywords : Array[(String, Value)],
  locals : Array[(String, Value)],
  globals : Array[(String, Value)],
  builtins : Array[(String, Value)],
  io : MockIO,
) -> Result[Value?, RuntimeError] {
  ensure_builtin_defs_ready()
  for def in builtin_defs_ref.val {
    if def.name == name {
      let value = match
        (def.run)(positional, keywords, locals, globals, builtins, io) {
        Ok(v) => v
        Err(err) => return Err(err)
      }
      return Ok(Some(value))
    }
  }
  Ok(None)
}