allow using other stdin/stdout/stderr via RunInfo

This commit is contained in:
Mark 2024-10-14 00:23:14 +02:00
parent 4e73ec0201
commit 8e07f240cc
4 changed files with 78 additions and 19 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mers_lib" name = "mers_lib"
version = "0.9.10" version = "0.9.11"
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
description = "library to use the mers language in other projects" description = "library to use the mers language in other projects"

View File

@ -4,19 +4,14 @@ use std::{
}; };
use crate::{ use crate::{
data::{ data::{self, bool::bool_type, int::INT_MAX, Data, MersTypeWInfo, Type},
self,
bool::bool_type,
int::{INT_MAX, INT_MIN},
Data, MersTypeWInfo, Type,
},
errors::CheckError, errors::CheckError,
program::run::{CheckInfo, Info}, program::run::{CheckInfo, Info},
}; };
use super::{ use super::{
gen::{ gen::{
function::{func, func_end, func_err}, function::{func, func_err},
IntR, OneOf, IntR, OneOf,
}, },
Config, Config,

View File

@ -1,5 +1,5 @@
use std::{ use std::{
io::Write, io::{BufRead, Write},
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@ -66,8 +66,13 @@ impl Config {
) )
.add_var( .add_var(
"read_line", "read_line",
func(|_: (), _| { func(|_: (), i| {
Ok(if let Some(Ok(line)) = std::io::stdin().lines().next() { let next_line = if let Some(stdin) = &mut *i.global.stdin.lock().unwrap() {
std::io::BufReader::new(stdin).lines().next()
} else {
std::io::stdin().lines().next()
};
Ok(if let Some(Ok(line)) = next_line {
OneOrNone(Some(line)) OneOrNone(Some(line))
} else { } else {
OneOrNone(None) OneOrNone(None)
@ -82,7 +87,15 @@ impl Config {
out: Ok(Arc::new(|a, _i| Ok(a.clone()))), out: Ok(Arc::new(|a, _i| Ok(a.clone()))),
run: Arc::new(|a, i| { run: Arc::new(|a, i| {
let a2 = a.get(); let a2 = a.get();
eprintln!("{} :: {}", a2.as_type().with_info(i), a2.with_info(i)); let ty = a2.as_type();
let ty = ty.with_info(i);
let v = a2.with_info(i);
if let Some((_, stderr)) = &mut *i.global.stdout.lock().unwrap() {
let _ = write!(stderr, "{ty} :: {v}");
let _ = stderr.flush();
} else {
eprintln!("{ty} :: {v}");
}
drop(a2); drop(a2);
Ok(a) Ok(a)
}), }),
@ -96,8 +109,13 @@ impl Config {
info_check: Arc::new(Mutex::new(CheckInfo::neverused())), info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, i| { run: Arc::new(|a, i| {
if let Some((_, stderr)) = &mut *i.global.stdout.lock().unwrap() {
let _ = write!(stderr, "{}", a.get().with_info(i));
let _ = stderr.flush();
} else {
eprint!("{}", a.get().with_info(i)); eprint!("{}", a.get().with_info(i));
_ = std::io::stderr().lock().flush(); let _ = std::io::stderr().lock().flush();
}
Ok(Data::empty_tuple()) Ok(Data::empty_tuple())
}), }),
inner_statements: None, inner_statements: None,
@ -110,7 +128,12 @@ impl Config {
info_check: Arc::new(Mutex::new(CheckInfo::neverused())), info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, i| { run: Arc::new(|a, i| {
if let Some((_, stderr)) = &mut *i.global.stdout.lock().unwrap() {
let _ = writeln!(stderr, "{}", a.get().with_info(i));
let _ = stderr.flush();
} else {
eprintln!("{}", a.get().with_info(i)); eprintln!("{}", a.get().with_info(i));
}
Ok(Data::empty_tuple()) Ok(Data::empty_tuple())
}), }),
inner_statements: None, inner_statements: None,
@ -123,8 +146,13 @@ impl Config {
info_check: Arc::new(Mutex::new(CheckInfo::neverused())), info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, i| { run: Arc::new(|a, i| {
if let Some((stdout, _)) = &mut *i.global.stdout.lock().unwrap() {
let _ = write!(stdout, "{}", a.get().with_info(i));
let _ = stdout.flush();
} else {
print!("{}", a.get().with_info(i)); print!("{}", a.get().with_info(i));
_ = std::io::stdout().lock().flush(); let _ = std::io::stdout().lock().flush();
}
Ok(Data::empty_tuple()) Ok(Data::empty_tuple())
}), }),
inner_statements: None, inner_statements: None,
@ -137,7 +165,12 @@ impl Config {
info_check: Arc::new(Mutex::new(CheckInfo::neverused())), info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))),
run: Arc::new(|a, i| { run: Arc::new(|a, i| {
if let Some((stdout, _)) = &mut *i.global.stdout.lock().unwrap() {
let _ = writeln!(stdout, "{}", a.get().with_info(i));
let _ = stdout.flush();
} else {
println!("{}", a.get().with_info(i)); println!("{}", a.get().with_info(i));
}
Ok(Data::empty_tuple()) Ok(Data::empty_tuple())
}), }),
inner_statements: None, inner_statements: None,

View File

@ -1,6 +1,7 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
fmt::Debug, fmt::Debug,
io::{Read, Write},
sync::{Arc, Mutex, RwLock}, sync::{Arc, Mutex, RwLock},
time::Instant, time::Instant,
}; };
@ -126,12 +127,38 @@ pub type CheckInfo = info::Info<CheckLocal>;
pub struct RunLocal { pub struct RunLocal {
pub vars: Vec<Arc<RwLock<Data>>>, pub vars: Vec<Arc<RwLock<Data>>>,
} }
#[derive(Clone, Debug)] #[derive(Clone)]
pub struct RunLocalGlobalInfo { pub struct RunLocalGlobalInfo {
/// if set, if `Instant::now()` is equal to or after the set `Instant`, stop the program with an error. /// if set, if `Instant::now()` is equal to or after the set `Instant`, stop the program with an error.
pub limit_runtime: Option<Instant>, pub limit_runtime: Option<Instant>,
pub object_fields: Arc<Mutex<HashMap<String, usize>>>, pub object_fields: Arc<Mutex<HashMap<String, usize>>>,
pub object_fields_rev: Arc<Mutex<Vec<String>>>, pub object_fields_rev: Arc<Mutex<Vec<String>>>,
pub stdin: Arc<Mutex<Option<Box<dyn Read + Send + Sync>>>>,
pub stdout: Arc<Mutex<Option<(Box<dyn Write + Send + Sync>, Box<dyn Write + Send + Sync>)>>>,
}
#[derive(Debug)]
#[allow(unused)]
struct RunLocalGlobalInfoDebug<'a> {
pub limit_runtime: &'a Option<Instant>,
pub object_fields: &'a Arc<Mutex<HashMap<String, usize>>>,
pub object_fields_rev: &'a Arc<Mutex<Vec<String>>>,
pub stdin: bool,
pub stdout: bool,
}
impl Debug for RunLocalGlobalInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{:?}",
RunLocalGlobalInfoDebug {
limit_runtime: &self.limit_runtime,
object_fields: &self.object_fields,
object_fields_rev: &self.object_fields_rev,
stdin: self.stdin.lock().unwrap().is_some(),
stdout: self.stdout.lock().unwrap().is_some()
}
)
}
} }
impl RunLocalGlobalInfo { impl RunLocalGlobalInfo {
pub fn new(object_fields: Arc<Mutex<HashMap<String, usize>>>) -> Self { pub fn new(object_fields: Arc<Mutex<HashMap<String, usize>>>) -> Self {
@ -139,6 +166,8 @@ impl RunLocalGlobalInfo {
limit_runtime: None, limit_runtime: None,
object_fields, object_fields,
object_fields_rev: Default::default(), object_fields_rev: Default::default(),
stdin: Arc::new(Mutex::new(None)),
stdout: Arc::new(Mutex::new(None)),
} }
} }
} }
@ -216,6 +245,8 @@ impl info::Local for RunLocal {
limit_runtime: None, limit_runtime: None,
object_fields: Default::default(), object_fields: Default::default(),
object_fields_rev: Default::default(), object_fields_rev: Default::default(),
stdin: Default::default(),
stdout: Default::default(),
} }
} }
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) { fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {