diff --git a/stdlib/src/file.rs b/stdlib/src/file.rs index ed5c1c54..12b8f452 100644 --- a/stdlib/src/file.rs +++ b/stdlib/src/file.rs @@ -6,6 +6,7 @@ use techscript_runtime::{ context::Capability, error::{RuntimeError, RuntimeErrorKind}, value::RuntimeValue, + RuntimeContext, }; impl StdlibRegistry { @@ -18,39 +19,7 @@ impl StdlibRegistry { Rc::new(StdFunction { name: "read".to_string(), arity: 1, - callback: |ctx, args| { - if !ctx.config.capabilities.contains(&Capability::FileSystem) { - return Err(RuntimeError::new( - RuntimeErrorKind::InvalidOperation( - "Security policy violation: FileSystem capability is denied" - .to_string(), - ), - None, - None, - )); - } - let path = match &args[0] { - RuntimeValue::Str(s) => s.clone(), - _ => { - return Err(RuntimeError::new( - RuntimeErrorKind::TypeMismatch { - expected: "string".to_string(), - found: "other".to_string(), - }, - None, - None, - )) - } - }; - let content = fs::read_to_string(&path).map_err(|e| { - RuntimeError::new( - RuntimeErrorKind::InvalidOperation(e.to_string()), - None, - None, - ) - })?; - Ok(RuntimeValue::Str(content)) - }, + callback: file_read, }), ); @@ -59,52 +28,7 @@ impl StdlibRegistry { Rc::new(StdFunction { name: "write".to_string(), arity: 2, - callback: |ctx, args| { - if !ctx.config.capabilities.contains(&Capability::FileSystem) { - return Err(RuntimeError::new( - RuntimeErrorKind::InvalidOperation( - "Security policy violation: FileSystem capability is denied" - .to_string(), - ), - None, - None, - )); - } - let path = match &args[0] { - RuntimeValue::Str(s) => s.clone(), - _ => { - return Err(RuntimeError::new( - RuntimeErrorKind::TypeMismatch { - expected: "string".to_string(), - found: "other".to_string(), - }, - None, - None, - )) - } - }; - let content = match &args[1] { - RuntimeValue::Str(s) => s.clone(), - _ => { - return Err(RuntimeError::new( - RuntimeErrorKind::TypeMismatch { - expected: "string".to_string(), - found: "other".to_string(), - }, - None, - None, - )) - } - }; - fs::write(&path, &content).map_err(|e| { - RuntimeError::new( - RuntimeErrorKind::InvalidOperation(e.to_string()), - None, - None, - ) - })?; - Ok(RuntimeValue::Null) - }, + callback: file_write, }), ); @@ -113,52 +37,7 @@ impl StdlibRegistry { Rc::new(StdFunction { name: "copy".to_string(), arity: 2, - callback: |ctx, args| { - if !ctx.config.capabilities.contains(&Capability::FileSystem) { - return Err(RuntimeError::new( - RuntimeErrorKind::InvalidOperation( - "Security policy violation: FileSystem capability is denied" - .to_string(), - ), - None, - None, - )); - } - let src = match &args[0] { - RuntimeValue::Str(s) => s.clone(), - _ => { - return Err(RuntimeError::new( - RuntimeErrorKind::TypeMismatch { - expected: "string".to_string(), - found: "other".to_string(), - }, - None, - None, - )) - } - }; - let dest = match &args[1] { - RuntimeValue::Str(s) => s.clone(), - _ => { - return Err(RuntimeError::new( - RuntimeErrorKind::TypeMismatch { - expected: "string".to_string(), - found: "other".to_string(), - }, - None, - None, - )) - } - }; - fs::copy(&src, &dest).map_err(|e| { - RuntimeError::new( - RuntimeErrorKind::InvalidOperation(e.to_string()), - None, - None, - ) - })?; - Ok(RuntimeValue::Null) - }, + callback: file_copy, }), ); @@ -167,39 +46,7 @@ impl StdlibRegistry { Rc::new(StdFunction { name: "remove".to_string(), arity: 1, - callback: |ctx, args| { - if !ctx.config.capabilities.contains(&Capability::FileSystem) { - return Err(RuntimeError::new( - RuntimeErrorKind::InvalidOperation( - "Security policy violation: FileSystem capability is denied" - .to_string(), - ), - None, - None, - )); - } - let path = match &args[0] { - RuntimeValue::Str(s) => s.clone(), - _ => { - return Err(RuntimeError::new( - RuntimeErrorKind::TypeMismatch { - expected: "string".to_string(), - found: "other".to_string(), - }, - None, - None, - )) - } - }; - fs::remove_file(&path).map_err(|e| { - RuntimeError::new( - RuntimeErrorKind::InvalidOperation(e.to_string()), - None, - None, - ) - })?; - Ok(RuntimeValue::Null) - }, + callback: file_remove, }), ); @@ -208,32 +55,7 @@ impl StdlibRegistry { Rc::new(StdFunction { name: "exists".to_string(), arity: 1, - callback: |ctx, args| { - if !ctx.config.capabilities.contains(&Capability::FileSystem) { - return Err(RuntimeError::new( - RuntimeErrorKind::InvalidOperation( - "Security policy violation: FileSystem capability is denied" - .to_string(), - ), - None, - None, - )); - } - let path = match &args[0] { - RuntimeValue::Str(s) => s.clone(), - _ => { - return Err(RuntimeError::new( - RuntimeErrorKind::TypeMismatch { - expected: "string".to_string(), - found: "other".to_string(), - }, - None, - None, - )) - } - }; - Ok(RuntimeValue::Bool(std::path::Path::new(&path).exists())) - }, + callback: file_exists, }), ); @@ -248,3 +70,202 @@ impl StdlibRegistry { ); } } + +fn file_read( + ctx: &mut RuntimeContext, + args: Vec, +) -> Result { + if !ctx.config.capabilities.contains(&Capability::FileSystem) { + return Err(RuntimeError::new( + RuntimeErrorKind::InvalidOperation( + "Security policy violation: FileSystem capability is denied".to_string(), + ), + None, + None, + )); + } + let path = match &args[0] { + RuntimeValue::Str(s) => s.clone(), + _ => { + return Err(RuntimeError::new( + RuntimeErrorKind::TypeMismatch { + expected: "string".to_string(), + found: "other".to_string(), + }, + None, + None, + )) + } + }; + let content = fs::read_to_string(&path).map_err(|e| { + RuntimeError::new( + RuntimeErrorKind::InvalidOperation(e.to_string()), + None, + None, + ) + })?; + Ok(RuntimeValue::Str(content)) +} + +fn file_write( + ctx: &mut RuntimeContext, + args: Vec, +) -> Result { + if !ctx.config.capabilities.contains(&Capability::FileSystem) { + return Err(RuntimeError::new( + RuntimeErrorKind::InvalidOperation( + "Security policy violation: FileSystem capability is denied".to_string(), + ), + None, + None, + )); + } + let path = match &args[0] { + RuntimeValue::Str(s) => s.clone(), + _ => { + return Err(RuntimeError::new( + RuntimeErrorKind::TypeMismatch { + expected: "string".to_string(), + found: "other".to_string(), + }, + None, + None, + )) + } + }; + let content = match &args[1] { + RuntimeValue::Str(s) => s.clone(), + _ => { + return Err(RuntimeError::new( + RuntimeErrorKind::TypeMismatch { + expected: "string".to_string(), + found: "other".to_string(), + }, + None, + None, + )) + } + }; + fs::write(&path, &content).map_err(|e| { + RuntimeError::new( + RuntimeErrorKind::InvalidOperation(e.to_string()), + None, + None, + ) + })?; + Ok(RuntimeValue::Null) +} + +fn file_copy( + ctx: &mut RuntimeContext, + args: Vec, +) -> Result { + if !ctx.config.capabilities.contains(&Capability::FileSystem) { + return Err(RuntimeError::new( + RuntimeErrorKind::InvalidOperation( + "Security policy violation: FileSystem capability is denied".to_string(), + ), + None, + None, + )); + } + let src = match &args[0] { + RuntimeValue::Str(s) => s.clone(), + _ => { + return Err(RuntimeError::new( + RuntimeErrorKind::TypeMismatch { + expected: "string".to_string(), + found: "other".to_string(), + }, + None, + None, + )) + } + }; + let dest = match &args[1] { + RuntimeValue::Str(s) => s.clone(), + _ => { + return Err(RuntimeError::new( + RuntimeErrorKind::TypeMismatch { + expected: "string".to_string(), + found: "other".to_string(), + }, + None, + None, + )) + } + }; + fs::copy(&src, &dest).map_err(|e| { + RuntimeError::new( + RuntimeErrorKind::InvalidOperation(e.to_string()), + None, + None, + ) + })?; + Ok(RuntimeValue::Null) +} + +fn file_remove( + ctx: &mut RuntimeContext, + args: Vec, +) -> Result { + if !ctx.config.capabilities.contains(&Capability::FileSystem) { + return Err(RuntimeError::new( + RuntimeErrorKind::InvalidOperation( + "Security policy violation: FileSystem capability is denied".to_string(), + ), + None, + None, + )); + } + let path = match &args[0] { + RuntimeValue::Str(s) => s.clone(), + _ => { + return Err(RuntimeError::new( + RuntimeErrorKind::TypeMismatch { + expected: "string".to_string(), + found: "other".to_string(), + }, + None, + None, + )) + } + }; + fs::remove_file(&path).map_err(|e| { + RuntimeError::new( + RuntimeErrorKind::InvalidOperation(e.to_string()), + None, + None, + ) + })?; + Ok(RuntimeValue::Null) +} + +fn file_exists( + ctx: &mut RuntimeContext, + args: Vec, +) -> Result { + if !ctx.config.capabilities.contains(&Capability::FileSystem) { + return Err(RuntimeError::new( + RuntimeErrorKind::InvalidOperation( + "Security policy violation: FileSystem capability is denied".to_string(), + ), + None, + None, + )); + } + let path = match &args[0] { + RuntimeValue::Str(s) => s.clone(), + _ => { + return Err(RuntimeError::new( + RuntimeErrorKind::TypeMismatch { + expected: "string".to_string(), + found: "other".to_string(), + }, + None, + None, + )) + } + }; + Ok(RuntimeValue::Bool(std::path::Path::new(&path).exists())) +}