use std::sync::{Arc, RwLock};
use crate::{
data::{
self,
int::{INT_MAX, INT_MIN},
Data, MersData, Type,
},
errors::CheckError,
info::Local,
program::run::{CheckInfo, CheckLocalGlobalInfo, RunLocalGlobalInfo},
};
pub mod gen;
pub mod util;
pub mod with_base;
pub mod with_command_running;
pub mod with_fs;
pub mod with_get;
pub mod with_iters;
pub mod with_list;
pub mod with_math;
pub mod with_multithreading;
pub mod with_stdio;
pub mod with_string;
pub struct Config {
globals: usize,
info_parsed: super::parsed::Info,
info_run: super::run::Info,
info_check: super::run::CheckInfo,
}
impl Config {
pub fn bundle_std(self) -> Self {
self.with_fs()
.with_multithreading()
.with_command_running()
.with_stdio()
.bundle_pure()
}
pub fn bundle_pure(self) -> Self {
self.with_string().with_list().bundle_base()
}
pub fn bundle_base(self) -> Self {
self.with_iters().with_get().with_math().with_base()
}
pub fn new() -> Self {
let info_parsed = crate::program::parsed::Info::new(
crate::program::parsed::LocalGlobalInfo::new(Arc::new(Default::default())),
);
let mut info_check = CheckInfo::new(CheckLocalGlobalInfo::new(Arc::clone(
&info_parsed.global.object_fields,
)));
let info_run = crate::program::run::Info::new(RunLocalGlobalInfo::new(Arc::clone(
&info_parsed.global.object_fields,
)));
macro_rules! init_d {
($e:expr) => {
let t = $e;
info_check
.scopes
.last_mut()
.unwrap()
.types
.insert(t.to_string(), Ok(Arc::new(data::Type::new(t))));
};
}
init_d!(data::bool::TrueT);
init_d!(data::bool::FalseT);
info_check
.scopes
.last_mut()
.unwrap()
.types
.insert("Bool".to_owned(), Ok(Arc::new(data::bool::bool_type())));
init_d!(data::byte::ByteT);
info_check.scopes.last_mut().unwrap().types.insert(
"Int".to_owned(),
Err(Arc::new(|range, _| {
Ok(Arc::new(Type::new({
let range = range.trim();
if range.is_empty() {
data::int::IntT(INT_MIN, INT_MAX)
} else if let Some((min, max)) = range.split_once("..") {
let (min, max) = (min.trim(), max.trim());
let min = if min.is_empty() {
data::int::INT_MIN
} else if let Ok(v) = min.parse() {
v
} else {
return Err(CheckError::new().msg_str(format!("In type `Int<{min}..{max}>`: min was present but not a valid integer.")));
};
let max = if max.is_empty() {
data::int::INT_MAX
} else if let Ok(v) = max.parse() {
v
} else {
return Err(CheckError::new().msg_str(format!("In type `Int<{min}..{max}>`: max was present but not a valid integer.")));
};
if min > max {
return Err(CheckError::new().msg_str(format!("In type `Int<{min}..{max}>`: min ({min}) must be smaller than or equal to max ({max}). Did you mean `Int<{max}..{min}>`?")));
}
crate::data::int::IntT(min, max)
} else if let Ok(v) = range.parse() {
crate::data::int::IntT(v, v)
} else {
return Err(CheckError::new().msg_str(format!("In type `Int<{range}>`: Invalid range. Either use `Int` (or `Int<>` or `Int<..>`) for the entire integer range, `Int<n>` for a specific number, `Int<n..>` for all numbers `>=n`, `Int<..m>` for all numbers `<=m`, or `Int<n..m>` for all numbers `>=n` and `<= m`.")));
}
})))
})),
);
init_d!(data::float::FloatT);
init_d!(data::string::StringT);
Self {
globals: 0,
info_parsed,
info_run,
info_check,
}
}
pub fn add_var(self, name: impl Into<String>, val: impl MersData) -> Self {
let t = val.as_type();
self.add_var_from_arc(name.into(), Arc::new(RwLock::new(Data::new(val))), t)
}
pub fn add_var_from_data(self, name: String, val: Data) -> Self {
let t = val.get().as_type();
self.add_var_from_arc(name, Arc::new(RwLock::new(val)), t)
}
pub fn add_var_from_arc(
mut self,
name: String,
val: Arc<RwLock<Data>>,
mut val_type: crate::data::Type,
) -> Self {
{
for t in val_type.types.iter_mut() {
if let Some(mut f) = t
.as_any()
.downcast_ref::<data::function::FunctionT>()
.cloned()
{
f.1.global.object_fields = Arc::clone(&self.info_check.global.object_fields);
f.1.global.object_fields_rev =
Arc::clone(&self.info_check.global.object_fields_rev);
*t = Arc::new(f);
}
}
let data = val.write().unwrap();
let mut data = data.get_mut_unchecked();
if let Some(f) = data.mut_any().downcast_mut::<data::function::Function>() {
f.info.global.object_fields = Arc::clone(&self.info_check.global.object_fields);
f.info.global.object_fields_rev =
Arc::clone(&self.info_check.global.object_fields_rev);
let mut info_check = f.info_check.lock().unwrap();
info_check.global.object_fields = Arc::clone(&self.info_check.global.object_fields);
info_check.global.object_fields_rev =
Arc::clone(&self.info_check.global.object_fields_rev);
}
}
self.info_parsed.scopes[0].init_var(name, (0, self.globals));
self.info_run.scopes[0].init_var(self.globals, val);
self.info_check.scopes[0].init_var(self.globals, val_type);
self.globals += 1;
self
}
pub fn add_type(
mut self,
name: String,
t: Result<
Arc<Type>,
Arc<dyn Fn(&str, &CheckInfo) -> Result<Arc<Type>, CheckError> + Send + Sync>,
>,
) -> Self {
self.info_check.scopes[0].types.insert(name, t);
self
}
pub fn infos(self) -> (super::parsed::Info, super::run::Info, super::run::CheckInfo) {
(self.info_parsed, self.info_run, self.info_check)
}
}