From 65fdc87c019d028468820db2b031c8e7fef3ffda Mon Sep 17 00:00:00 2001 From: Dummi26 Date: Sat, 15 Apr 2023 14:41:52 +0200 Subject: [PATCH] added more accurate type-checking to some of the builtins --- mers/src/script/builtins.rs | 76 ++++++++++++++++++++++++++++++++++--- mers/src/script/val_type.rs | 24 ++++++++++++ 2 files changed, 95 insertions(+), 5 deletions(-) diff --git a/mers/src/script/builtins.rs b/mers/src/script/builtins.rs index 4472d28..909ac11 100755 --- a/mers/src/script/builtins.rs +++ b/mers/src/script/builtins.rs @@ -332,8 +332,13 @@ impl BuiltinFunction { if input.len() == 2 { // check if the element that should be inserted fits in the list's inner type let (vec, el) = (&input[0], &input[1]); - if let Some(t) = vec.get_any() { - el.fits_in(&t).is_empty() + // if vec.is_reference().is_some_and(|v| v) { // unstable + if let Some(true) = vec.is_reference() { + if let Some(t) = vec.get_any() { + el.fits_in(&t).is_empty() + } else { + false + } } else { false } @@ -344,8 +349,50 @@ impl BuiltinFunction { Self::Insert => { if input.len() == 3 { let (vec, el) = (&input[0], &input[1]); - if let Some(t) = vec.get_any() { - el.fits_in(&t).is_empty() + if let Some(true) = vec.is_reference() { + if let Some(t) = vec.get_any() { + el.fits_in(&t).is_empty() + } else { + false + } + } else { + false + } + } else { + false + } + } + Self::Pop => { + if input.len() == 1 { + let vec = &input[0]; + if let Some(true) = vec.is_reference() { + // TODO! this also returns true for tuples. what should we do for tuples? should pop return (first_val rest_of_tuple) and not take a reference? + if let Some(_) = vec.get_any() { + true + } else { + false + } + } else { + false + } + } else { + false + } + } + Self::Remove => { + if input.len() == 2 { + let (vec, index) = (&input[0], &input[1]); + if let Some(true) = vec.is_reference() { + // TODO! same issue as in pop + if let Some(_) = vec.get_any() { + if index.fits_in(&VSingleType::Int.to()).is_empty() { + true + } else { + false + } + } else { + false + } } else { false } @@ -354,7 +401,26 @@ impl BuiltinFunction { } } // TODO! finish this - Self::Pop | Self::Remove | Self::Get | Self::Len | Self::Substring => true, + Self::Get | Self::Len => true, + Self::Substring => { + if input.len() >= 2 && input.len() <= 3 { + let (s, start) = (&input[0], &input[1]); + let index_type = VSingleType::Int.to(); + if s.fits_in(&VSingleType::String.to()).is_empty() + && start.fits_in(&index_type).is_empty() + { + if let Some(end) = input.get(2) { + end.fits_in(&index_type).is_empty() + } else { + true + } + } else { + false + } + } else { + false + } + } Self::Contains | Self::StartsWith | Self::EndsWith | Self::Regex => { input.len() == 2 && input diff --git a/mers/src/script/val_type.rs b/mers/src/script/val_type.rs index b9bc27d..16c209e 100755 --- a/mers/src/script/val_type.rs +++ b/mers/src/script/val_type.rs @@ -41,6 +41,24 @@ impl VType { } Some(out) } + // returns Some(true) or Some(false) if all types are references or not references. If it is mixed or types is empty, returns None. + pub fn is_reference(&self) -> Option { + let mut noref = false; + let mut reference = false; + for t in &self.types { + if t.is_reference() { + reference = true; + } else { + noref = true; + } + } + if noref != reference { + Some(reference) + } else { + // either empty (false == false) or mixed (true == true) + None + } + } } impl VSingleType { @@ -55,6 +73,12 @@ impl VSingleType { Self::EnumVariantS(..) => unreachable!(), } } + pub fn is_reference(&self) -> bool { + match self { + Self::Reference(_) => true, + _ => false, + } + } } impl VType { pub fn get_any(&self) -> Option {