From 5d752c99691b5c381fb0d224877da474d7869c74 Mon Sep 17 00:00:00 2001 From: Mark <> Date: Sat, 17 Feb 2024 11:46:07 +0100 Subject: [PATCH] change parse_int/float and debug, add spawn_command and childproc_* functions --- mers/Cargo.toml | 4 +- .../program/configs/with_command_running.rs | 371 ++++++++++++++++-- mers_lib/src/program/configs/with_math.rs | 16 +- mers_lib/src/program/configs/with_stdio.rs | 9 +- 4 files changed, 350 insertions(+), 50 deletions(-) diff --git a/mers/Cargo.toml b/mers/Cargo.toml index 35402ef..7930b42 100755 --- a/mers/Cargo.toml +++ b/mers/Cargo.toml @@ -11,6 +11,6 @@ repository = "https://github.com/Dummi26/mers" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -mers_lib = "0.4.0" -# mers_lib = { path = "../mers_lib" } +# mers_lib = "0.4.0" +mers_lib = { path = "../mers_lib" } clap = { version = "4.3.19", features = ["derive"] } diff --git a/mers_lib/src/program/configs/with_command_running.rs b/mers_lib/src/program/configs/with_command_running.rs index b7de3a9..aa4d52b 100755 --- a/mers_lib/src/program/configs/with_command_running.rs +++ b/mers_lib/src/program/configs/with_command_running.rs @@ -1,6 +1,7 @@ use std::{ fmt::Display, - process::Command, + io::{BufRead, BufReader, Read}, + process::{ChildStderr, ChildStdin, ChildStdout, Command, Stdio}, sync::{Arc, Mutex}, }; @@ -18,7 +19,10 @@ impl Config { /// `RunCommandError` holds the error if the command can't be executed /// returns (int/(), string, string) on success (status code, stdout, stderr) pub fn with_command_running(self) -> Self { - self.add_var( + self + .add_type("RunCommandError".to_owned(), Ok(Arc::new(RunCommandErrorT))) + .add_type("ChildProcess".to_owned(), Ok(Arc::new(ChildProcessT))) + .add_var( "run_command".to_string(), Data::new(data::function::Function { info: Arc::new(program::run::Info::neverused()), @@ -27,7 +31,7 @@ impl Config { if a.types.iter().all(|t| t.as_any().downcast_ref::().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in(&data::string::StringT) && t.0[1].iterable().is_some_and(|t| t.is_included_in(&data::string::StringT)))) { Ok(Type::newm(vec![ Arc::new(data::tuple::TupleT(vec![ - Type::newm(vec![Arc::new(data::int::IntT), Arc::new(data::tuple::TupleT(vec![]))]), + Type::newm(vec![Arc::new(data::int::IntT), Arc::new(data::bool::BoolT)]), Type::new(data::string::StringT), Type::new(data::string::StringT), ])), @@ -38,47 +42,338 @@ impl Config { } }), run: Arc::new(|a, _i| { - if let Some(cmd) = a.get().as_any().downcast_ref::() { - if let (Some(cmd), Some(args)) = (cmd.get(0), cmd.get(1)) { - if let (Some(cmd), Some(args)) = ( - cmd.get().as_any().downcast_ref::(), - args.get().iterable(), - ) { - match Command::new(&cmd.0) - .args(args.map(|v| v.get().to_string())) - .output() - { - Ok(output) => { - let status = if let Some(code) = output.status.code() { - Data::new(data::int::Int(code as _)) - } else { - Data::empty_tuple() - }; - let stdout = - String::from_utf8_lossy(&output.stdout).into_owned(); - let stderr = - String::from_utf8_lossy(&output.stderr).into_owned(); - Data::new(data::tuple::Tuple(vec![ - status, - Data::new(data::string::String(stdout)), - Data::new(data::string::String(stderr)), - ])) - } - Err(e) => Data::new(RunCommandError(e.to_string())), - } + let a = a.get(); + let cmd = a.as_any().downcast_ref::().unwrap(); + let (cmd, args) = (&cmd.0[0], &cmd.0[1]); + let cmd = cmd.get(); + let (cmd, args) = ( + cmd.as_any().downcast_ref::().unwrap(), + args.get().iterable().unwrap(), + ); + match Command::new(&cmd.0) + .args(args.map(|v| v.get().to_string())) + .output() + { + Ok(output) => { + let status = if let Some(code) = output.status.code() { + Data::new(data::int::Int(code as _)) } else { - unreachable!("run_command called with arguments other than (String, ).") - } - } else { - unreachable!("run_command called with too few arguments") + Data::new(data::bool::Bool(output.status.success())) + }; + let stdout = + String::from_utf8_lossy(&output.stdout).into_owned(); + let stderr = + String::from_utf8_lossy(&output.stderr).into_owned(); + Data::new(data::tuple::Tuple(vec![ + status, + Data::new(data::string::String(stdout)), + Data::new(data::string::String(stderr)), + ])) } - } else { - unreachable!("run_command called with non-tuple argument") + Err(e) => Data::new(RunCommandError(e.to_string())), } }), inner_statements: None, }), ) + .add_var( + "spawn_command".to_string(), + Data::new(data::function::Function { + info: Arc::new(program::run::Info::neverused()), + info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + out: Arc::new(|a, _i| { + if a.types.iter().all(|t| t.as_any().downcast_ref::().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in(&data::string::StringT) && t.0[1].iterable().is_some_and(|t| t.is_included_in(&data::string::StringT)))) { + Ok(Type::newm(vec![ + Arc::new(ChildProcessT), + Arc::new(RunCommandErrorT) + ])) + } else { + return Err(format!("spawn_command called with invalid arguments (must be (String, Iter))").into()); + } + }), + run: Arc::new(|a, _i| { + let a = a.get(); + let cmd = a.as_any().downcast_ref::().unwrap(); + let (cmd, args) = (&cmd.0[0], &cmd.0[1]); + let cmd = cmd.get(); + let (cmd, args) = ( + cmd.as_any().downcast_ref::().unwrap(), + args.get().iterable().unwrap(), + ); + match Command::new(&cmd.0) + .args(args.map(|v| v.get().to_string())) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + { + Ok(mut child) => { + let a = child.stdin.take().unwrap(); + let b = BufReader::new(child.stdout.take().unwrap()); + let c = BufReader::new(child.stderr.take().unwrap()); + Data::new(ChildProcess(Arc::new(Mutex::new((child, a, b, c))))) + } + Err(e) => Data::new(RunCommandError(e.to_string())), + } + }), + inner_statements: None, + }), + ) + .add_var( + "childproc_exited".to_string(), + Data::new(data::function::Function { + info: Arc::new(program::run::Info::neverused()), + info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + out: Arc::new(|a, _i| { + if a.is_included_in(&ChildProcessT) { + Ok(Type::newm(vec![ + Arc::new(data::tuple::TupleT(vec![Type::new(data::bool::BoolT)])), + Arc::new(data::tuple::TupleT(vec![])), + ])) + } else { + return Err(format!("childproc_exited called on non-ChildProcess type {a}").into()); + } + }), + run: Arc::new(|a, _i| { + let a = a.get(); + let child = a.as_any().downcast_ref::().unwrap(); + let mut child = child.0.lock().unwrap(); + match child.0.try_wait() { + Ok(Some(_)) => Data::one_tuple(Data::new(data::bool::Bool(true))), + Ok(None) => Data::one_tuple(Data::new(data::bool::Bool(false))), + Err(_) => Data::empty_tuple(), + } + }), + inner_statements: None, + }), + ) + .add_var( + "childproc_await".to_string(), + Data::new(data::function::Function { + info: Arc::new(program::run::Info::neverused()), + info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + out: Arc::new(|a, _i| { + if a.is_included_in(&ChildProcessT) { + Ok(Type::newm(vec![ + Arc::new(data::int::IntT), + Arc::new(data::bool::BoolT), + Arc::new(data::tuple::TupleT(vec![])), + ])) + } else { + return Err(format!("childproc_exited called on non-ChildProcess type {a}").into()); + } + }), + run: Arc::new(|a, _i| { + let a = a.get(); + let child = a.as_any().downcast_ref::().unwrap(); + let mut child = child.0.lock().unwrap(); + match child.0.wait() { + Ok(s) => if let Some(s) = s.code() { + Data::new(data::int::Int(s as _)) + } else { + Data::new(data::bool::Bool(s.success())) + } + Err(_) => Data::empty_tuple(), + } + }), + inner_statements: None, + }), + ) + .add_var( + "childproc_read_byte".to_string(), + Data::new(data::function::Function { + info: Arc::new(program::run::Info::neverused()), + info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + out: Arc::new(|a, _i| { + if a.is_included_in(&ChildProcessT) { + Ok(Type::newm(vec![ + Arc::new(data::tuple::TupleT(vec![Type::new(data::int::IntT)])), + Arc::new(data::tuple::TupleT(vec![])), + ])) + } else { + return Err(format!("childproc_read_byte called on non-ChildProcess type {a}").into()); + } + }), + run: Arc::new(|a, _i| { + let a = a.get(); + let child = a.as_any().downcast_ref::().unwrap(); + let mut child = child.0.lock().unwrap(); + let mut buf = [0]; + if child.2.read_exact(&mut buf).is_ok() { + Data::one_tuple(Data::new(data::int::Int(buf[0] as _))) + } else { + Data::empty_tuple() + } + }), + inner_statements: None, + }), + ) + .add_var( + "childproc_readerr_byte".to_string(), + Data::new(data::function::Function { + info: Arc::new(program::run::Info::neverused()), + info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + out: Arc::new(|a, _i| { + if a.is_included_in(&ChildProcessT) { + Ok(Type::newm(vec![ + Arc::new(data::tuple::TupleT(vec![Type::new(data::int::IntT)])), + Arc::new(data::tuple::TupleT(vec![])), + ])) + } else { + return Err(format!("childproc_readerr_byte called on non-ChildProcess type {a}").into()); + } + }), + run: Arc::new(|a, _i| { + let a = a.get(); + let child = a.as_any().downcast_ref::().unwrap(); + let mut child = child.0.lock().unwrap(); + let mut buf = [0]; + if child.3.read_exact(&mut buf).is_ok() { + Data::one_tuple(Data::new(data::int::Int(buf[0] as _))) + } else { + Data::empty_tuple() + } + }), + inner_statements: None, + }), + ) + .add_var( + "childproc_read_line".to_string(), + Data::new(data::function::Function { + info: Arc::new(program::run::Info::neverused()), + info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + out: Arc::new(|a, _i| { + if a.is_included_in(&ChildProcessT) { + Ok(Type::newm(vec![ + Arc::new(data::tuple::TupleT(vec![Type::new(data::string::StringT)])), + Arc::new(data::tuple::TupleT(vec![])), + ])) + } else { + return Err(format!("childproc_read_line called on non-ChildProcess type {a}").into()); + } + }), + run: Arc::new(|a, _i| { + let a = a.get(); + let child = a.as_any().downcast_ref::().unwrap(); + let mut child = child.0.lock().unwrap(); + let mut buf = String::new(); + if child.2.read_line(&mut buf).is_ok() { + Data::one_tuple(Data::new(data::string::String(buf))) + } else { + Data::empty_tuple() + } + }), + inner_statements: None, + }), + ) + .add_var( + "childproc_readerr_line".to_string(), + Data::new(data::function::Function { + info: Arc::new(program::run::Info::neverused()), + info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + out: Arc::new(|a, _i| { + if a.is_included_in(&ChildProcessT) { + Ok(Type::newm(vec![ + Arc::new(data::tuple::TupleT(vec![Type::new(data::string::StringT)])), + Arc::new(data::tuple::TupleT(vec![])), + ])) + } else { + return Err(format!("childproc_read_line called on non-ChildProcess type {a}").into()); + } + }), + run: Arc::new(|a, _i| { + let a = a.get(); + let child = a.as_any().downcast_ref::().unwrap(); + let mut child = child.0.lock().unwrap(); + let mut buf = String::new(); + if child.3.read_line(&mut buf).is_ok() { + Data::one_tuple(Data::new(data::string::String(buf))) + } else { + Data::empty_tuple() + } + }), + inner_statements: None, + }), + ) + } +} + +#[derive(Clone, Debug)] +pub struct ChildProcess( + Arc< + Mutex<( + std::process::Child, + ChildStdin, + BufReader, + BufReader, + )>, + >, +); +#[derive(Clone, Debug)] +pub struct ChildProcessT; +impl MersData for ChildProcess { + fn iterable(&self) -> Option>> { + None + } + fn get(&self, _i: usize) -> Option { + None + } + fn is_eq(&self, other: &dyn MersData) -> bool { + other + .as_any() + .downcast_ref::() + .is_some_and(|other| Arc::ptr_eq(&self.0, &other.0)) + } + fn clone(&self) -> Box { + Box::new(Clone::clone(self)) + } + fn as_type(&self) -> Type { + Type::new(ChildProcessT) + } + fn as_any(&self) -> &dyn std::any::Any { + self + } + fn mut_any(&mut self) -> &mut dyn std::any::Any { + self + } + fn to_any(self) -> Box { + Box::new(self) + } +} +impl Display for ChildProcess { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "") + } +} +impl MersType for ChildProcessT { + fn iterable(&self) -> Option { + None + } + fn get(&self) -> Option { + None + } + fn is_same_type_as(&self, other: &dyn MersType) -> bool { + other.as_any().is::() + } + fn is_included_in_single(&self, target: &dyn MersType) -> bool { + target.as_any().is::() + } + fn subtypes(&self, acc: &mut Type) { + acc.add(Arc::new(self.clone())); + } + fn as_any(&self) -> &dyn std::any::Any { + self + } + fn mut_any(&mut self) -> &mut dyn std::any::Any { + self + } + fn to_any(self) -> Box { + Box::new(self) + } +} +impl Display for ChildProcessT { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "ChildProcess") } } @@ -132,7 +427,7 @@ impl MersType for RunCommandErrorT { } impl Display for RunCommandError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "RunCommandError: {}", self.0) + write!(f, "{}", self.0) } } impl Display for RunCommandErrorT { diff --git a/mers_lib/src/program/configs/with_math.rs b/mers_lib/src/program/configs/with_math.rs index ceb40bd..74f9960 100755 --- a/mers_lib/src/program/configs/with_math.rs +++ b/mers_lib/src/program/configs/with_math.rs @@ -19,8 +19,8 @@ impl Config { /// `gt: fn` returns true if the input keeps decreasing, that is, for (a, b), a > b, for (a, b, c), a > b > c, and so on. /// `ltoe: fn` returns true if the input only increases, that is, for (a, b), a <= b, for (a, b, c), a <= b <= c, and so on. /// `gtoe: fn` returns true if the input only decreases, that is, for (a, b), a >= b, for (a, b, c), a >= b >= c, and so on. - /// `parse_int: fn` parses a string to an int, returns () on failure - /// `parse_float: fn` parses a string to an int, returns () on failure + /// `parse_int: fn` parses a string to an int, returns () on failure and (Int) otherwise + /// `parse_float: fn` parses a string to an int, returns () on failure and (Int) otherwise /// TODO! /// `as_float: fn` turns integers into floats. returns floats without changing them. /// `round: fn` rounds the float and returns an int @@ -62,7 +62,9 @@ impl Config { out: Arc::new(|a, _i| { if a.is_included_in(&Type::new(data::string::StringT)) { Ok(Type::newm(vec![ - Arc::new(data::float::FloatT), + Arc::new(data::tuple::TupleT(vec![ + Type::new(data::float::FloatT), + ])), Arc::new(data::tuple::TupleT(vec![])), ])) } else { @@ -71,7 +73,7 @@ impl Config { }), run: Arc::new(|a, _i| { if let Ok(n) = a.get().as_any().downcast_ref::().unwrap().0.parse() { - Data::new(data::float::Float(n)) + Data::one_tuple(Data::new(data::float::Float(n))) } else { Data::empty_tuple() } @@ -83,7 +85,9 @@ impl Config { out: Arc::new(|a, _i| { if a.is_included_in(&Type::new(data::string::StringT)) { Ok(Type::newm(vec![ - Arc::new(data::int::IntT), + Arc::new(data::tuple::TupleT(vec![ + Type::new(data::int::IntT), + ])), Arc::new(data::tuple::TupleT(vec![])), ])) } else { @@ -92,7 +96,7 @@ impl Config { }), run: Arc::new(|a, _i| { if let Ok(n) = a.get().as_any().downcast_ref::().unwrap().0.parse() { - Data::new(data::int::Int(n)) + Data::one_tuple(Data::new(data::int::Int(n))) } else { Data::empty_tuple() } diff --git a/mers_lib/src/program/configs/with_stdio.rs b/mers_lib/src/program/configs/with_stdio.rs index 0b2d9d4..e9f18cd 100755 --- a/mers_lib/src/program/configs/with_stdio.rs +++ b/mers_lib/src/program/configs/with_stdio.rs @@ -50,11 +50,12 @@ impl Config { Data::new(data::function::Function { info: Arc::new(program::run::Info::neverused()), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), - out: Arc::new(|_a, _i| Ok(Type::empty_tuple())), + out: Arc::new(|a, _i| Ok(a.clone())), run: Arc::new(|a, _i| { - let a = a.get(); - eprintln!("{} :: {}", a.as_type(), a); - Data::empty_tuple() + let a2 = a.get(); + eprintln!("{} :: {}", a2.as_type(), a2); + drop(a2); + a }), inner_statements: None, }),