diff --git a/src/built_in_functions/fs.rs b/src/built_in_functions/fs.rs index 9eecc19..7d630e7 100644 --- a/src/built_in_functions/fs.rs +++ b/src/built_in_functions/fs.rs @@ -7,7 +7,7 @@ use crate::{error::RuntimeError, Context, Type, Value}; use super::Callable; -pub fn fs_functions() -> impl Iterator { +pub fn all_fs_functions() -> impl Iterator { all() } diff --git a/src/built_in_functions/io.rs b/src/built_in_functions/io.rs new file mode 100644 index 0000000..b6e869e --- /dev/null +++ b/src/built_in_functions/io.rs @@ -0,0 +1,56 @@ +use enum_iterator::{all, Sequence}; +use serde::{Deserialize, Serialize}; + +use crate::{error::RuntimeError, Context, Type, Value}; + +use super::Callable; + +pub fn all_io_functions() -> impl Iterator { + all() +} + +#[derive(Sequence, Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +pub enum Io { + Stdin, +} + +impl Callable for Io { + fn name(&self) -> &'static str { + match self { + Io::Stdin => "stdin", + } + } + + fn description(&self) -> &'static str { + match self { + Io::Stdin => "Read input from stdin.", + } + } + + fn r#type(&self) -> crate::Type { + match self { + Io::Stdin => Type::Function { + parameter_types: vec![], + return_type: Box::new(Type::String), + }, + } + } + + fn call( + &self, + _arguments: &[Value], + _source: &str, + _context: &Context, + ) -> Result { + match self { + Io::Stdin => { + let mut input = String::new(); + let stdin = std::io::stdin(); + + stdin.read_line(&mut input)?; + + Ok(Value::string(input)) + } + } + } +} diff --git a/src/built_in_functions/mod.rs b/src/built_in_functions/mod.rs index 3535c44..203fa56 100644 --- a/src/built_in_functions/mod.rs +++ b/src/built_in_functions/mod.rs @@ -1,4 +1,5 @@ pub mod fs; +pub mod io; pub mod json; pub mod str; @@ -12,7 +13,7 @@ use crate::{ Context, EnumInstance, Format, Identifier, Type, Value, }; -use self::{fs::Fs, json::Json, str::StrFunction}; +use self::{fs::Fs, io::Io, json::Json, str::StrFunction}; pub trait Callable { fn name(&self) -> &'static str; @@ -30,6 +31,7 @@ pub trait Callable { pub enum BuiltInFunction { AssertEqual, Fs(Fs), + Io(Io), Json(Json), Length, Output, @@ -45,6 +47,7 @@ impl Callable for BuiltInFunction { match self { BuiltInFunction::AssertEqual => "assert_equal", BuiltInFunction::Fs(fs_function) => fs_function.name(), + BuiltInFunction::Io(io_function) => io_function.name(), BuiltInFunction::Json(json_function) => json_function.name(), BuiltInFunction::Length => "length", BuiltInFunction::Output => "output", @@ -60,6 +63,7 @@ impl Callable for BuiltInFunction { match self { BuiltInFunction::AssertEqual => "assert_equal", BuiltInFunction::Fs(fs_function) => fs_function.description(), + BuiltInFunction::Io(io_function) => io_function.description(), BuiltInFunction::Json(json_function) => json_function.description(), BuiltInFunction::Length => "length", BuiltInFunction::Output => "output", @@ -75,6 +79,7 @@ impl Callable for BuiltInFunction { match self { BuiltInFunction::AssertEqual => Type::function(vec![Type::Any, Type::Any], Type::None), BuiltInFunction::Fs(fs_function) => fs_function.r#type(), + BuiltInFunction::Io(io_function) => io_function.r#type(), BuiltInFunction::Json(json_function) => json_function.r#type(), BuiltInFunction::Length => Type::function(vec![Type::Collection], Type::Integer), BuiltInFunction::Output => Type::function(vec![Type::Any], Type::None), @@ -113,6 +118,7 @@ impl Callable for BuiltInFunction { } } BuiltInFunction::Fs(fs_function) => fs_function.call(arguments, _source, context), + BuiltInFunction::Io(io_function) => io_function.call(arguments, _source, context), BuiltInFunction::Json(json_function) => json_function.call(arguments, _source, context), BuiltInFunction::Length => { RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?; diff --git a/src/built_in_values.rs b/src/built_in_values.rs index 3e84733..8d1a835 100644 --- a/src/built_in_values.rs +++ b/src/built_in_values.rs @@ -4,12 +4,16 @@ use enum_iterator::{all, Sequence}; use serde::{Deserialize, Serialize}; use crate::{ - built_in_functions::{fs::fs_functions, json::json_functions, str::string_functions, Callable}, + built_in_functions::{ + fs::all_fs_functions, io::all_io_functions, json::json_functions, str::string_functions, + Callable, + }, BuiltInFunction, EnumInstance, Function, Identifier, List, Map, Value, }; static ARGS: OnceLock = OnceLock::new(); static FS: OnceLock = OnceLock::new(); +static IO: OnceLock = OnceLock::new(); static JSON: OnceLock = OnceLock::new(); static NONE: OnceLock = OnceLock::new(); static RANDOM: OnceLock = OnceLock::new(); @@ -32,6 +36,9 @@ pub enum BuiltInValue { /// File system tools. Fs, + /// Input and output tools. + Io, + /// JSON format tools. Json, @@ -58,6 +65,7 @@ impl BuiltInValue { BuiltInValue::Args => "args", BuiltInValue::AssertEqual => "assert_equal", BuiltInValue::Fs => "fs", + BuiltInValue::Io => "io", BuiltInValue::Json => "json", BuiltInValue::Length => BuiltInFunction::Length.name(), BuiltInValue::None => "None", @@ -75,6 +83,7 @@ impl BuiltInValue { BuiltInValue::Args => "The command line arguments sent to this program.", BuiltInValue::AssertEqual => "Error if the two values are not equal.", BuiltInValue::Fs => "File and directory tools.", + BuiltInValue::Io => "Input/output tools.", BuiltInValue::Json => "JSON formatting tools.", BuiltInValue::Length => BuiltInFunction::Length.description(), BuiltInValue::None => "The absence of a value.", @@ -98,11 +107,26 @@ impl BuiltInValue { BuiltInValue::AssertEqual => { Value::Function(Function::BuiltIn(BuiltInFunction::AssertEqual)) } + BuiltInValue::Io => IO + .get_or_init(|| { + let mut io_map = Map::new(); + + for io_function in all_io_functions() { + let key = io_function.name(); + let value = + Value::Function(Function::BuiltIn(BuiltInFunction::Io(io_function))); + + io_map.set(Identifier::new(key), value); + } + + Value::Map(io_map) + }) + .clone(), BuiltInValue::Fs => FS .get_or_init(|| { let mut fs_map = Map::new(); - for fs_function in fs_functions() { + for fs_function in all_fs_functions() { let key = fs_function.name(); let value = Value::Function(Function::BuiltIn(BuiltInFunction::Fs(fs_function)));