use crate::exec::Interpreter;
use crate::js::function::NativeFunctionData;
use crate::js::object::{ObjectKind, INSTANCE_PROTOTYPE};
use crate::js::value::{from_value, to_value, ResultValue, Value, ValueData};
use chrono::Local;
use gc::Gc;
use std::fmt::Write;
use std::iter::FromIterator;
fn log_string_from(x: Value) -> String {
match *x {
ValueData::Object(ref v) => {
let mut s = String::new();
match v.borrow().kind {
ObjectKind::String => {
let str_val: String = from_value(
v.borrow()
.internal_slots
.get("PrimitiveValue")
.unwrap()
.clone(),
)
.unwrap();
write!(s, "{}", str_val).unwrap();
}
ObjectKind::Array => {
write!(s, "[").unwrap();
let len: i32 =
from_value(v.borrow().properties.get("length").unwrap().value.clone())
.unwrap();
for i in 0..len {
let arr_str = log_string_from(
v.borrow()
.properties
.get(&i.to_string())
.unwrap()
.value
.clone(),
);
write!(s, "{}", arr_str).unwrap();
if i != len - 1 {
write!(s, ", ").unwrap();
}
}
write!(s, "]").unwrap();
}
_ => {
write!(s, "{{").unwrap();
if let Some((last_key, _)) = v.borrow().properties.iter().last() {
for (key, val) in v.borrow().properties.iter() {
if key == INSTANCE_PROTOTYPE {
continue;
}
write!(s, "{}: {}", key, log_string_from(val.value.clone())).unwrap();
if key != last_key {
write!(s, ", ").unwrap();
}
}
}
write!(s, "}}").unwrap();
}
}
s
}
_ => from_value::<String>(x.clone()).unwrap(),
}
}
pub fn log(_: &Value, args: &[Value], _: &Interpreter) -> ResultValue {
let args: Vec<String> =
FromIterator::from_iter(args.iter().map(|x| log_string_from(x.clone())));
println!(
"{}: {}",
Local::now().format("%X").to_string(),
args.join(" ")
);
Ok(Gc::new(ValueData::Undefined))
}
pub fn error(_: &Value, args: &[Value], _: &Interpreter) -> ResultValue {
let args: Vec<String> = FromIterator::from_iter(
args.iter()
.map(|x| from_value::<String>(x.clone()).unwrap()),
);
println!(
"{}: {}",
Local::now().format("%X").to_string(),
args.join(" ")
);
Ok(Gc::new(ValueData::Undefined))
}
pub fn _create(global: &Value) -> Value {
let console = ValueData::new_obj(Some(global));
console.set_field_slice("log", to_value(log as NativeFunctionData));
console.set_field_slice("error", to_value(error as NativeFunctionData));
console.set_field_slice("exception", to_value(error as NativeFunctionData));
console
}
pub fn init(global: &Value) {
global.set_field_slice("console", _create(global));
}