use crate::evaluator::RuntimeError;
use crate::value::Value;
use num_traits::ToPrimitive;
use std::collections::HashMap;
pub fn json_parse(args: &[Value]) -> Result<Value, RuntimeError> {
if args.len() != 1 {
return Err(RuntimeError::WrongArity {
expected: 1,
got: args.len(),
});
}
let json_str = match &args[0] {
Value::String(s) => s,
other => {
return Err(RuntimeError::TypeErrorDetailed {
expected: "String".to_string(),
got: format!("{:?}", other),
});
}
};
let json_value: serde_json::Value = serde_json::from_str(json_str)
.map_err(|e| RuntimeError::CustomError(format!("JSON parse error: {}", e)))?;
json_to_value(&json_value)
}
pub fn json_stringify(args: &[Value]) -> Result<Value, RuntimeError> {
if args.is_empty() || args.len() > 2 {
return Err(RuntimeError::WrongArity {
expected: 1,
got: args.len(),
});
}
let value = &args[0];
let indent = if args.len() == 2 {
match &args[1] {
Value::Number(n) => *n as usize,
other => {
return Err(RuntimeError::TypeErrorDetailed {
expected: "Number".to_string(),
got: format!("{:?}", other),
});
}
}
} else {
0
};
let json_value = value_to_json(value)?;
let json_str = if indent > 0 {
serde_json::to_string_pretty(&json_value)
} else {
serde_json::to_string(&json_value)
}
.map_err(|e| RuntimeError::CustomError(format!("JSON stringify error: {}", e)))?;
Ok(Value::String(json_str))
}
fn json_to_value(json: &serde_json::Value) -> Result<Value, RuntimeError> {
match json {
serde_json::Value::Null => Ok(Value::Null),
serde_json::Value::Bool(b) => Ok(Value::Boolean(*b)),
serde_json::Value::Number(n) => {
if let Some(i) = n.as_i64() {
Ok(Value::Number(i as f64))
} else if let Some(u) = n.as_u64() {
Ok(Value::Number(u as f64))
} else if let Some(f) = n.as_f64() {
Ok(Value::Number(f))
} else {
Err(RuntimeError::CustomError("Invalid JSON number".to_string()))
}
}
serde_json::Value::String(s) => Ok(Value::String(s.clone())),
serde_json::Value::Array(arr) => {
let mut aether_arr = Vec::new();
for item in arr {
aether_arr.push(json_to_value(item)?);
}
Ok(Value::Array(aether_arr))
}
serde_json::Value::Object(obj) => {
let mut aether_dict = HashMap::new();
for (key, val) in obj {
aether_dict.insert(key.clone(), json_to_value(val)?);
}
Ok(Value::Dict(aether_dict))
}
}
}
fn value_to_json(value: &Value) -> Result<serde_json::Value, RuntimeError> {
match value {
Value::Null => Ok(serde_json::Value::Null),
Value::Boolean(b) => Ok(serde_json::Value::Bool(*b)),
Value::Number(n) => Ok(serde_json::json!(n)),
Value::String(s) => Ok(serde_json::Value::String(s.clone())),
Value::Array(arr) => {
let mut json_arr = Vec::new();
for item in arr {
json_arr.push(value_to_json(item)?);
}
Ok(serde_json::Value::Array(json_arr))
}
Value::Dict(dict) => {
let mut json_obj = serde_json::Map::new();
for (key, val) in dict {
json_obj.insert(key.clone(), value_to_json(val)?);
}
Ok(serde_json::Value::Object(json_obj))
}
Value::Fraction(f) => {
let float_val = f.numer().to_f64().unwrap_or(0.0) / f.denom().to_f64().unwrap_or(1.0);
Ok(serde_json::json!(float_val))
}
other => Err(RuntimeError::CustomError(format!(
"Cannot convert {:?} to JSON",
other
))),
}
}