bock_core/primitives/
bool.rs1use bock_interp::{BockString, BuiltinRegistry, RuntimeError, TypeTag, Value};
4
5pub fn register(registry: &mut BuiltinRegistry) {
7 registry.register(TypeTag::Bool, "compare", bool_compare);
9
10 registry.register(TypeTag::Bool, "equals", bool_equals);
12
13 registry.register(TypeTag::Bool, "hash_code", bool_hash_code);
15
16 registry.register(TypeTag::Bool, "display", bool_display);
18
19 registry.register(TypeTag::Bool, "negate", bool_negate);
21 registry.register(TypeTag::Bool, "to_int", bool_to_int);
22}
23
24fn expect_bool(args: &[Value], pos: usize, method: &str) -> Result<bool, RuntimeError> {
27 match args.get(pos) {
28 Some(Value::Bool(v)) => Ok(*v),
29 Some(other) => Err(RuntimeError::TypeError(format!(
30 "Bool.{method} expects Bool, got {other}"
31 ))),
32 None => Err(RuntimeError::ArityMismatch {
33 expected: pos + 1,
34 got: args.len(),
35 }),
36 }
37}
38
39fn bool_compare(args: &[Value]) -> Result<Value, RuntimeError> {
42 let a = expect_bool(args, 0, "compare")?;
43 let b = expect_bool(args, 1, "compare")?;
44 Ok(Value::Int(a.cmp(&b) as i64))
45}
46
47fn bool_equals(args: &[Value]) -> Result<Value, RuntimeError> {
50 let a = expect_bool(args, 0, "equals")?;
51 let b = expect_bool(args, 1, "equals")?;
52 Ok(Value::Bool(a == b))
53}
54
55fn bool_hash_code(args: &[Value]) -> Result<Value, RuntimeError> {
58 use std::hash::{Hash, Hasher};
59 let a = expect_bool(args, 0, "hash_code")?;
60 let mut hasher = std::collections::hash_map::DefaultHasher::new();
61 a.hash(&mut hasher);
62 Ok(Value::Int(hasher.finish() as i64))
63}
64
65fn bool_display(args: &[Value]) -> Result<Value, RuntimeError> {
68 let a = expect_bool(args, 0, "display")?;
69 Ok(Value::String(BockString::new(if a {
70 "true"
71 } else {
72 "false"
73 })))
74}
75
76fn bool_negate(args: &[Value]) -> Result<Value, RuntimeError> {
79 let a = expect_bool(args, 0, "negate")?;
80 Ok(Value::Bool(!a))
81}
82
83fn bool_to_int(args: &[Value]) -> Result<Value, RuntimeError> {
84 let a = expect_bool(args, 0, "to_int")?;
85 Ok(Value::Int(if a { 1 } else { 0 }))
86}
87
88#[cfg(test)]
91mod tests {
92 use super::*;
93
94 fn reg() -> BuiltinRegistry {
95 let mut r = BuiltinRegistry::new();
96 register(&mut r);
97 r
98 }
99
100 #[test]
101 fn compare_false_less_than_true() {
102 let r = reg();
103 let result = r.call(
104 TypeTag::Bool,
105 "compare",
106 &[Value::Bool(false), Value::Bool(true)],
107 );
108 assert_eq!(result.unwrap().unwrap(), Value::Int(-1));
109 }
110
111 #[test]
112 fn equals_true() {
113 let r = reg();
114 let result = r.call(
115 TypeTag::Bool,
116 "equals",
117 &[Value::Bool(true), Value::Bool(true)],
118 );
119 assert_eq!(result.unwrap().unwrap(), Value::Bool(true));
120 }
121
122 #[test]
123 fn equals_false() {
124 let r = reg();
125 let result = r.call(
126 TypeTag::Bool,
127 "equals",
128 &[Value::Bool(true), Value::Bool(false)],
129 );
130 assert_eq!(result.unwrap().unwrap(), Value::Bool(false));
131 }
132
133 #[test]
134 fn display_true() {
135 let r = reg();
136 let result = r.call(TypeTag::Bool, "display", &[Value::Bool(true)]);
137 assert_eq!(
138 result.unwrap().unwrap(),
139 Value::String(BockString::new("true"))
140 );
141 }
142
143 #[test]
144 fn display_false() {
145 let r = reg();
146 let result = r.call(TypeTag::Bool, "display", &[Value::Bool(false)]);
147 assert_eq!(
148 result.unwrap().unwrap(),
149 Value::String(BockString::new("false"))
150 );
151 }
152
153 #[test]
154 fn negate_ok() {
155 let r = reg();
156 let result = r.call(TypeTag::Bool, "negate", &[Value::Bool(true)]);
157 assert_eq!(result.unwrap().unwrap(), Value::Bool(false));
158 }
159
160 #[test]
161 fn to_int_ok() {
162 let r = reg();
163 let true_result = r.call(TypeTag::Bool, "to_int", &[Value::Bool(true)]);
164 assert_eq!(true_result.unwrap().unwrap(), Value::Int(1));
165 let false_result = r.call(TypeTag::Bool, "to_int", &[Value::Bool(false)]);
166 assert_eq!(false_result.unwrap().unwrap(), Value::Int(0));
167 }
168
169 #[test]
170 fn hash_code_deterministic() {
171 let r = reg();
172 let h1 = r
173 .call(TypeTag::Bool, "hash_code", &[Value::Bool(true)])
174 .unwrap()
175 .unwrap();
176 let h2 = r
177 .call(TypeTag::Bool, "hash_code", &[Value::Bool(true)])
178 .unwrap()
179 .unwrap();
180 assert_eq!(h1, h2);
181 }
182}