///|
/// What a predefined member is to the checker.
pub(all) enum Member {
  /// A value of a type.
  Typed(Type)
  /// A name usable only in an annotation or as a decorator: `int`, `list`,
  /// `Callable`, `dataclass`.
  AnnotationOnly
  /// A class, by its qualified name in the class table: `range`.
  ClassOf(String)
} derive(Eq, Debug)

///|
/// The predefined modules of Figure 2.7 and what each member is: the
/// reference's `PREDEFINED_MEMBERS`. The table lives here, below both the checker and
/// the evaluator, because both have to agree on it: a name the checker
/// accepts and the evaluator has no value for would type-check and then fail
/// to run.
pub fn predefined_members(q : String) -> Array[(String, Member)]? {
  match q {
    "builtins" =>
      Some([
        ("print", Typed(Callable([t_object], t_none))),
        ("len", Typed(Callable([t_sized], t_int))),
        ("range", ClassOf(range_class)),
        ("round", Typed(Callable([t_float], t_int))),
        ("None", AnnotationOnly),
        ("object", AnnotationOnly),
        ("bool", AnnotationOnly),
        ("int", AnnotationOnly),
        ("float", AnnotationOnly),
        ("str", AnnotationOnly),
        ("list", AnnotationOnly),
        ("dict", AnnotationOnly),
        ("tuple", AnnotationOnly),
      ])
    "sys" =>
      Some([
        ("argv", Typed(List(t_str))),
        ("exit", Typed(Callable([t_int], t_never))),
      ])
    "typing" =>
      Some([
        ("Callable", AnnotationOnly),
        ("Literal", AnnotationOnly),
        ("Never", AnnotationOnly),
        ("Sized", AnnotationOnly),
      ])
    "dataclasses" => Some([("dataclass", AnnotationOnly)])
    _ => None
  }
}

///|
/// The modules the specification predefines.
pub let predefined_modules : Array[String] = [
  "builtins", "dataclasses", "sys", "typing",
]