extern crate lambda_calculus as lambda;
use lambda::term::Context;
use lambda::*;
fn name_of(ordinal: usize) -> String {
Var(ordinal + 1).to_string()
}
#[test]
fn generated_names_are_bijective_base26() {
for (ordinal, expected) in [
(0, "a"),
(1, "b"),
(25, "z"),
(26, "aa"),
(27, "ab"),
(51, "az"),
(52, "ba"),
(701, "zz"),
(702, "aaa"),
] {
assert_eq!(name_of(ordinal), expected, "ordinal {ordinal}");
}
}
#[test]
fn names_are_generated_on_demand() {
assert_eq!(Var(usize::MAX).to_string(), "gkgwbylwrxtlpo");
assert_eq!(Var(4_000_001).to_string(), name_of(4_000_000));
assert_eq!(Var(1_000_001).to_string().len(), 5);
}
#[test]
fn indices_past_u32_stay_distinct() {
let boundary = 1usize << 32;
let at = Var(boundary).to_string();
let past = Var(boundary + 3).to_string();
let small = Var(3).to_string();
let small_past = Var(4).to_string();
assert_ne!(at, small);
assert_ne!(past, small);
assert_ne!(past, small_past);
assert_ne!(at, past);
assert_eq!(
Var(u32::MAX as usize).to_string(),
name_of(u32::MAX as usize - 1)
);
assert_eq!(Var(boundary).to_string(), name_of(boundary - 1));
assert_eq!(Var(boundary + 1).to_string(), name_of(boundary));
}
#[test]
fn context_reports_unresolved_indices_faithfully() {
let ctx = Context::new(&["x", "y", "z"]);
assert_eq!(Var(3).with_context(&ctx).to_string(), "z");
assert_eq!(
Var(1usize << 32).with_context(&ctx).to_string(),
"<unknown4294967296>"
);
assert_eq!(
Var(usize::MAX).with_context(&ctx).to_string(),
"<unknown18446744073709551615>"
);
}
#[test]
fn binder_and_free_names_do_not_collide() {
use lambda::term::LAMBDA;
let term = abs(abs(app(app(Var(1), Var(2)), app(Var(3), Var(4)))));
assert_eq!(term.to_string(), format!("{LAMBDA}a.{LAMBDA}b.b a (c d)"));
}