use crate::evaluator::RuntimeError;
use crate::sandbox::get_filesystem_validator;
use crate::value::Value;
use std::fs;
use std::path::Path;
fn get_string(val: &Value) -> Result<String, RuntimeError> {
match val {
Value::String(s) => Ok(s.clone()),
_ => Err(RuntimeError::TypeErrorDetailed {
expected: "String".to_string(),
got: format!("{:?}", val),
}),
}
}
fn validate_path(path_str: &str) -> Result<std::path::PathBuf, RuntimeError> {
if let Some(validator) = get_filesystem_validator() {
let path = Path::new(path_str);
validator
.validate_and_normalize(path)
.map_err(|e| RuntimeError::CustomError(format!("Path validation failed: {}", e)))
} else {
Ok(std::path::PathBuf::from(path_str))
}
}
pub fn read_file(args: &[Value]) -> Result<Value, RuntimeError> {
if args.is_empty() {
return Err(RuntimeError::WrongArity {
expected: 1,
got: 0,
});
}
let path_str = get_string(&args[0])?;
let validated_path = validate_path(&path_str)?;
match fs::read_to_string(&validated_path) {
Ok(content) => Ok(Value::String(content)),
Err(e) => Err(RuntimeError::CustomError(format!(
"Failed to read file '{}': {}",
validated_path.display(),
e
))),
}
}
pub fn write_file(args: &[Value]) -> Result<Value, RuntimeError> {
if args.len() < 2 {
return Err(RuntimeError::WrongArity {
expected: 2,
got: args.len(),
});
}
let path_str = get_string(&args[0])?;
let content = get_string(&args[1])?;
let validated_path = validate_path(&path_str)?;
match fs::write(&validated_path, content) {
Ok(_) => Ok(Value::Boolean(true)),
Err(e) => Err(RuntimeError::CustomError(format!(
"Failed to write file '{}': {}",
validated_path.display(),
e
))),
}
}
pub fn append_file(args: &[Value]) -> Result<Value, RuntimeError> {
if args.len() < 2 {
return Err(RuntimeError::WrongArity {
expected: 2,
got: args.len(),
});
}
let path_str = get_string(&args[0])?;
let content = get_string(&args[1])?;
let validated_path = validate_path(&path_str)?;
match fs::OpenOptions::new()
.create(true)
.append(true)
.open(&validated_path)
{
Ok(mut file) => {
use std::io::Write;
match file.write_all(content.as_bytes()) {
Ok(_) => Ok(Value::Boolean(true)),
Err(e) => Err(RuntimeError::CustomError(format!(
"Failed to append to file '{}': {}",
validated_path.display(),
e
))),
}
}
Err(e) => Err(RuntimeError::CustomError(format!(
"Failed to open file '{}': {}",
validated_path.display(),
e
))),
}
}
pub fn delete_file(args: &[Value]) -> Result<Value, RuntimeError> {
if args.is_empty() {
return Err(RuntimeError::WrongArity {
expected: 1,
got: 0,
});
}
let path_str = get_string(&args[0])?;
let validated_path = validate_path(&path_str)?;
match fs::remove_file(&validated_path) {
Ok(_) => Ok(Value::Boolean(true)),
Err(e) => Err(RuntimeError::CustomError(format!(
"Failed to delete file '{}': {}",
validated_path.display(),
e
))),
}
}
pub fn file_exists(args: &[Value]) -> Result<Value, RuntimeError> {
if args.is_empty() {
return Err(RuntimeError::WrongArity {
expected: 1,
got: 0,
});
}
let path = get_string(&args[0])?;
Ok(Value::Boolean(Path::new(&path).exists()))
}
pub fn list_dir(args: &[Value]) -> Result<Value, RuntimeError> {
if args.is_empty() {
return Err(RuntimeError::WrongArity {
expected: 1,
got: 0,
});
}
let path_str = get_string(&args[0])?;
let validated_path = validate_path(&path_str)?;
match fs::read_dir(&validated_path) {
Ok(entries) => {
let mut items = Vec::new();
for entry in entries {
match entry {
Ok(e) => {
if let Some(name) = e.file_name().to_str() {
items.push(Value::String(name.to_string()));
}
}
Err(e) => {
return Err(RuntimeError::CustomError(format!(
"Failed to read directory entry: {}",
e
)));
}
}
}
Ok(Value::Array(items))
}
Err(e) => Err(RuntimeError::CustomError(format!(
"Failed to list directory '{}': {}",
validated_path.display(),
e
))),
}
}
pub fn create_dir(args: &[Value]) -> Result<Value, RuntimeError> {
if args.is_empty() {
return Err(RuntimeError::WrongArity {
expected: 1,
got: 0,
});
}
let path_str = get_string(&args[0])?;
let validated_path = validate_path(&path_str)?;
match fs::create_dir_all(&validated_path) {
Ok(_) => Ok(Value::Boolean(true)),
Err(e) => Err(RuntimeError::CustomError(format!(
"Failed to create directory '{}': {}",
validated_path.display(),
e
))),
}
}