Skip to content

Commit

Permalink
Merge pull request #725 from ergoplatform/i724-slice-index-out-of-bounds
Browse files Browse the repository at this point in the history
implement Scala version semantics for Coll.slice
  • Loading branch information
greenhat authored Oct 5, 2023
2 parents 9ab86db + 15d8995 commit 22e3958
Showing 1 changed file with 33 additions and 12 deletions.
45 changes: 33 additions & 12 deletions ergotree-interpreter/src/eval/coll_slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ impl Evaluable for Slice {
}?;
let from = from_v.try_extract_into::<i32>()?;
let until = until_v.try_extract_into::<i32>()?;
match input_vec.get(from as usize..until as usize) {
// intersection of the range with collection bounds
// to preserve the Scala version semantics of slice op
// see https://github.com/ergoplatform/sigma-rust/issues/724
let range = from.max(0) as usize..until.min(input_vec.len() as i32) as usize;
match input_vec.get(range) {
Some(slice) => Ok(Value::Coll(CollKind::from_vec(elem_tpe, slice.to_vec())?)),
None => Err(EvalError::Misc(format!(
"Slice: indices {0:?}..{1:?} out of bounds for collection size {2:?}",
from,
until,
input_vec.len()
))),
// Scala version returns empty collection if the range is out of bounds
None => Ok(Value::Coll(CollKind::from_vec(elem_tpe, vec![])?)),
}
}
}
Expand All @@ -42,7 +42,7 @@ mod tests {
use ergotree_ir::types::stype::SType;

use super::*;
use crate::eval::tests::{eval_out_wo_ctx, try_eval_out_wo_ctx};
use crate::eval::tests::eval_out_wo_ctx;

#[test]
fn slice() {
Expand Down Expand Up @@ -74,14 +74,17 @@ mod tests {

#[test]
fn slice_empty_coll() {
// In Scala version the slice with indices out of bounds does not throw
// but returns an intersection or an empty array.
// see https://github.com/ergoplatform/sigma-rust/issues/724
let expr: Expr = Slice::new(
Expr::Const(Vec::<i64>::new().into()),
Expr::Const(1i32.into()),
Expr::Const(3i32.into()),
)
.unwrap()
.into();
assert!(try_eval_out_wo_ctx::<Vec<i64>>(&expr).is_err());
assert_eq!(eval_out_wo_ctx::<Vec<i64>>(&expr), Vec::<i64>::new());
}

#[test]
Expand All @@ -98,26 +101,32 @@ mod tests {

#[test]
fn slice_start_index_greater_than_end_index() {
// In Scala version the slice with indices out of bounds does not throw
// but returns an intersection or an empty array.
// see https://github.com/ergoplatform/sigma-rust/issues/724
let expr: Expr = Slice::new(
Expr::Const(vec![1i64, 2i64, 3i64, 4i64].into()),
Expr::Const(3i32.into()),
Expr::Const(1i32.into()),
)
.unwrap()
.into();
assert!(try_eval_out_wo_ctx::<Vec<i64>>(&expr).is_err());
assert_eq!(eval_out_wo_ctx::<Vec<i64>>(&expr), Vec::<i64>::new());
}

#[test]
fn slice_index_out_of_bounds() {
// In Scala version the slice with indices out of bounds does not throw
// but returns an intersection or an empty array.
// see https://github.com/ergoplatform/sigma-rust/issues/724
let expr: Expr = Slice::new(
Expr::Const(vec![1i64, 2i64, 3i64, 4i64].into()),
Expr::Const((-1i32).into()),
Expr::Const(1i32.into()),
)
.unwrap()
.into();
assert!(try_eval_out_wo_ctx::<Vec<i64>>(&expr).is_err());
assert_eq!(eval_out_wo_ctx::<Vec<i64>>(&expr), vec![1i64]);

let expr: Expr = Slice::new(
Expr::Const(vec![1i64, 2i64, 3i64, 4i64].into()),
Expand All @@ -126,6 +135,18 @@ mod tests {
)
.unwrap()
.into();
assert!(try_eval_out_wo_ctx::<Vec<i64>>(&expr).is_err());
assert_eq!(
eval_out_wo_ctx::<Vec<i64>>(&expr),
vec![1i64, 2i64, 3i64, 4i64]
);

let expr: Expr = Slice::new(
Expr::Const(vec![1i64, 2i64, 3i64, 4i64].into()),
Expr::Const(9i32.into()),
Expr::Const(10i32.into()),
)
.unwrap()
.into();
assert_eq!(eval_out_wo_ctx::<Vec<i64>>(&expr), Vec::<i64>::new());
}
}

0 comments on commit 22e3958

Please sign in to comment.