//! Map operations: get, set, remove, contains_key, keys, values, entries, merge. use el_types::{Type, TypeEnv}; use super::fn_type; pub fn register(env: &mut TypeEnv) { let map_unk = Type::Map { key: Box::new(Type::Unknown), value: Box::new(Type::Unknown) }; let arr_unk = Type::Array(Box::new(Type::Unknown)); env.register_fn("map_get", fn_type(vec![map_unk.clone(), Type::Unknown], Type::Optional(Box::new(Type::Unknown)))); env.register_fn("map_set", fn_type(vec![map_unk.clone(), Type::Unknown, Type::Unknown], map_unk.clone())); env.register_fn("map_remove", fn_type(vec![map_unk.clone(), Type::Unknown], map_unk.clone())); env.register_fn("map_contains_key", fn_type(vec![map_unk.clone(), Type::Unknown], Type::Bool)); env.register_fn("map_keys", fn_type(vec![map_unk.clone()], arr_unk.clone())); env.register_fn("map_values", fn_type(vec![map_unk.clone()], arr_unk.clone())); env.register_fn("map_entries", fn_type(vec![map_unk.clone()], arr_unk.clone())); env.register_fn("map_merge", fn_type(vec![map_unk.clone(), map_unk.clone()], map_unk.clone())); env.register_fn("map_size", fn_type(vec![map_unk.clone()], Type::Int)); env.register_fn("map_is_empty", fn_type(vec![map_unk.clone()], Type::Bool)); env.register_fn("map_new", fn_type(vec![], map_unk)); } #[cfg(test)] mod tests { use super::*; fn env() -> TypeEnv { let mut e = TypeEnv::with_builtins(); register(&mut e); e } #[test] fn test_map_get_registered() { assert!(env().lookup_fn("map_get").is_some()); } #[test] fn test_map_get_returns_optional() { let e = env(); let ty = e.lookup_fn("map_get").unwrap(); assert!(matches!(ty, Type::Fn { return_type, .. } if matches!(return_type.as_ref(), Type::Optional(_)))); } #[test] fn test_map_contains_key_returns_bool() { let e = env(); let ty = e.lookup_fn("map_contains_key").unwrap(); assert!(matches!(ty, Type::Fn { return_type, .. } if matches!(return_type.as_ref(), Type::Bool))); } #[test] fn test_map_merge_registered() { assert!(env().lookup_fn("map_merge").is_some()); } }