use super::*;
impl TypeChecker {
pub(super) fn register_builtins(&mut self) {
let header_map = || {
Type::Map(
Box::new(Type::Str),
Box::new(Type::List(Box::new(Type::Str))),
)
};
let net_resp_fields: &[(&str, Type)] = &[
("status", Type::Int),
("body", Type::Str),
("headers", header_map()),
];
for (field, ty) in net_resp_fields {
self.record_field_types.insert(
crate::visibility::member_key("HttpResponse", field),
ty.clone(),
);
}
let net_req_fields: &[(&str, Type)] = &[
("method", Type::Str),
("path", Type::Str),
("query", Type::Str),
("body", Type::Str),
("headers", header_map()),
];
for (field, ty) in net_req_fields {
self.record_field_types.insert(
crate::visibility::member_key("HttpRequest", field),
ty.clone(),
);
}
let effect_arg_var = || Type::Var("EffectArg".to_string());
let context_var = || Type::Var("Context".to_string());
let effect_event_fields: &[(&str, Type)] = &[
("method", Type::Str),
("args", Type::List(Box::new(effect_arg_var()))),
("path", Type::Str),
];
for (field, ty) in effect_event_fields {
self.record_field_types.insert(
crate::visibility::member_key(crate::types::effect_event::TYPE_NAME, field),
ty.clone(),
);
}
let trace_fields: &[(&str, Type)] = &[(
"events",
Type::List(Box::new(Type::Named(
crate::types::effect_event::TYPE_NAME.to_string(),
))),
)];
for (field, ty) in trace_fields {
self.record_field_types.insert(
crate::visibility::member_key(crate::types::trace::TYPE_NAME, field),
ty.clone(),
);
}
let tcp_conn_fields: &[(&str, Type)] =
&[("id", Type::Str), ("host", Type::Str), ("port", Type::Int)];
for (field, ty) in tcp_conn_fields {
self.record_field_types.insert(
crate::visibility::member_key("Tcp.Connection", field),
ty.clone(),
);
}
let net_ret = || {
Type::Result(
Box::new(Type::Named("HttpResponse".to_string())),
Box::new(Type::Str),
)
};
let disk_unit = || Type::Result(Box::new(Type::Unit), Box::new(Type::Str));
let disk_str = || Type::Result(Box::new(Type::Str), Box::new(Type::Str));
let disk_list = || {
Type::Result(
Box::new(Type::List(Box::new(Type::Str))),
Box::new(Type::Str),
)
};
let header_list = header_map;
let server_handler_effects = || {
vec![
"Args.get".to_string(),
"Console.print".to_string(),
"Console.error".to_string(),
"Console.warn".to_string(),
"Console.readLine".to_string(),
"Http.get".to_string(),
"Http.head".to_string(),
"Http.delete".to_string(),
"Http.post".to_string(),
"Http.put".to_string(),
"Http.patch".to_string(),
"Disk.readText".to_string(),
"Disk.writeText".to_string(),
"Disk.appendText".to_string(),
"Disk.exists".to_string(),
"Disk.delete".to_string(),
"Disk.deleteDir".to_string(),
"Disk.listDir".to_string(),
"Disk.makeDir".to_string(),
"Env.get".to_string(),
"Env.set".to_string(),
"Tcp.connect".to_string(),
"Tcp.send".to_string(),
"Tcp.ping".to_string(),
"Tcp.writeLine".to_string(),
"Tcp.readLine".to_string(),
"Tcp.close".to_string(),
"HttpServer.listen".to_string(),
"HttpServer.listenWith".to_string(),
"Random.int".to_string(),
"Random.float".to_string(),
"Time.now".to_string(),
"Time.unixMs".to_string(),
"Time.sleep".to_string(),
]
};
let http_handler = || {
Type::Fn(
vec![Type::Named("HttpRequest".to_string())],
Box::new(Type::Named("HttpResponse".to_string())),
server_handler_effects(),
)
};
let http_handler_with_context = || {
Type::Fn(
vec![context_var(), Type::Named("HttpRequest".to_string())],
Box::new(Type::Named("HttpResponse".to_string())),
server_handler_effects(),
)
};
let service_sigs: &[(&str, &[Type], Type, &[&str])] = &[
(
"Args.get",
&[],
Type::List(Box::new(Type::Str)),
&["Args.get"],
),
(
"Console.print",
&[Type::Str],
Type::Unit,
&["Console.print"],
),
(
"Console.error",
&[Type::Str],
Type::Unit,
&["Console.error"],
),
("Console.warn", &[Type::Str], Type::Unit, &["Console.warn"]),
(
"Console.readLine",
&[],
Type::Result(Box::new(Type::Str), Box::new(Type::Str)),
&["Console.readLine"],
),
("Http.get", &[Type::Str], net_ret(), &["Http.get"]),
("Http.head", &[Type::Str], net_ret(), &["Http.head"]),
("Http.delete", &[Type::Str], net_ret(), &["Http.delete"]),
(
"Http.post",
&[Type::Str, Type::Str, Type::Str, header_list()],
net_ret(),
&["Http.post"],
),
(
"Http.put",
&[Type::Str, Type::Str, Type::Str, header_list()],
net_ret(),
&["Http.put"],
),
(
"Http.patch",
&[Type::Str, Type::Str, Type::Str, header_list()],
net_ret(),
&["Http.patch"],
),
(
"HttpServer.listen",
&[Type::Int, http_handler()],
Type::Unit,
&["HttpServer.listen"],
),
(
"HttpServer.listenWith",
&[Type::Int, context_var(), http_handler_with_context()],
Type::Unit,
&["HttpServer.listenWith"],
),
(
"SelfHostRuntime.httpServerListen",
&[Type::Int, Type::Var("Handler".to_string())],
disk_unit(),
&["HttpServer.listen"],
),
(
"SelfHostRuntime.httpServerListenWith",
&[
Type::Int,
Type::Var("Ctx".to_string()),
Type::Var("Handler".to_string()),
],
disk_unit(),
&["HttpServer.listenWith"],
),
(
"Disk.readText",
&[Type::Str],
disk_str(),
&["Disk.readText"],
),
(
"Disk.writeText",
&[Type::Str, Type::Str],
disk_unit(),
&["Disk.writeText"],
),
(
"Disk.appendText",
&[Type::Str, Type::Str],
disk_unit(),
&["Disk.appendText"],
),
("Disk.exists", &[Type::Str], Type::Bool, &["Disk.exists"]),
("Disk.delete", &[Type::Str], disk_unit(), &["Disk.delete"]),
(
"Disk.deleteDir",
&[Type::Str],
disk_unit(),
&["Disk.deleteDir"],
),
("Disk.listDir", &[Type::Str], disk_list(), &["Disk.listDir"]),
("Disk.makeDir", &[Type::Str], disk_unit(), &["Disk.makeDir"]),
(
"Env.get",
&[Type::Str],
Type::Option(Box::new(Type::Str)),
&["Env.get"],
),
("Env.set", &[Type::Str, Type::Str], Type::Unit, &["Env.set"]),
(
"Tcp.send",
&[Type::Str, Type::Int, Type::Str],
Type::Result(Box::new(Type::Str), Box::new(Type::Str)),
&["Tcp.send"],
),
(
"Tcp.ping",
&[Type::Str, Type::Int],
Type::Result(Box::new(Type::Unit), Box::new(Type::Str)),
&["Tcp.ping"],
),
(
"Tcp.connect",
&[Type::Str, Type::Int],
Type::Result(
Box::new(Type::Named("Tcp.Connection".to_string())),
Box::new(Type::Str),
),
&["Tcp.connect"],
),
(
"Tcp.writeLine",
&[Type::Named("Tcp.Connection".to_string()), Type::Str],
Type::Result(Box::new(Type::Unit), Box::new(Type::Str)),
&["Tcp.writeLine"],
),
(
"Tcp.readLine",
&[Type::Named("Tcp.Connection".to_string())],
Type::Result(Box::new(Type::Str), Box::new(Type::Str)),
&["Tcp.readLine"],
),
(
"Tcp.close",
&[Type::Named("Tcp.Connection".to_string())],
Type::Result(Box::new(Type::Unit), Box::new(Type::Str)),
&["Tcp.close"],
),
(
"Random.int",
&[Type::Int, Type::Int],
Type::Int,
&["Random.int"],
),
("Random.float", &[], Type::Float, &["Random.float"]),
("Time.now", &[], Type::Str, &["Time.now"]),
("Time.unixMs", &[], Type::Int, &["Time.unixMs"]),
("Time.sleep", &[Type::Int], Type::Unit, &["Time.sleep"]),
];
for (name, params, ret, effects) in service_sigs {
self.insert_sig(name, params, ret.clone(), effects);
}
{
let terminal_sigs: &[(&str, &[Type], Type, &[&str])] = &[
(
"Terminal.enableRawMode",
&[],
Type::Unit,
&["Terminal.enableRawMode"],
),
(
"Terminal.disableRawMode",
&[],
Type::Unit,
&["Terminal.disableRawMode"],
),
("Terminal.clear", &[], Type::Unit, &["Terminal.clear"]),
(
"Terminal.moveTo",
&[Type::Int, Type::Int],
Type::Unit,
&["Terminal.moveTo"],
),
(
"Terminal.print",
&[Type::Str],
Type::Unit,
&["Terminal.print"],
),
(
"Terminal.setColor",
&[Type::Str],
Type::Unit,
&["Terminal.setColor"],
),
(
"Terminal.resetColor",
&[],
Type::Unit,
&["Terminal.resetColor"],
),
(
"Terminal.readKey",
&[],
Type::Option(Box::new(Type::Str)),
&["Terminal.readKey"],
),
(
"Terminal.size",
&[],
Type::Named("Terminal.Size".to_string()),
&["Terminal.size"],
),
(
"Terminal.hideCursor",
&[],
Type::Unit,
&["Terminal.hideCursor"],
),
(
"Terminal.showCursor",
&[],
Type::Unit,
&["Terminal.showCursor"],
),
("Terminal.flush", &[], Type::Unit, &["Terminal.flush"]),
];
for (name, params, ret, effects) in terminal_sigs {
self.insert_sig(name, params, ret.clone(), effects);
}
let terminal_size_fields: &[(&str, Type)] =
&[("width", Type::Int), ("height", Type::Int)];
for (field, ty) in terminal_size_fields {
self.record_field_types.insert(
crate::visibility::member_key("Terminal.Size", field),
ty.clone(),
);
}
}
let bool_sigs: &[(&str, &[Type], Type, &[&str])] = &[
("Bool.or", &[Type::Bool, Type::Bool], Type::Bool, &[]),
("Bool.and", &[Type::Bool, Type::Bool], Type::Bool, &[]),
("Bool.not", &[Type::Bool], Type::Bool, &[]),
];
for (name, params, ret, effects) in bool_sigs {
self.insert_sig(name, params, ret.clone(), effects);
}
let int_result = || Type::Result(Box::new(Type::Int), Box::new(Type::Str));
let int_sigs: &[(&str, &[Type], Type, &[&str])] = &[
("Int.fromString", &[Type::Str], int_result(), &[]),
("Int.fromFloat", &[Type::Float], Type::Int, &[]),
("Int.abs", &[Type::Int], Type::Int, &[]),
("Int.min", &[Type::Int, Type::Int], Type::Int, &[]),
("Int.max", &[Type::Int, Type::Int], Type::Int, &[]),
("Int.mod", &[Type::Int, Type::Int], int_result(), &[]),
];
for (name, params, ret, effects) in int_sigs {
self.insert_sig(name, params, ret.clone(), effects);
}
let float_result = || Type::Result(Box::new(Type::Float), Box::new(Type::Str));
let float_sigs: &[(&str, &[Type], Type, &[&str])] = &[
("Float.fromString", &[Type::Str], float_result(), &[]),
("Float.fromInt", &[Type::Int], Type::Float, &[]),
("Float.abs", &[Type::Float], Type::Float, &[]),
("Float.floor", &[Type::Float], Type::Int, &[]),
("Float.ceil", &[Type::Float], Type::Int, &[]),
("Float.round", &[Type::Float], Type::Int, &[]),
("Float.min", &[Type::Float, Type::Float], Type::Float, &[]),
("Float.max", &[Type::Float, Type::Float], Type::Float, &[]),
("Float.sin", &[Type::Float], Type::Float, &[]),
("Float.cos", &[Type::Float], Type::Float, &[]),
("Float.sqrt", &[Type::Float], Type::Float, &[]),
("Float.pow", &[Type::Float, Type::Float], Type::Float, &[]),
("Float.atan2", &[Type::Float, Type::Float], Type::Float, &[]),
("Float.pi", &[], Type::Float, &[]),
];
for (name, params, ret, effects) in float_sigs {
self.insert_sig(name, params, ret.clone(), effects);
}
let str_list = || Type::List(Box::new(Type::Str));
let string_sigs: &[(&str, &[Type], Type, &[&str])] = &[
("String.len", &[Type::Str], Type::Int, &[]),
("String.byteLength", &[Type::Str], Type::Int, &[]),
(
"String.startsWith",
&[Type::Str, Type::Str],
Type::Bool,
&[],
),
("String.endsWith", &[Type::Str, Type::Str], Type::Bool, &[]),
("String.contains", &[Type::Str, Type::Str], Type::Bool, &[]),
(
"String.slice",
&[Type::Str, Type::Int, Type::Int],
Type::Str,
&[],
),
("String.trim", &[Type::Str], Type::Str, &[]),
("String.split", &[Type::Str, Type::Str], str_list(), &[]),
(
"String.replace",
&[Type::Str, Type::Str, Type::Str],
Type::Str,
&[],
),
("String.join", &[str_list(), Type::Str], Type::Str, &[]),
(
"String.charAt",
&[Type::Str, Type::Int],
Type::Option(Box::new(Type::Str)),
&[],
),
("String.chars", &[Type::Str], str_list(), &[]),
("String.fromInt", &[Type::Int], Type::Str, &[]),
("String.fromFloat", &[Type::Float], Type::Str, &[]),
("String.fromBool", &[Type::Bool], Type::Str, &[]),
("String.toLower", &[Type::Str], Type::Str, &[]),
("String.toUpper", &[Type::Str], Type::Str, &[]),
];
for (name, params, ret, effects) in string_sigs {
self.insert_sig(name, params, ret.clone(), effects);
}
let t_var = || Type::Var("T".to_string());
let list_t = || Type::List(Box::new(t_var()));
let list_sigs: &[(&str, &[Type], Type, &[&str])] = &[
("List.len", &[list_t()], Type::Int, &[]),
("List.prepend", &[t_var(), list_t()], list_t(), &[]),
("List.take", &[list_t(), Type::Int], list_t(), &[]),
("List.drop", &[list_t(), Type::Int], list_t(), &[]),
("List.concat", &[list_t(), list_t()], list_t(), &[]),
("List.reverse", &[list_t()], list_t(), &[]),
("List.contains", &[list_t(), t_var()], Type::Bool, &[]),
(
"List.zip",
&[
Type::List(Box::new(Type::Var("A".to_string()))),
Type::List(Box::new(Type::Var("B".to_string()))),
],
Type::List(Box::new(Type::Tuple(vec![
Type::Var("A".to_string()),
Type::Var("B".to_string()),
]))),
&[],
),
];
for (name, params, ret, effects) in list_sigs {
self.insert_sig(name, params, ret.clone(), effects);
}
let k_var = || Type::Var("K".to_string());
let v_var = || Type::Var("V".to_string());
let map_kv = || Type::Map(Box::new(k_var()), Box::new(v_var()));
let map_sigs: &[(&str, &[Type], Type, &[&str])] = &[
("Map.set", &[map_kv(), k_var(), v_var()], map_kv(), &[]),
(
"Map.get",
&[map_kv(), k_var()],
Type::Option(Box::new(v_var())),
&[],
),
("Map.remove", &[map_kv(), k_var()], map_kv(), &[]),
("Map.has", &[map_kv(), k_var()], Type::Bool, &[]),
("Map.keys", &[map_kv()], Type::List(Box::new(k_var())), &[]),
(
"Map.values",
&[map_kv()],
Type::List(Box::new(v_var())),
&[],
),
(
"Map.entries",
&[map_kv()],
Type::List(Box::new(Type::Tuple(vec![k_var(), v_var()]))),
&[],
),
("Map.len", &[map_kv()], Type::Int, &[]),
(
"Map.fromList",
&[Type::List(Box::new(Type::Tuple(vec![k_var(), v_var()])))],
map_kv(),
&[],
),
];
for (name, params, ret, effects) in map_sigs {
self.insert_sig(name, params, ret.clone(), effects);
}
let vec_t = || Type::Vector(Box::new(t_var()));
let vector_sigs: &[(&str, &[Type], Type, &[&str])] = &[
("Vector.new", &[Type::Int, t_var()], vec_t(), &[]),
(
"Vector.get",
&[vec_t(), Type::Int],
Type::Option(Box::new(t_var())),
&[],
),
(
"Vector.set",
&[vec_t(), Type::Int, t_var()],
Type::Option(Box::new(vec_t())),
&[],
),
("Vector.len", &[vec_t()], Type::Int, &[]),
(
"Vector.fromList",
&[Type::List(Box::new(t_var()))],
vec_t(),
&[],
),
(
"List.fromVector",
&[vec_t()],
Type::List(Box::new(t_var())),
&[],
),
];
for (name, params, ret, effects) in vector_sigs {
self.insert_sig(name, params, ret.clone(), effects);
}
let char_sigs: &[(&str, &[Type], Type, &[&str])] = &[
("Char.toCode", &[Type::Str], Type::Int, &[]),
(
"Char.fromCode",
&[Type::Int],
Type::Option(Box::new(Type::Str)),
&[],
),
];
for (name, params, ret, effects) in char_sigs {
self.insert_sig(name, params, ret.clone(), effects);
}
let branch_path_ty = || Type::Named(crate::types::branch_path::TYPE_NAME.to_string());
self.value_members
.insert("BranchPath.Root".to_string(), branch_path_ty());
let branch_path_sigs: &[(&str, &[Type], Type, &[&str])] = &[
(
"BranchPath.child",
&[branch_path_ty(), Type::Int],
branch_path_ty(),
&[],
),
("BranchPath.parse", &[Type::Str], branch_path_ty(), &[]),
];
for (name, params, ret, effects) in branch_path_sigs {
self.insert_sig(name, params, ret.clone(), effects);
}
let byte_sigs: &[(&str, &[Type], Type, &[&str])] = &[
(
"Byte.toHex",
&[Type::Int],
Type::Result(Box::new(Type::Str), Box::new(Type::Str)),
&[],
),
(
"Byte.fromHex",
&[Type::Str],
Type::Result(Box::new(Type::Int), Box::new(Type::Str)),
&[],
),
];
for (name, params, ret, effects) in byte_sigs {
self.insert_sig(name, params, ret.clone(), effects);
}
let e_var = || Type::Var("E".to_string());
let result_te = || Type::Result(Box::new(t_var()), Box::new(e_var()));
let option_t = || Type::Option(Box::new(t_var()));
self.insert_sig("Result.Ok", &[t_var()], result_te(), &[]);
self.insert_sig("Result.Err", &[e_var()], result_te(), &[]);
self.insert_sig("Option.Some", &[t_var()], option_t(), &[]);
self.value_members
.insert("Option.None".to_string(), option_t());
self.insert_sig("Result.withDefault", &[result_te(), t_var()], t_var(), &[]);
self.insert_sig("Option.withDefault", &[option_t(), t_var()], t_var(), &[]);
self.insert_sig("Option.toResult", &[option_t(), e_var()], result_te(), &[]);
}
}