1use std::collections::HashMap;
10use std::rc::Rc;
11
12use crate::nan_value::{Arena, NanValue};
13use crate::value::{RuntimeError, Value};
14
15pub fn register(global: &mut HashMap<String, Value>) {
16 let mut members = HashMap::new();
17 for method in &["or", "and", "not"] {
18 members.insert(
19 method.to_string(),
20 Value::Builtin(format!("Bool.{}", method)),
21 );
22 }
23 global.insert(
24 "Bool".to_string(),
25 Value::Namespace {
26 name: "Bool".to_string(),
27 members,
28 },
29 );
30}
31
32pub fn effects(_name: &str) -> &'static [&'static str] {
33 &[]
34}
35
36pub fn call(name: &str, args: &[Value]) -> Option<Result<Value, RuntimeError>> {
37 match name {
38 "Bool.or" => Some(bool_or(args)),
39 "Bool.and" => Some(bool_and(args)),
40 "Bool.not" => Some(bool_not(args)),
41 _ => None,
42 }
43}
44
45fn bool_or(args: &[Value]) -> Result<Value, RuntimeError> {
46 let [a, b] = args else {
47 return Err(RuntimeError::Error(format!(
48 "Bool.or() takes 2 arguments, got {}",
49 args.len()
50 )));
51 };
52 let Value::Bool(a) = a else {
53 return Err(RuntimeError::Error(
54 "Bool.or: first argument must be a Bool".to_string(),
55 ));
56 };
57 let Value::Bool(b) = b else {
58 return Err(RuntimeError::Error(
59 "Bool.or: second argument must be a Bool".to_string(),
60 ));
61 };
62 Ok(Value::Bool(*a || *b))
63}
64
65fn bool_and(args: &[Value]) -> Result<Value, RuntimeError> {
66 let [a, b] = args else {
67 return Err(RuntimeError::Error(format!(
68 "Bool.and() takes 2 arguments, got {}",
69 args.len()
70 )));
71 };
72 let Value::Bool(a) = a else {
73 return Err(RuntimeError::Error(
74 "Bool.and: first argument must be a Bool".to_string(),
75 ));
76 };
77 let Value::Bool(b) = b else {
78 return Err(RuntimeError::Error(
79 "Bool.and: second argument must be a Bool".to_string(),
80 ));
81 };
82 Ok(Value::Bool(*a && *b))
83}
84
85fn bool_not(args: &[Value]) -> Result<Value, RuntimeError> {
86 let [a] = args else {
87 return Err(RuntimeError::Error(format!(
88 "Bool.not() takes 1 argument, got {}",
89 args.len()
90 )));
91 };
92 let Value::Bool(a) = a else {
93 return Err(RuntimeError::Error(
94 "Bool.not: argument must be a Bool".to_string(),
95 ));
96 };
97 Ok(Value::Bool(!*a))
98}
99
100pub fn register_nv(global: &mut HashMap<String, NanValue>, arena: &mut Arena) {
103 let methods = &["or", "and", "not"];
104 let mut members: Vec<(Rc<str>, NanValue)> = Vec::with_capacity(methods.len());
105 for method in methods {
106 let idx = arena.push_builtin(&format!("Bool.{}", method));
107 members.push((Rc::from(*method), NanValue::new_builtin(idx)));
108 }
109 let ns_idx = arena.push(crate::nan_value::ArenaEntry::Namespace {
110 name: Rc::from("Bool"),
111 members,
112 });
113 global.insert("Bool".to_string(), NanValue::new_namespace(ns_idx));
114}
115
116pub fn call_nv(
117 name: &str,
118 args: &[NanValue],
119 _arena: &mut Arena,
120) -> Option<Result<NanValue, RuntimeError>> {
121 match name {
122 "Bool.or" => Some(bool_or_nv(args)),
123 "Bool.and" => Some(bool_and_nv(args)),
124 "Bool.not" => Some(bool_not_nv(args)),
125 _ => None,
126 }
127}
128
129fn bool_or_nv(args: &[NanValue]) -> Result<NanValue, RuntimeError> {
130 if args.len() != 2 {
131 return Err(RuntimeError::Error(format!(
132 "Bool.or() takes 2 arguments, got {}",
133 args.len()
134 )));
135 }
136 if !args[0].is_bool() {
137 return Err(RuntimeError::Error(
138 "Bool.or: first argument must be a Bool".to_string(),
139 ));
140 }
141 if !args[1].is_bool() {
142 return Err(RuntimeError::Error(
143 "Bool.or: second argument must be a Bool".to_string(),
144 ));
145 }
146 Ok(NanValue::new_bool(args[0].as_bool() || args[1].as_bool()))
147}
148
149fn bool_and_nv(args: &[NanValue]) -> Result<NanValue, RuntimeError> {
150 if args.len() != 2 {
151 return Err(RuntimeError::Error(format!(
152 "Bool.and() takes 2 arguments, got {}",
153 args.len()
154 )));
155 }
156 if !args[0].is_bool() {
157 return Err(RuntimeError::Error(
158 "Bool.and: first argument must be a Bool".to_string(),
159 ));
160 }
161 if !args[1].is_bool() {
162 return Err(RuntimeError::Error(
163 "Bool.and: second argument must be a Bool".to_string(),
164 ));
165 }
166 Ok(NanValue::new_bool(args[0].as_bool() && args[1].as_bool()))
167}
168
169fn bool_not_nv(args: &[NanValue]) -> Result<NanValue, RuntimeError> {
170 if args.len() != 1 {
171 return Err(RuntimeError::Error(format!(
172 "Bool.not() takes 1 argument, got {}",
173 args.len()
174 )));
175 }
176 if !args[0].is_bool() {
177 return Err(RuntimeError::Error(
178 "Bool.not: argument must be a Bool".to_string(),
179 ));
180 }
181 Ok(NanValue::new_bool(!args[0].as_bool()))
182}