use crate::executor::Environment;
use crate::value::Value;
fn convert_json5_to_json(input: &str) -> String {
let mut result = String::with_capacity(input.len() + 32);
let chars: Vec<char> = input.chars().collect();
let len = chars.len();
let mut i = 0;
while i < len {
let c = chars[i];
match c {
'"' | '\'' => {
let quote = c;
result.push('"');
i += 1;
while i < len && chars[i] != quote {
if chars[i] == '\\' && i + 1 < len {
result.push(chars[i]);
result.push(chars[i + 1]);
i += 2;
} else {
if chars[i] == '"' && quote == '\'' {
result.push('\\');
}
result.push(chars[i]);
i += 1;
}
}
result.push('"');
if i < len {
i += 1; }
}
_ if c.is_alphabetic() || c == '_' || c == '$' => {
let start = i;
while i < len && (chars[i].is_alphanumeric() || chars[i] == '_' || chars[i] == '$') {
i += 1;
}
let word: String = chars[start..i].iter().collect();
let mut j = i;
while j < len && chars[j].is_whitespace() {
j += 1;
}
if j < len && chars[j] == ':' {
result.push('"');
result.push_str(&word);
result.push('"');
} else {
result.push_str(&word);
}
}
_ => {
result.push(c);
i += 1;
}
}
}
result
}
pub fn register(env: &mut Environment) {
env.register_builtin("obj", |args, _| {
if let Some(Value::String(s)) = args.first() {
match serde_json::from_str::<serde_json::Value>(s) {
Ok(v) => Ok(Value::from(v)),
Err(_) => {
let converted = convert_json5_to_json(s);
match serde_json::from_str::<serde_json::Value>(&converted) {
Ok(v) => Ok(Value::from(v)),
Err(e) => Err(format!("obj: Failed to parse: {}", e)),
}
}
}
} else {
Ok(Value::Object(indexmap::IndexMap::new()))
}
});
env.register_builtin("array", |args, _| {
Ok(Value::Array(args.to_vec()))
});
env.register_builtin("range", |args, _| {
let start = args.first().and_then(|v| v.as_number()).unwrap_or(0.0) as i64;
let end = args.get(1).and_then(|v| v.as_number()).unwrap_or(0.0) as i64;
let step = args.get(2).and_then(|v| v.as_number()).unwrap_or(1.0) as i64;
let mut arr = Vec::new();
if step > 0 {
let mut i = start;
while i <= end {
arr.push(Value::Number(i as f64));
i += step;
}
} else if step < 0 {
let mut i = start;
while i >= end {
arr.push(Value::Number(i as f64));
i += step;
}
}
Ok(Value::Array(arr))
});
env.register_builtin("set", |args, _| {
args.first().cloned().ok_or_else(|| "set: missing value".to_string())
});
env.register_builtin("get", |args, _| {
match (args.first(), args.get(1)) {
(Some(val), Some(Value::String(key))) => {
let mut current = val.clone();
for part in key.split('.') {
current = match ¤t {
Value::Object(obj) => obj.get(part).cloned().unwrap_or(Value::Null),
Value::Array(arr) => {
if let Ok(idx) = part.parse::<usize>() {
arr.get(idx).cloned().unwrap_or(Value::Null)
} else {
Value::Null
}
}
_ => Value::Null,
};
}
Ok(current)
}
(Some(Value::Array(arr)), Some(Value::Number(idx))) => {
let i = *idx as usize;
Ok(arr.get(i).cloned().unwrap_or(Value::Null))
}
_ => Ok(Value::Null),
}
});
env.register_builtin("getType", |args, _| {
Ok(Value::String(
args.first().map_or("null", |v| v.type_of()).to_string(),
))
});
env.register_builtin("repeat", |args, _| {
let count = args.first().and_then(|v| v.as_number()).unwrap_or(0.0) as usize;
let value = args.get(1).cloned().unwrap_or(Value::Null);
Ok(Value::Array(vec![value; count]))
});
}