use crate::error::JsError;
use crate::gc::Gc;
use crate::interpreter::Interpreter;
use crate::value::{ExoticObject, Guarded, JsObject, JsString, JsValue, PropertyKey};
pub fn init_boolean_prototype(interp: &mut Interpreter) {
let proto = interp.boolean_prototype.clone();
interp.register_method(&proto, "toString", boolean_to_string, 0);
interp.register_method(&proto, "valueOf", boolean_value_of, 0);
}
pub fn boolean_constructor_fn(
interp: &mut Interpreter,
this: JsValue,
args: &[JsValue],
) -> Result<Guarded, JsError> {
let bool_val = args
.first()
.cloned()
.unwrap_or(JsValue::Undefined)
.to_boolean();
if let JsValue::Object(obj) = &this {
let is_new_call = {
let borrowed = obj.borrow();
if let Some(ref proto) = borrowed.prototype {
core::ptr::eq(
&*proto.borrow() as *const _,
&*interp.boolean_prototype.borrow() as *const _,
)
} else {
false
}
};
if is_new_call {
obj.borrow_mut().exotic = ExoticObject::Boolean(bool_val);
return Ok(Guarded::unguarded(this));
}
}
Ok(Guarded::unguarded(JsValue::Boolean(bool_val)))
}
pub fn create_boolean_constructor(interp: &mut Interpreter) -> Gc<JsObject> {
let constructor = interp.create_native_function("Boolean", boolean_constructor_fn, 1);
let proto_key = PropertyKey::String(interp.intern("prototype"));
constructor
.borrow_mut()
.set_property(proto_key, JsValue::Object(interp.boolean_prototype.clone()));
let ctor_key = PropertyKey::String(interp.intern("constructor"));
interp
.boolean_prototype
.borrow_mut()
.set_property(ctor_key, JsValue::Object(constructor.clone()));
constructor
}
pub fn boolean_to_string(
_interp: &mut Interpreter,
this: JsValue,
_args: &[JsValue],
) -> Result<Guarded, JsError> {
let bool_val = get_boolean_value(&this)?;
let result = if bool_val { "true" } else { "false" };
Ok(Guarded::unguarded(JsValue::String(JsString::from(result))))
}
pub fn boolean_value_of(
_interp: &mut Interpreter,
this: JsValue,
_args: &[JsValue],
) -> Result<Guarded, JsError> {
let bool_val = get_boolean_value(&this)?;
Ok(Guarded::unguarded(JsValue::Boolean(bool_val)))
}
fn get_boolean_value(this: &JsValue) -> Result<bool, JsError> {
match this {
JsValue::Boolean(b) => Ok(*b),
JsValue::Object(obj) => {
let borrowed = obj.borrow();
match borrowed.exotic {
ExoticObject::Boolean(b) => Ok(b),
_ => Err(JsError::type_error(
"Boolean.prototype method called on incompatible receiver",
)),
}
}
_ => Err(JsError::type_error(
"Boolean.prototype method called on incompatible receiver",
)),
}
}