From ecb3cd4df5fb9410974369b4b8c94db221f8b92c Mon Sep 17 00:00:00 2001 From: Daniel Alley Date: Sun, 22 Sep 2019 19:50:31 -0400 Subject: [PATCH] Fix implementation of range slicing closes #1373 --- vm/src/obj/objrange.rs | 104 ++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 48 deletions(-) diff --git a/vm/src/obj/objrange.rs b/vm/src/obj/objrange.rs index bdb1aa7cc..04f326308 100644 --- a/vm/src/obj/objrange.rs +++ b/vm/src/obj/objrange.rs @@ -320,62 +320,70 @@ impl PyRange { fn getitem(&self, subscript: RangeIndex, vm: &VirtualMachine) -> PyResult { match subscript { RangeIndex::Slice(slice) => { - let start = self.start.as_bigint(); - let stop = self.stop.as_bigint(); - let step = self.step.as_bigint(); + let range_start = self.start.as_bigint(); + let range_step = self.step.as_bigint(); + let _tmp_len = self.length(); + let range_length = _tmp_len.as_bigint(); - let new_start = if let Some(int) = slice.start_index(vm)? { - let int = ∫ - if let Some(i) = self.get(int) { - PyInt::new(i).into_ref(vm) - } else if start < stop { - if stop <= int { - self.stop.clone() - } else { - self.start.clone() - } - } else if int < stop { - self.stop.clone() - } else { - self.start.clone() - } - } else { - self.start.clone() - }; - - let new_end = if let Some(int) = slice.stop_index(vm)? { - let int = ∫ - if let Some(i) = self.get(int) { - PyInt::new(i).into_ref(vm) - } else if start < stop { - if int < start { - self.start.clone() - } else { - self.stop.clone() - } - } else if start < int { - self.start.clone() - } else { - self.stop.clone() - } - } else { - self.stop.clone() - }; - - let new_step = if let Some(int) = slice.step_index(vm)? { - if int.is_zero() { + let substep = if let Some(slice_step) = slice.step_index(vm)? { + if slice_step.is_zero() { return Err(vm.new_value_error("slice step cannot be zero".to_string())); + } + slice_step + } else { + BigInt::one() + }; + + let negative_step = substep.is_negative(); + let lower_bound = if negative_step { -BigInt::one() } else { BigInt::zero() }; + let upper_bound = if negative_step { &lower_bound + range_length } else { range_length.clone() }; + + let substart = if let Some(slice_start) = slice.start_index(vm)? { + if slice_start.is_negative() { + let tmp = slice_start + range_length; + if tmp < lower_bound { + lower_bound.clone() + } else { + tmp.clone() + } } else { - PyInt::new(int * self.step.as_bigint()).into_ref(vm) + if slice_start > upper_bound { + upper_bound.clone() + } else { + slice_start.clone() + } } } else { - self.step.clone() + if negative_step { upper_bound.clone() } else { lower_bound.clone() } }; + let substop = if let Some(slice_stop) = slice.stop_index(vm)? { + if slice_stop.is_negative() { + let tmp = slice_stop + range_length; + if tmp < lower_bound { + lower_bound.clone() + } else { + tmp.clone() + } + } else { + if slice_stop > upper_bound { + upper_bound.clone() + } else { + slice_stop.clone() + } + } + } else { + if negative_step { lower_bound.clone() } else { upper_bound.clone() } + }; + + let step = range_step * &substep; + let start = range_start + (&substart * range_step); + let stop = range_start + (&substop * range_step); + Ok(PyRange { - start: new_start, - stop: new_end, - step: new_step, + start: PyInt::new(start).into_ref(vm), + stop: PyInt::new(stop).into_ref(vm), + step: PyInt::new(step).into_ref(vm), } .into_ref(vm) .into_object())