diff --git a/src/script/block.rs b/src/script/block.rs index a62311f..a1650f1 100644 --- a/src/script/block.rs +++ b/src/script/block.rs @@ -310,7 +310,7 @@ pub mod to_runnable { if builtin.can_take(&rargs.iter().map(|v| v.out()).collect()) { RStatementEnum::BuiltinFunction(builtin, rargs) } else { - todo!("ERR: Builtin function with wrong args - this isn't a proper error yet, sorry."); + todo!("ERR: Builtin function \"{v}\" with wrong args - this isn't a proper error yet, sorry."); } } else { return Err(ToRunnableError::UseOfUndefinedFunction(v.clone())); diff --git a/src/script/builtins.rs b/src/script/builtins.rs index 1f2b01a..a6212c8 100644 --- a/src/script/builtins.rs +++ b/src/script/builtins.rs @@ -134,7 +134,7 @@ impl BuiltinFunction { if input.len() >= 1 { input[0].types.iter().all(|v| { if let VSingleType::Function(v) = v { - if v.iter().any(|(i, _)| i.len() == input.len()) { + if v.iter().any(|(i, _)| i.len() == input.len() - 1) { eprintln!("Warn: Function inputs aren't type checked yet!)"); // TODO! true diff --git a/src/script/val_data.rs b/src/script/val_data.rs new file mode 100644 index 0000000..6d91034 --- /dev/null +++ b/src/script/val_data.rs @@ -0,0 +1,143 @@ +use std::{ + fmt::Debug, + sync::{Arc, Mutex}, + thread::JoinHandle, + time::Duration, +}; + +use super::{ + block::RFunction, + val_type::{VSingleType, VType}, +}; + +#[derive(Clone, Debug)] +pub struct VData { + // parents: Vec<()>, + pub data: VDataEnum, +} + +#[derive(Clone, Debug)] +pub enum VDataEnum { + Bool(bool), + Int(isize), + Float(f64), + String(String), + Tuple(Vec), + List(VType, Vec), + Function(RFunction), + Thread(VDataThread, VType), + Reference(Arc>), +} + +impl VData { + pub fn out(&self) -> VType { + VType { + types: vec![self.out_single()], + } + } + pub fn out_single(&self) -> VSingleType { + match &self.data { + VDataEnum::Bool(..) => VSingleType::Bool, + VDataEnum::Int(..) => VSingleType::Int, + VDataEnum::Float(..) => VSingleType::Float, + VDataEnum::String(..) => VSingleType::String, + VDataEnum::Tuple(v) => VSingleType::Tuple(v.iter().map(|v| v.out()).collect()), + VDataEnum::List(t, _) => VSingleType::List(t.clone()), + VDataEnum::Function(f) => VSingleType::Function(f.input_output_map.clone()), + VDataEnum::Thread(_, o) => VSingleType::Thread(o.clone()), + VDataEnum::Reference(r) => r.lock().unwrap().out_single(), + } + } + pub fn get(&self, i: usize) -> Option { + self.data.get(i) + } +} + +impl VDataEnum { + pub fn to(self) -> VData { + VData { data: self } + } +} + +// get() +impl VDataEnum { + pub fn get(&self, i: usize) -> Option { + match self { + Self::Bool(..) + | Self::Int(..) + | Self::Float(..) + | Self::Function(..) + | Self::Thread(..) => None, + Self::String(s) => match s.chars().nth(i) { + // Slow! + Some(ch) => Some(Self::String(format!("{ch}")).to()), + None => None, + }, + Self::Tuple(v) | Self::List(_, v) => v.get(i).cloned(), + Self::Reference(r) => r.lock().unwrap().get(i), + } + } +} +#[derive(Clone)] +pub struct VDataThread(Arc>); +impl VDataThread { + pub fn try_get(&self) -> Option { + match &*self.lock() { + VDataThreadEnum::Running(_) => None, + VDataThreadEnum::Finished(v) => Some(v.clone()), + } + } + pub fn get(&self) -> VData { + let dur = Duration::from_millis(100); + loop { + match &*self.lock() { + VDataThreadEnum::Running(v) => { + while !v.is_finished() { + std::thread::sleep(dur); + } + } + VDataThreadEnum::Finished(v) => return v.clone(), + } + } + } + pub fn lock(&self) -> std::sync::MutexGuard { + let mut mg = self.0.lock().unwrap(); + match &*mg { + VDataThreadEnum::Running(v) => { + if v.is_finished() { + let m = std::mem::replace( + &mut *mg, + VDataThreadEnum::Finished(VData { + data: VDataEnum::Bool(false), + }), + ); + match m { + VDataThreadEnum::Running(v) => { + *mg = VDataThreadEnum::Finished(v.join().unwrap()) + } + _ => unreachable!(), + } + } + } + _ => (), + } + mg + } +} +impl Debug for VDataThread { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &*self.lock() { + VDataThreadEnum::Running(_) => write!(f, "(thread running)"), + VDataThreadEnum::Finished(v) => write!(f, "(thread finished: {v})"), + } + } +} +pub enum VDataThreadEnum { + Running(JoinHandle), + Finished(VData), +} +impl VDataThreadEnum { + pub fn to(self) -> VDataThread { + VDataThread(Arc::new(Mutex::new(self))) + } +} diff --git a/src/script/val_type.rs b/src/script/val_type.rs new file mode 100644 index 0000000..3d14b21 --- /dev/null +++ b/src/script/val_type.rs @@ -0,0 +1,182 @@ +use std::{fmt::Debug, ops::BitOr}; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct VType { + pub types: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum VSingleType { + Bool, + Int, + Float, + String, + Tuple(Vec), + List(VType), + Function(Vec<(Vec, VType)>), + Thread(VType), + Reference(Box), +} + +impl VSingleType { + // None => Cannot get, Some(t) => getting can return t or nothing + pub fn get(&self, i: usize) -> Option { + match self { + Self::Bool | Self::Int | Self::Float | Self::Function(..) | Self::Thread(..) => None, + Self::String => Some(VSingleType::String.into()), + Self::Tuple(t) => t.get(i).cloned(), + Self::List(t) => Some(t.clone()), + Self::Reference(r) => r.get(i), + } + } +} +impl VType { + pub fn get(&self, i: usize) -> Option { + let mut out = VType { types: vec![] }; + for t in &self.types { + out = out | t.get(i)?; // if we can't use *get* on one type, we can't use it at all. + } + Some(out) + } +} + +impl VSingleType { + pub fn get_any(&self) -> Option { + match self { + Self::Bool | Self::Int | Self::Float | Self::Function(..) | Self::Thread(..) => None, + Self::String => Some(VSingleType::String.into()), + Self::Tuple(t) => Some(t.iter().fold(VType { types: vec![] }, |a, b| a | b)), + Self::List(t) => Some(t.clone()), + Self::Reference(r) => r.get_any(), + } + } +} +impl VType { + pub fn get_any(&self) -> Option { + let mut out = VType { types: vec![] }; + for t in &self.types { + out = out | t.get_any()?; // if we can't use *get* on one type, we can't use it at all. + } + Some(out) + } +} + +impl VType { + /// Returns a vec with all types in self that aren't covered by rhs. If the returned vec is empty, self fits in rhs. + pub fn fits_in(&self, rhs: &Self) -> Vec { + let mut no = vec![]; + for t in &self.types { + // if t doesnt fit in any of rhs's types + if !rhs.types.iter().any(|r| t.fits_in(r)) { + no.push(t.clone()) + } + } + no + } + pub fn inner_types(&self) -> VType { + let mut out = VType { types: vec![] }; + for t in &self.types { + for it in t.inner_types() { + out = out | it.to(); + } + } + out + } + pub fn contains(&self, t: &VSingleType) -> bool { + self.types.contains(t) + } +} +impl BitOr for VType { + type Output = Self; + fn bitor(self, rhs: Self) -> Self::Output { + let mut types = self.types; + for t in rhs.types { + if !types.contains(&t) { + types.push(t) + } + } + Self { types } + } +} +impl BitOr<&VType> for VType { + type Output = Self; + fn bitor(self, rhs: &Self) -> Self::Output { + let mut types = self.types; + for t in &rhs.types { + if !types.contains(t) { + types.push(t.clone()) + } + } + Self { types } + } +} + +impl VSingleType { + pub fn to(self) -> VType { + VType { types: vec![self] } + } + pub fn inner_types(&self) -> Vec { + match self { + Self::Tuple(v) => { + let mut types = vec![]; + for it in v { + // the tuple values + for it in &it.types { + // the possible types for each value + if !types.contains(it) { + types.push(it.clone()); + } + } + } + types + } + Self::List(v) => v.types.clone(), + _ => vec![], + } + } + pub fn fits_in(&self, rhs: &Self) -> bool { + match (self, rhs) { + (Self::Bool, Self::Bool) + | (Self::Int, Self::Int) + | (Self::Float, Self::Float) + | (Self::String, Self::String) => true, + (Self::Bool | Self::Int | Self::Float | Self::String, _) => false, + (Self::Tuple(a), Self::Tuple(b)) => { + if a.len() == b.len() { + a.iter().zip(b.iter()).all(|(a, b)| a.fits_in(b).is_empty()) + } else { + false + } + } + (Self::Tuple(_), _) => false, + (Self::List(a), Self::List(b)) => a.fits_in(b).is_empty(), + (Self::List(_), _) => false, + (Self::Function(a), Self::Function(b)) => 'func_out: { + for a in a { + 'search: { + for b in b { + if a.1.fits_in(&b.1).is_empty() + && a.0.iter().zip(b.0.iter()).all(|(a, b)| *a == *b) + { + break 'search; + } + } + break 'func_out false; + } + } + true + } + (Self::Function(..), _) => false, + (Self::Thread(a), Self::Thread(b)) => a.fits_in(b).is_empty(), + (Self::Thread(..), _) => false, + (Self::Reference(r), Self::Reference(b)) => r.fits_in(b), + (Self::Reference(_), _) => false, + } + } +} + +impl Into for VSingleType { + fn into(self) -> VType { + VType { types: vec![self] } + } +}