diff --git a/mers/src/lang/builtins.rs b/mers/src/lang/builtins.rs index dad7316..0d5cbc7 100755 --- a/mers/src/lang/builtins.rs +++ b/mers/src/lang/builtins.rs @@ -381,7 +381,7 @@ impl BuiltinFunction { if let Some(true) = vec.is_reference() { if let Some(t) = vec.get_any(info) { el.fits_in( - &t.dereference() + &t.dereference(info) .expect("running get() on &[ ...] should give a reference"), info, ) @@ -402,7 +402,7 @@ impl BuiltinFunction { if let Some(true) = vec.is_reference() { if let Some(t) = vec.get_any(info) { el.fits_in( - &t.dereference() + &t.dereference(info) .expect("running get() on a &[ ...] should give a reference."), info, ) @@ -519,10 +519,10 @@ impl BuiltinFunction { match t { VSingleType::Tuple(v) => { if !v.is_empty() { - out = out | &v[0]; + out.add_typesr(&v[0], info) } } - v => out = out | v.clone().to(), + v => out.add_typer(v, info), } } out @@ -532,15 +532,15 @@ impl BuiltinFunction { for t in &input[0].types { match t { VSingleType::EnumVariant(..) | VSingleType::EnumVariantS(..) => (), - t => out = out | t.clone().to(), + t => out.add_typer(t, info), } } out } - Self::NoEnum => input[0].clone().noenum(), - Self::Matches => input[0].matches().1, + Self::NoEnum => input[0].clone().noenum(info), + Self::Matches => input[0].matches(info).1, Self::Clone => input[0] - .dereference() + .dereference(info) .expect("type is a reference, so it can be dereferenced"), // [] Self::Print | Self::Println | Self::Debug | Self::Sleep => VType { @@ -562,25 +562,25 @@ impl BuiltinFunction { for func in &funcs.types { if let VSingleType::Function(io) = func { let mut empty = true; - let fn_out = io.iter().fold(VType::empty(), |t, (fn_in, fn_out)| { - if fn_in.len() == (input.len() - 1) - && fn_in - .iter() - .zip(input.iter().skip(1)) - .all(|(fn_in, arg)| arg.fits_in(fn_in, info).is_empty()) - { - empty = false; - t | fn_out.clone() - } else { + let fn_out = + io.iter().fold(VType::empty(), |mut t, (fn_in, fn_out)| { + if fn_in.len() == (input.len() - 1) + && fn_in + .iter() + .zip(input.iter().skip(1)) + .all(|(fn_in, arg)| arg.fits_in(fn_in, info).is_empty()) + { + empty = false; + t.add_typesr(fn_out, info); + } t - } - }); + }); if empty { unreachable!( "fn args are incorrect for builtin run() or thread()!" ); } - out = out | fn_out; + out.add_types(fn_out, info); } else { unreachable!("run called, first arg not a function") } @@ -599,7 +599,7 @@ impl BuiltinFunction { let mut out = VType { types: vec![] }; for v in &v.types { if let VSingleType::Thread(v) = v { - out = out | v; + out.add_typesr(v, info); } else { unreachable!("await called with non-thread arg") } @@ -611,7 +611,7 @@ impl BuiltinFunction { } Self::Pop => { if let Some(v) = input.first() { - if let Some(v) = v.dereference() { + if let Some(v) = v.dereference(info) { VType { types: vec![ VSingleType::Tuple(vec![]), @@ -629,14 +629,14 @@ impl BuiltinFunction { } Self::Remove => { if input[1].fits_in(&VSingleType::Int.to(), info).is_empty() { - if let Some(v) = input[0].dereference() { + if let Some(v) = input[0].dereference(info) { VType { types: vec![ VSingleType::Tuple(vec![]), VSingleType::Tuple(vec![v .get_any(info) .expect("cannot use get on this type") - .dereference() + .dereference(info) .expect( "running get_any() on &[ ...] should give a reference...", )]), @@ -745,7 +745,7 @@ impl BuiltinFunction { (false, false) => (), } } - let o = match ( + let mut o = match ( ( input[0].contains(&VSingleType::Int, info), input[0].contains(&VSingleType::Float, info), @@ -763,10 +763,9 @@ impl BuiltinFunction { _ => VSingleType::Float.to(), }; if might_be_string { - o | VSingleType::String.to() - } else { - o + o.add_type(VSingleType::String, info); } + o } else { unreachable!("called add/sub/mul/div/mod/pow with args != 2") } diff --git a/mers/src/lang/code_runnable.rs b/mers/src/lang/code_runnable.rs index 5500e0c..68abdfd 100755 --- a/mers/src/lang/code_runnable.rs +++ b/mers/src/lang/code_runnable.rs @@ -83,7 +83,7 @@ impl RFunction { let out = self .out_map .iter() - .fold(VType::empty(), |t, (fn_in, fn_out)| { + .fold(VType::empty(), |mut t, (fn_in, fn_out)| { if fn_in.len() == (input_types.len()) && fn_in .iter() @@ -91,10 +91,9 @@ impl RFunction { .all(|(fn_in, arg)| arg.fits_in(fn_in, info).is_empty()) { empty = false; - t | fn_out.clone() - } else { - t + t.add_typesr(fn_out, info); } + t }); if empty { None @@ -102,9 +101,12 @@ impl RFunction { Some(out) } } - pub fn out_all(&self, _info: &GlobalScriptInfo) -> VType { + pub fn out_all(&self, info: &GlobalScriptInfo) -> VType { // self.statement.out(info) - self.out_map.iter().fold(VType::empty(), |t, (_, v)| t | v) + self.out_map.iter().fold(VType::empty(), |mut t, (_, v)| { + t.add_typesr(v, info); + t + }) } pub fn in_types(&self) -> &Vec { &self.input_types @@ -155,7 +157,7 @@ impl RStatement { } let mut o = self.statement.out(info); for _ in 0..self.derefs { - o = o.dereference().expect("can't dereference (out())"); + o = o.dereference(info).expect("can't dereference (out())"); } o } @@ -177,7 +179,7 @@ impl RStatementEnum { let mut out = VType { types: vec![] }; for v in v { let val = v.run(info); - out = out | val.out(); + out.add_types(val.out(), &info); w.push(val); } VDataEnum::List(out, w).to() @@ -331,7 +333,7 @@ impl RStatementEnum { Self::List(v) => VSingleType::List({ let mut types = VType { types: vec![] }; for t in v { - types = types | t.out(info); + types.add_types(t.out(info), info); } types }) @@ -358,14 +360,20 @@ impl RStatementEnum { Self::LibFunctionCall(.., out) => out.clone(), Self::Block(b) => b.out(info), Self::If(_, a, b) => { + let mut out = a.out(info); if let Some(b) = b { - a.out(info) | b.out(info) + out.add_types(b.out(info), info); } else { - a.out(info) | VSingleType::Tuple(vec![]).to() + out.add_type(VSingleType::Tuple(vec![]), info); } + out + } + Self::Loop(c) => c.out(info).matches(info).1, + Self::For(_, _, b) => { + let mut out = b.out(info).matches(info).1; + out.add_type(VSingleType::Tuple(vec![]), info); + out } - Self::Loop(c) => c.out(info).matches().1, - Self::For(_, _, b) => VSingleType::Tuple(vec![]).to() | b.out(info).matches().1, Self::BuiltinFunctionCall(f, args) => { f.returns(args.iter().map(|rs| rs.out(info)).collect(), info) } @@ -379,7 +387,7 @@ impl RStatementEnum { }; for switch_on in switch_on { for (_on_type, _assign_to, case) in cases.iter() { - out = out | case.out(info); + out.add_types(case.out(info), info); } } out @@ -388,14 +396,14 @@ impl RStatementEnum { let mut out = VType::empty(); let mut can_fail_to_match = true; for (condition, _assign_to, action) in cases { - out = out | action.out(info); - if !condition.out(info).matches().0 { + out.add_types(action.out(info), info); + if !condition.out(info).matches(info).0 { can_fail_to_match = false; break; } } if can_fail_to_match { - out = out | VSingleType::Tuple(vec![]).to() + out.add_type(VSingleType::Tuple(vec![]), info); } out } diff --git a/mers/src/lang/to_runnable.rs b/mers/src/lang/to_runnable.rs index d0f7d73..a67810b 100755 --- a/mers/src/lang/to_runnable.rs +++ b/mers/src/lang/to_runnable.rs @@ -508,19 +508,21 @@ fn statement_adv( let lib = &ginfo.libs[*libid]; let libfn = &lib.registered_fns[*fnid]; let mut empty = true; - let fn_out = libfn.1.iter().fold(VType::empty(), |t, (fn_in, fn_out)| { - if fn_in.len() == arg_types.len() - && fn_in - .iter() - .zip(arg_types.iter()) - .all(|(fn_in, arg)| arg.fits_in(fn_in, ginfo).is_empty()) - { - empty = false; - t | fn_out.clone() - } else { - t - } - }); + let fn_out = + libfn + .1 + .iter() + .fold(VType::empty(), |mut t, (fn_in, fn_out)| { + if fn_in.len() == arg_types.len() + && fn_in.iter().zip(arg_types.iter()).all(|(fn_in, arg)| { + arg.fits_in(fn_in, ginfo).is_empty() + }) + { + empty = false; + t.add_typesr(fn_out, ginfo); + } + t + }); if empty { return Err(ToRunnableError::WrongArgsForLibFunction( v.to_owned(), @@ -579,7 +581,7 @@ fn statement_adv( SStatementEnum::For(v, c, b) => { let mut linfo = linfo.clone(); let container = statement(&c, ginfo, &mut linfo)?; - let inner = container.out(ginfo).inner_types(); + let inner = container.out(ginfo).inner_types(ginfo); if inner.types.is_empty() { return Err(ToRunnableError::ForLoopContainerHasNoInnerTypes); } @@ -601,7 +603,7 @@ fn statement_adv( stypes(&mut v, ginfo)?; v }; - covered_types = covered_types | &case_type; + covered_types.add_typesr(&case_type, ginfo); ncases.push(( case_type.clone(), statement_adv( @@ -633,7 +635,7 @@ fn statement_adv( for (condition, assign_to, action) in cases.iter() { let mut linfo = linfo.clone(); let condition = statement(condition, ginfo, &mut linfo)?; - let (can_fail, matches) = condition.out(ginfo).matches(); + let (can_fail, matches) = condition.out(ginfo).matches(ginfo); let assign_to = statement_adv( assign_to, ginfo, @@ -647,7 +649,7 @@ fn statement_adv( } } if may_not_match { - out_type = out_type | VSingleType::Tuple(vec![]).to(); + out_type.add_type(VSingleType::Tuple(vec![]), ginfo); } RStatementEnum::Match(ncases).to() diff --git a/mers/src/lang/val_data.rs b/mers/src/lang/val_data.rs index 0c5d79d..4d171cb 100755 --- a/mers/src/lang/val_data.rs +++ b/mers/src/lang/val_data.rs @@ -417,13 +417,13 @@ impl VSingleType { } impl VType { /// returns (can_fail_to_match, matches_as) - pub fn matches(&self) -> (bool, VType) { + pub fn matches(&self, info: &GlobalScriptInfo) -> (bool, VType) { let mut can_fail = false; let mut matches_as = VType { types: vec![] }; for t in self.types.iter() { let (f, t) = t.matches(); can_fail |= f; - matches_as = matches_as | t; + matches_as.add_types(t, info); } (can_fail, matches_as) } diff --git a/mers/src/lang/val_type.rs b/mers/src/lang/val_type.rs index 035afbf..51f21b9 100755 --- a/mers/src/lang/val_type.rs +++ b/mers/src/lang/val_type.rs @@ -14,12 +14,12 @@ use super::{ use super::global_info::LogMsg; -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct VType { pub types: Vec, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] pub enum VSingleType { Any, Bool, @@ -128,21 +128,21 @@ impl VType { pub fn get(&self, i: usize, info: &GlobalScriptInfo) -> Option { let mut out = VType { types: vec![] }; for t in &self.types { - out = out | t.get(i, info)?; // if we can't use *get* on one type, we can't use it at all. + out.add_types(t.get(i, info)?, info); // if we can't use *get* on one type, we can't use it at all. } Some(out) } pub fn get_always(&self, i: usize, info: &GlobalScriptInfo) -> Option { let mut out = VType { types: vec![] }; for t in &self.types { - out = out | t.get_always(i, info)?; // if we can't use *get* on one type, we can't use it at all. + out.add_types(t.get_always(i, info)?, info); // if we can't use *get* on one type, we can't use it at all. } Some(out) } pub fn get_always_ref(&self, i: usize, info: &GlobalScriptInfo) -> Option { let mut out = VType { types: vec![] }; for t in &self.types { - out = out | t.get_always_ref(i, info)?; // if we can't use *get* on one type, we can't use it at all. + out.add_types(t.get_always_ref(i, info)?, info); // if we can't use *get* on one type, we can't use it at all. } Some(out) } @@ -165,10 +165,10 @@ impl VType { } } /// returns Some(t) where t is the type you get from dereferencing self or None if self contains even a single type that cannot be dereferenced. - pub fn dereference(&self) -> Option { + pub fn dereference(&self, info: &GlobalScriptInfo) -> Option { let mut out = Self::empty(); for t in self.types.iter() { - out = out | t.deref()?.to(); + out.add_type(t.deref()?, info); } Some(out) } @@ -194,7 +194,10 @@ impl VSingleType { | 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::Tuple(t) => Some(t.iter().fold(VType::empty(), |mut a, b| { + a.add_typesr(b, info); + a + })), Self::List(t) => Some(t.clone()), Self::Reference(r) => r.get_any_ref(info), Self::EnumVariant(_, t) => t.get_any(info), @@ -212,10 +215,10 @@ impl VSingleType { | 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.reference()), - ), + Self::Tuple(t) => Some(t.iter().fold(VType::empty(), |mut a, b| { + a.add_types(b.reference(), info); + a + })), Self::List(t) => Some(t.reference()), // TODO: idk if this is right... Self::Reference(r) => r.get_any_ref(info), @@ -243,14 +246,14 @@ impl VType { pub fn get_any(&self, info: &GlobalScriptInfo) -> Option { let mut out = VType { types: vec![] }; for t in &self.types { - out = out | t.get_any(info)?; // if we can't use *get* on one type, we can't use it at all. + out.add_types(t.get_any(info)?, info); // if we can't use *get* on one type, we can't use it at all. } Some(out) } pub fn get_any_ref(&self, info: &GlobalScriptInfo) -> Option { let mut out = VType { types: vec![] }; for t in &self.types { - out = out | t.get_any_ref(info)?; // if we can't use *get* on one type, we can't use it at all. + out.add_types(t.get_any_ref(info)?, info); // if we can't use *get* on one type, we can't use it at all. } Some(out) } @@ -272,12 +275,10 @@ impl VType { } no } - pub fn inner_types(&self) -> VType { + pub fn inner_types(&self, info: &GlobalScriptInfo) -> VType { let mut out = VType { types: vec![] }; for t in &self.types { - for it in t.inner_types() { - out = out | it.to(); - } + out.add_types(t.inner_types(info), info); } out } @@ -289,36 +290,45 @@ impl VType { pub fn contains(&self, t: &VSingleType, info: &GlobalScriptInfo) -> bool { t.fits_in_type(self, info) } - pub fn noenum(self) -> Self { + pub fn noenum(self, info: &GlobalScriptInfo) -> Self { let mut o = Self { types: vec![] }; for t in self.types { - o = o | t.noenum(); + o.add_types(t.noenum(), info); } o } } -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 VType { + pub fn eq(&self, rhs: &Self, info: &GlobalScriptInfo) -> bool { + self.fits_in(rhs, info).is_empty() && rhs.fits_in(self, info).is_empty() } } -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()) - } +impl VSingleType { + pub fn eq(&self, rhs: &Self, info: &GlobalScriptInfo) -> bool { + self.fits_in(rhs, info) && rhs.fits_in(self, info) + } +} +impl VType { + pub fn add_types(&mut self, new: Self, info: &GlobalScriptInfo) { + for t in new.types { + self.add_type(t, info) + } + } + pub fn add_type(&mut self, new: VSingleType, info: &GlobalScriptInfo) { + if !self.contains(&new, info) { + self.types.push(new) + } + } + pub fn add_typesr(&mut self, new: &Self, info: &GlobalScriptInfo) { + for t in &new.types { + self.add_typer(t, info) + } + } + pub fn add_typer(&mut self, new: &VSingleType, info: &GlobalScriptInfo) { + if !self.contains(new, info) { + self.types.push(new.clone()) } - Self { types } } } @@ -326,65 +336,49 @@ impl VSingleType { pub fn to(self) -> VType { VType { types: vec![self] } } - pub fn inner_types(&self) -> Vec { + pub fn inner_types(&self, info: &GlobalScriptInfo) -> VType { match self { Self::Tuple(v) => { - let mut types = vec![]; + let mut out = VType::empty(); 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()); - } - } + out.add_typesr(it, info); } - types + out } - Self::List(v) => v.types.clone(), + Self::List(v) => v.clone(), // NOTE: to make ints work in for loops - Self::Int => vec![Self::Int], + Self::Int => Self::Int.to(), // for iterators in for loops: the match of the function's returned value make up the inner type Self::Function(f) => { // function that takes no inputs if let Some(out) = f.iter().find_map(|(args, out)| { if args.is_empty() { - Some(out.clone().inner_types()) + Some(out.clone()) } else { None } }) { - out.types + out } else { - vec![] + VType::empty() } } - Self::Reference(r) => r.inner_types_ref(), - _ => vec![], + Self::Reference(r) => r.inner_types_ref(info), + _ => VType::empty(), } } - pub fn inner_types_ref(&self) -> Vec { + pub fn inner_types_ref(&self, info: &GlobalScriptInfo) -> VType { match self { Self::Tuple(v) => { - let mut types = vec![]; + let mut out = VType::empty(); for it in v { - // the tuple values - for it in &it.types { - // the possible types for each value - if !types.contains(it) { - types.push(Self::Reference(Box::new(it.clone()))); - } - } + out.add_types(it.reference(), info); } - types + out } - Self::List(v) => v - .types - .iter() - .map(|v| Self::Reference(Box::new(v.clone()))) - .collect(), - Self::Reference(r) => r.inner_types_ref(), - _ => vec![], + Self::List(v) => v.reference(), + Self::Reference(r) => r.inner_types_ref(info), + _ => VType::empty(), } } pub fn noenum(self) -> VType { diff --git a/mers/src/lib.rs b/mers/src/lib.rs index f27e562..2bd31e4 100755 --- a/mers/src/lib.rs +++ b/mers/src/lib.rs @@ -5,7 +5,7 @@ mod lang; mod libs; mod parsing; -pub use lang::{val_data::*, val_type::*}; +pub use lang::{global_info::GlobalScriptInfo, val_data::*, val_type::*}; pub use libs::{ comms::{ByteData, ByteDataA, Message, RespondableMessage}, inlib::MyLib, @@ -14,7 +14,10 @@ pub use parsing::*; pub mod prelude { pub use super::{ - lang::{val_data::*, val_type::*}, + lang::{ + val_data::{VData, VDataEnum}, + val_type::{VSingleType, VType}, + }, MyLib, RespondableMessage, }; } diff --git a/mers/src/libs/comms.rs b/mers/src/libs/comms.rs index 4e9856c..2a576ce 100644 --- a/mers/src/libs/comms.rs +++ b/mers/src/libs/comms.rs @@ -495,8 +495,9 @@ impl ByteDataA for VDataEnum { vec.push(b't'); c.as_byte_data(vec); } - Self::List(_, data) => { + Self::List(t, data) => { vec.push(b'l'); + t.as_byte_data(vec); data.as_byte_data(vec); } // TODO? @@ -525,13 +526,10 @@ impl ByteData for VDataEnum { b'f' => Self::Float(ByteData::from_byte_data(data)?), b'"' => Self::String(ByteData::from_byte_data(data)?), b't' => Self::Tuple(ByteData::from_byte_data(data)?), - b'l' => { - let entries: Vec = ByteData::from_byte_data(data)?; - Self::List( - entries.iter().fold(VType::empty(), |t, v| t | v.out()), - entries, - ) - } + b'l' => Self::List( + ByteData::from_byte_data(data)?, + ByteData::from_byte_data(data)?, + ), b'E' => Self::EnumVariant( ByteData::from_byte_data(data)?, Box::new(ByteData::from_byte_data(data)?), diff --git a/mers/tests/lib_comms.rs b/mers/tests/lib_comms.rs index d2f1fe3..0b04fd2 100644 --- a/mers/tests/lib_comms.rs +++ b/mers/tests/lib_comms.rs @@ -1,6 +1,6 @@ use std::io::Cursor; -use mers_libs::prelude::*; +use mers_libs::{prelude::*, GlobalScriptInfo}; use mers_libs::{ByteData, ByteDataA}; #[test] @@ -14,9 +14,10 @@ fn list_type() { ); let a = VSingleType::List(VSingleType::Int.to()).to(); - assert_eq!( - VType::from_byte_data(&mut Cursor::new(a.as_byte_data_vec())).unwrap(), - a + assert!( + VType::from_byte_data(&mut Cursor::new(a.as_byte_data_vec())) + .unwrap() + .eq(&a, &GlobalScriptInfo::default()), ); let a = VSingleType::Tuple(vec![ @@ -27,8 +28,9 @@ fn list_type() { VSingleType::EnumVariant(12, VSingleType::Float.to()).to(), ]) .to(); - assert_eq!( - VType::from_byte_data(&mut Cursor::new(a.as_byte_data_vec())).unwrap(), - a + assert!( + VType::from_byte_data(&mut Cursor::new(a.as_byte_data_vec())) + .unwrap() + .eq(&a, &GlobalScriptInfo::default()) ); }