// Table of predefined types.
///|
fn predef_def(name : String, mk : (Loc, TypeExpr) -> TypeExpr) -> TypeDef {
let loc = dummy_loc
let d : TypeDef = {
loc,
name: TypeName::simple(name),
param: ["a"],
annot: [],
value: mk(loc, Tvar(loc, "a")),
orig: None,
}
{ ..d, orig: Some(d), }
}
///|
/// The list of predefined types: name, arity, and definition if any.
pub let predef_list : Array[(TypeName, Int, TypeDef?)] = [
(TypeName::simple("unit"), 0, None),
(TypeName::simple("bool"), 0, None),
(TypeName::simple("int"), 0, None),
(TypeName::simple("float"), 0, None),
(TypeName::simple("string"), 0, None),
(TypeName::simple("abstract"), 0, None),
(
TypeName::simple("list"),
1,
Some(predef_def("list", (l, a) => List(l, a, []))),
),
(
TypeName::simple("option"),
1,
Some(predef_def("option", (l, a) => Option(l, a, []))),
),
(
TypeName::simple("nullable"),
1,
Some(predef_def("nullable", (l, a) => Nullable(l, a, []))),
),
(
TypeName::simple("shared"),
1,
Some(predef_def("shared", (l, a) => Shared(l, a, []))),
),
(
TypeName::simple("wrap"),
1,
Some(predef_def("wrap", (l, a) => Wrap(l, a, []))),
),
]
///|
/// A table mapping type names to their arity and definition.
pub type PredefTable = Map[TypeName, (Int, TypeDef?)]
///|
/// Build the table of predefined and user-defined types, checking for
/// duplicate definitions.
pub fn make_predef_table(
user_defs : ArrayView[TypeDef],
) -> PredefTable raise AtdError {
let predef : PredefTable = Map([])
for x in predef_list {
let (k, n, opt_t) = x
predef[k] = (n, opt_t)
}
let tbl : PredefTable = Map([])
for k, v in predef {
tbl[k] = v
}
for x in user_defs {
let name = x.name
if tbl.contains(name) {
if predef.contains(name) {
error_at(x.loc, "\{name} is a predefined type, it cannot be redefined.")
} else {
error_at(x.loc, "Type \{name} is defined for the second time.")
}
}
tbl[name] = (x.param.length(), Some(x))
}
tbl
}
///|
/// Follow aliases of the form `type t = u` down to the original definition.
pub fn get_original_definition(
tbl : PredefTable,
name : TypeName,
) -> (Int, TypeDef?)? {
match tbl.get(name) {
None => None
Some((_, opt_def)) as res =>
match opt_def {
None => res
Some(def) =>
match def.value {
Name(_, inst, _) =>
match get_original_definition(tbl, inst.name) {
None => res
Some(_) as res => res
}
_ => res
}
}
}
}
///|
/// Return the type construct that a type name stands for, if known.
pub fn get_construct(tbl : PredefTable, name : TypeName) -> (Int, TypeExpr)? {
match get_original_definition(tbl, name) {
None | Some((_, None)) => None
Some((n, Some(def))) => Some((n, def.value))
}
}
///|
/// Return the type construct of a type expression, looking up
/// parameterless type names.
pub fn get_construct_of_expr(tbl : PredefTable, x : TypeExpr) -> TypeExpr? {
match x {
Name(_, { name, args: [], .. }, _) =>
match get_original_definition(tbl, name) {
None => None
Some((_, None)) => Some(x)
Some((_, Some(def))) => Some(def.value)
}
construct => Some(construct)
}
}