git.delta.rocks / jrsonnet / refs/commits / 4c008687f967

difftreelog

perf lazy slice

Yaroslav Bolyukin2022-04-20parent: #9c0fa01.patch.diff
in: master

5 files changed

modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs
@@ -43,33 +43,45 @@
 
 pub fn std_slice(
 	indexable: IndexableVal,
-	index: Option<usize>,
-	end: Option<usize>,
-	step: Option<usize>,
+	index: Option<BoundedUsize<0, { i32::MAX as usize }>>,
+	end: Option<BoundedUsize<0, { i32::MAX as usize }>>,
+	step: Option<BoundedUsize<1, { i32::MAX as usize }>>,
 ) -> Result<Val> {
-	let index = index.unwrap_or(0);
-	let end = end.unwrap_or_else(|| match &indexable {
-		IndexableVal::Str(_) => usize::MAX,
-		IndexableVal::Arr(v) => v.len(),
-	});
-	let step = step.unwrap_or(1);
 	match &indexable {
-		IndexableVal::Str(s) => Ok(Val::Str(
+		IndexableVal::Str(s) => {
+			let index = index.as_deref().copied().unwrap_or(0);
+			let end = end.as_deref().copied().unwrap_or(usize::MAX);
+			let step = step.as_deref().copied().unwrap_or(1);
+
+			if index >= end {
+				return Ok(Val::Str("".into()));
+			}
+
+			Ok(Val::Str(
 			(s.chars()
 				.skip(index)
 				.take(end - index)
 				.step_by(step)
 				.collect::<String>())
 			.into(),
-		)),
-		IndexableVal::Arr(arr) => Ok(Val::Arr(
-			(arr.iter()
-				.skip(index)
-				.take(end - index)
-				.step_by(step)
-				.collect::<Result<Vec<Val>>>()?)
-			.into(),
-		)),
+			))
+		}
+		IndexableVal::Arr(arr) => {
+			let index = index.as_deref().copied().unwrap_or(0);
+			let end = end.as_deref().copied().unwrap_or(usize::MAX).min(arr.len());
+			let step = step.as_deref().copied().unwrap_or(1);
+
+			if index >= end {
+				return Ok(Val::Arr(ArrValue::new_eager()));
+			}
+
+			Ok(Val::Arr(ArrValue::Slice(Box::new(Slice {
+				inner: arr.clone(),
+				from: index as u32,
+				to: end as u32,
+				step: step as u32,
+			}))))
+		}
 	}
 }
 
@@ -221,9 +233,9 @@
 #[jrsonnet_macros::builtin]
 fn builtin_slice(
 	indexable: IndexableVal,
-	index: Option<usize>,
-	end: Option<usize>,
-	step: Option<usize>,
+	index: Option<BoundedUsize<0, { i32::MAX as usize }>>,
+	end: Option<BoundedUsize<0, { i32::MAX as usize }>>,
+	step: Option<BoundedUsize<1, { i32::MAX as usize }>>,
 ) -> Result<Any> {
 	std_slice(indexable, index, end, step).map(Any)
 }
modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/error.rs
+++ b/crates/jrsonnet-evaluator/src/error.rs
@@ -191,3 +191,10 @@
 		return Err($e.into())
 	};
 }
+
+#[macro_export]
+macro_rules! throw_runtime {
+	($($tt:tt)*) => {
+		return Err($crate::error::Error::RuntimeError(format!($($tt)*).into()).into())
+	};
+}
modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -665,23 +665,28 @@
 		}
 		Slice(value, desc) => {
 			let indexable = evaluate(context.clone(), value)?;
+			let loc = CallLocation::new(loc);
 
-			fn parse_num(
+			fn parse_idx<const MIN: usize>(
+				loc: CallLocation,
 				context: &Context,
-				expr: Option<&LocExpr>,
+				expr: &Option<LocExpr>,
 				desc: &'static str,
-			) -> Result<Option<usize>> {
-				Ok(match expr {
-					Some(s) => evaluate(context.clone(), s)?
-						.try_cast_nullable_num(desc)?
-						.map(|v| v as usize),
-					None => None,
-				})
+			) -> Result<Option<BoundedUsize<MIN, { i32::MAX as usize }>>> {
+				if let Some(value) = expr {
+					Ok(Some(push_frame(
+						loc,
+						|| format!("slice {}", desc),
+						|| Ok(evaluate(context.clone(), value)?.try_into()?),
+					)?))
+				} else {
+					Ok(None)
+				}
 			}
 
-			let start = parse_num(&context, desc.start.as_ref(), "start")?;
-			let end = parse_num(&context, desc.end.as_ref(), "end")?;
-			let step = parse_num(&context, desc.step.as_ref(), "step")?;
+			let start = parse_idx(loc, &context, &desc.start, "start")?;
+			let end = parse_idx(loc, &context, &desc.end, "end")?;
+			let step = parse_idx(loc, &context, &desc.step, "step")?;
 
 			std_slice(indexable.into_indexable()?, start, end, step)?
 		}
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/typed/conversions.rs
1use std::{2	convert::{TryFrom, TryInto},3	rc::Rc,4};56use gcmodule::Cc;7use jrsonnet_interner::IStr;8pub use jrsonnet_macros::Typed;9use jrsonnet_types::{ComplexValType, ValType};1011use crate::{12	error::{Error::*, LocError, Result},13	throw,14	typed::CheckType,15	ArrValue, FuncDesc, FuncVal, IndexableVal, ObjValue, ObjValueBuilder, Val,16};1718pub trait TypedObj: Typed {19	fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>;20	fn parse(obj: &ObjValue) -> Result<Self>;21	fn into_object(self) -> Result<ObjValue> {22		let mut builder = ObjValueBuilder::new();23		self.serialize(&mut builder)?;24		Ok(builder.build())25	}26}2728pub trait Typed: TryFrom<Val, Error = LocError> + TryInto<Val, Error = LocError> {29	const TYPE: &'static ComplexValType;30}3132macro_rules! impl_int {33	($($ty:ty)*) => {$(34		impl Typed for $ty {35			const TYPE: &'static ComplexValType =36				&ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));37		}38		impl TryFrom<Val> for $ty {39			type Error = LocError;4041			fn try_from(value: Val) -> Result<Self> {42				<Self as Typed>::TYPE.check(&value)?;43				match value {44					Val::Num(n) => {45						if n.trunc() != n {46							throw!(RuntimeError(47								format!(48									"cannot convert number with fractional part to {}",49									stringify!($ty)50								)51								.into()52							))53						}54						Ok(n as Self)55					}56					_ => unreachable!(),57				}58			}59		}60		impl TryFrom<$ty> for Val {61			type Error = LocError;6263			fn try_from(value: $ty) -> Result<Self> {64				Ok(Self::Num(value as f64))65			}66		}67	)*};68}6970impl_int!(i8 u8 i16 u16 i32 u32);7172impl Typed for f64 {73	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);74}75impl TryFrom<Val> for f64 {76	type Error = LocError;7778	fn try_from(value: Val) -> Result<Self> {79		<Self as Typed>::TYPE.check(&value)?;80		match value {81			Val::Num(n) => Ok(n),82			_ => unreachable!(),83		}84	}85}86impl TryFrom<f64> for Val {87	type Error = LocError;8889	fn try_from(value: f64) -> Result<Self> {90		Ok(Self::Num(value))91	}92}9394pub struct PositiveF64(pub f64);95impl Typed for PositiveF64 {96	const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);97}98impl TryFrom<Val> for PositiveF64 {99	type Error = LocError;100101	fn try_from(value: Val) -> Result<Self> {102		<Self as Typed>::TYPE.check(&value)?;103		match value {104			Val::Num(n) => Ok(Self(n)),105			_ => unreachable!(),106		}107	}108}109impl TryFrom<PositiveF64> for Val {110	type Error = LocError;111112	fn try_from(value: PositiveF64) -> Result<Self> {113		Ok(Self::Num(value.0))114	}115}116117impl Typed for usize {118	// It is possible to store 54 bits of precision in f64, but leaving u32::MAX here for compatibility119	const TYPE: &'static ComplexValType =120		&ComplexValType::BoundedNumber(Some(0.0), Some(4294967295.0));121}122impl TryFrom<Val> for usize {123	type Error = LocError;124125	fn try_from(value: Val) -> Result<Self> {126		<Self as Typed>::TYPE.check(&value)?;127		match value {128			Val::Num(n) => {129				if n.trunc() != n {130					throw!(RuntimeError(131						"cannot convert number with fractional part to usize".into()132					))133				}134				Ok(n as Self)135			}136			_ => unreachable!(),137		}138	}139}140impl TryFrom<usize> for Val {141	type Error = LocError;142143	fn try_from(value: usize) -> Result<Self> {144		if value > u32::MAX as usize {145			throw!(RuntimeError("number is too large".into()))146		}147		Ok(Self::Num(value as f64))148	}149}150151impl Typed for IStr {152	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);153}154impl TryFrom<Val> for IStr {155	type Error = LocError;156157	fn try_from(value: Val) -> Result<Self> {158		<Self as Typed>::TYPE.check(&value)?;159		match value {160			Val::Str(s) => Ok(s),161			_ => unreachable!(),162		}163	}164}165impl TryFrom<IStr> for Val {166	type Error = LocError;167168	fn try_from(value: IStr) -> Result<Self> {169		Ok(Self::Str(value))170	}171}172173impl Typed for String {174	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);175}176impl TryFrom<Val> for String {177	type Error = LocError;178179	fn try_from(value: Val) -> Result<Self> {180		<Self as Typed>::TYPE.check(&value)?;181		match value {182			Val::Str(s) => Ok(s.to_string()),183			_ => unreachable!(),184		}185	}186}187impl TryFrom<String> for Val {188	type Error = LocError;189190	fn try_from(value: String) -> Result<Self> {191		Ok(Self::Str(value.into()))192	}193}194195impl Typed for char {196	const TYPE: &'static ComplexValType = &ComplexValType::Char;197}198impl TryFrom<Val> for char {199	type Error = LocError;200201	fn try_from(value: Val) -> Result<Self> {202		<Self as Typed>::TYPE.check(&value)?;203		match value {204			Val::Str(s) => Ok(s.chars().next().unwrap()),205			_ => unreachable!(),206		}207	}208}209impl TryFrom<char> for Val {210	type Error = LocError;211212	fn try_from(value: char) -> Result<Self> {213		Ok(Self::Str(value.to_string().into()))214	}215}216217impl<T> Typed for Vec<T>218where219	T: Typed,220	T: TryFrom<Val, Error = LocError>,221	T: TryInto<Val, Error = LocError>,222{223	const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);224}225impl<T> TryFrom<Val> for Vec<T>226where227	T: Typed,228	T: TryFrom<Val, Error = LocError>,229	T: TryInto<Val, Error = LocError>,230{231	type Error = LocError;232233	fn try_from(value: Val) -> Result<Self> {234		<Self as Typed>::TYPE.check(&value)?;235		match value {236			Val::Arr(a) => {237				let mut o = Self::with_capacity(a.len());238				for i in a.iter() {239					o.push(T::try_from(i?)?);240				}241				Ok(o)242			}243			_ => unreachable!(),244		}245	}246}247impl<T> TryFrom<Vec<T>> for Val248where249	T: Typed,250	T: TryFrom<Self, Error = LocError>,251	T: TryInto<Self, Error = LocError>,252{253	type Error = LocError;254255	fn try_from(value: Vec<T>) -> Result<Self> {256		let mut o = Vec::with_capacity(value.len());257		for i in value {258			o.push(i.try_into()?);259		}260		Ok(Self::Arr(o.into()))261	}262}263264/// To be used in Vec<Any>265/// Regular Val can't be used here, because it has wrong TryFrom::Error type266#[derive(Clone)]267pub struct Any(pub Val);268269impl Typed for Any {270	const TYPE: &'static ComplexValType = &ComplexValType::Any;271}272impl TryFrom<Val> for Any {273	type Error = LocError;274275	fn try_from(value: Val) -> Result<Self> {276		Ok(Self(value))277	}278}279impl TryFrom<Any> for Val {280	type Error = LocError;281282	fn try_from(value: Any) -> Result<Self> {283		Ok(value.0)284	}285}286287/// Specialization, provides faster TryFrom<VecVal> for Val288pub struct VecVal(pub Cc<Vec<Val>>);289290impl Typed for VecVal {291	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);292}293impl TryFrom<Val> for VecVal {294	type Error = LocError;295296	fn try_from(value: Val) -> Result<Self> {297		<Self as Typed>::TYPE.check(&value)?;298		match value {299			Val::Arr(a) => Ok(Self(a.evaluated()?)),300			_ => unreachable!(),301		}302	}303}304impl TryFrom<VecVal> for Val {305	type Error = LocError;306307	fn try_from(value: VecVal) -> Result<Self> {308		Ok(Self::Arr(ArrValue::Eager(value.0)))309	}310}311312/// Specialization313pub struct Bytes(pub Rc<[u8]>);314315impl Typed for Bytes {316	const TYPE: &'static ComplexValType =317		&ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));318}319impl TryFrom<Val> for Bytes {320	type Error = LocError;321322	fn try_from(value: Val) -> Result<Self> {323		match value {324			Val::Arr(ArrValue::Bytes(bytes)) => Ok(Self(bytes)),325			_ => {326				<Self as Typed>::TYPE.check(&value)?;327				match value {328					Val::Arr(a) => {329						let mut out = Vec::with_capacity(a.len());330						for e in a.iter() {331							let r = e?;332							out.push(u8::try_from(r)?);333						}334						Ok(Self(out.into()))335					}336					_ => unreachable!(),337				}338			}339		}340	}341}342impl TryFrom<Bytes> for Val {343	type Error = LocError;344345	fn try_from(value: Bytes) -> Result<Self> {346		Ok(Self::Arr(ArrValue::Bytes(value.0)))347	}348}349350pub struct M1;351impl Typed for M1 {352	const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));353}354impl TryFrom<Val> for M1 {355	type Error = LocError;356357	fn try_from(value: Val) -> Result<Self> {358		<Self as Typed>::TYPE.check(&value)?;359		Ok(Self)360	}361}362impl TryFrom<M1> for Val {363	type Error = LocError;364365	fn try_from(_: M1) -> Result<Self> {366		Ok(Self::Num(-1.0))367	}368}369370macro_rules! decl_either {371	($($name: ident, $($id: ident)*);*) => {$(372		pub enum $name<$($id),*> {373			$($id($id)),*374		}375		impl<$($id),*> Typed for $name<$($id),*>376		where377			$($id: Typed,)*378		{379			const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);380		}381		impl<$($id),*> TryFrom<Val> for $name<$($id),*>382		where383			$($id: Typed,)*384		{385			type Error = LocError;386387			fn try_from(value: Val) -> Result<Self> {388				$(389					if $id::TYPE.check(&value).is_ok() {390						$id::try_from(value).map(Self::$id)391					} else392				)* {393					<Self as Typed>::TYPE.check(&value)?;394					unreachable!()395				}396			}397		}398		impl<$($id),*> TryFrom<$name<$($id),*>> for Val399		where400			$($id: Typed,)*401		{402			type Error = LocError;403			fn try_from(value: $name<$($id),*>) -> Result<Self> {404				match value {$(405					$name::$id(v) => v.try_into()406				),*}407			}408		}409	)*}410}411decl_either!(412	Either1, A;413	Either2, A B;414	Either3, A B C;415	Either4, A B C D;416	Either5, A B C D E;417	Either6, A B C D E F;418	Either7, A B C D E F G419);420#[macro_export]421macro_rules! Either {422	($a:ty) => {Either1<$a>};423	($a:ty, $b:ty) => {Either2<$a, $b>};424	($a:ty, $b:ty, $c:ty) => {Either3<$a, $b, $c>};425	($a:ty, $b:ty, $c:ty, $d:ty) => {Either4<$a, $b, $c, $d>};426	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty) => {Either5<$a, $b, $c, $d, $e>};427	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty) => {Either6<$a, $b, $c, $d, $e, $f>};428	($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty) => {Either7<$a, $b, $c, $d, $e, $f, $g>};429}430431pub type MyType = Either![u32, f64, String];432433impl Typed for ArrValue {434	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);435}436impl TryFrom<Val> for ArrValue {437	type Error = LocError;438439	fn try_from(value: Val) -> Result<Self> {440		<Self as Typed>::TYPE.check(&value)?;441		match value {442			Val::Arr(a) => Ok(a),443			_ => unreachable!(),444		}445	}446}447impl TryFrom<ArrValue> for Val {448	type Error = LocError;449450	fn try_from(value: ArrValue) -> Result<Self> {451		Ok(Self::Arr(value))452	}453}454455impl Typed for FuncVal {456	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);457}458impl TryFrom<Val> for FuncVal {459	type Error = LocError;460461	fn try_from(value: Val) -> Result<Self> {462		<Self as Typed>::TYPE.check(&value)?;463		match value {464			Val::Func(a) => Ok(a),465			_ => unreachable!(),466		}467	}468}469impl TryFrom<FuncVal> for Val {470	type Error = LocError;471472	fn try_from(value: FuncVal) -> Result<Self> {473		Ok(Self::Func(value))474	}475}476477impl Typed for Cc<FuncDesc> {478	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);479}480impl TryFrom<Val> for Cc<FuncDesc> {481	type Error = LocError;482483	fn try_from(value: Val) -> Result<Self, Self::Error> {484		<Self as Typed>::TYPE.check(&value)?;485		match value {486			Val::Func(FuncVal::Normal(desc)) => Ok(desc),487			Val::Func(_) => throw!(RuntimeError("expected normal function, not builtin".into())),488			_ => unreachable!(),489		}490	}491}492impl TryFrom<Cc<FuncDesc>> for Val {493	type Error = LocError;494495	fn try_from(value: Cc<FuncDesc>) -> Result<Self, Self::Error> {496		Ok(Self::Func(FuncVal::Normal(value)))497	}498}499500impl Typed for ObjValue {501	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj);502}503impl TryFrom<Val> for ObjValue {504	type Error = LocError;505506	fn try_from(value: Val) -> Result<Self> {507		<Self as Typed>::TYPE.check(&value)?;508		match value {509			Val::Obj(a) => Ok(a),510			_ => unreachable!(),511		}512	}513}514impl TryFrom<ObjValue> for Val {515	type Error = LocError;516517	fn try_from(value: ObjValue) -> Result<Self> {518		Ok(Self::Obj(value))519	}520}521522impl Typed for bool {523	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);524}525impl TryFrom<Val> for bool {526	type Error = LocError;527528	fn try_from(value: Val) -> Result<Self> {529		<Self as Typed>::TYPE.check(&value)?;530		match value {531			Val::Bool(a) => Ok(a),532			_ => unreachable!(),533		}534	}535}536impl TryFrom<bool> for Val {537	type Error = LocError;538539	fn try_from(value: bool) -> Result<Self> {540		Ok(Self::Bool(value))541	}542}543544impl Typed for IndexableVal {545	const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[546		&ComplexValType::Simple(ValType::Arr),547		&ComplexValType::Simple(ValType::Str),548	]);549}550impl TryFrom<Val> for IndexableVal {551	type Error = LocError;552553	fn try_from(value: Val) -> Result<Self> {554		<Self as Typed>::TYPE.check(&value)?;555		value.into_indexable()556	}557}558impl TryFrom<IndexableVal> for Val {559	type Error = LocError;560561	fn try_from(value: IndexableVal) -> Result<Self> {562		match value {563			IndexableVal::Str(s) => Ok(Self::Str(s)),564			IndexableVal::Arr(a) => Ok(Self::Arr(a)),565		}566	}567}568569pub struct Null;570impl Typed for Null {571	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);572}573impl TryFrom<Val> for Null {574	type Error = LocError;575576	fn try_from(value: Val) -> Result<Self> {577		<Self as Typed>::TYPE.check(&value)?;578		Ok(Self)579	}580}581impl TryFrom<Null> for Val {582	type Error = LocError;583584	fn try_from(_: Null) -> Result<Self> {585		Ok(Self::Null)586	}587}
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -172,6 +172,37 @@
 }
 
 #[derive(Debug, Clone, Trace)]
+pub struct Slice {
+	pub(crate) inner: ArrValue,
+	pub(crate) from: u32,
+	pub(crate) to: u32,
+	pub(crate) step: u32,
+}
+impl Slice {
+	fn from(&self) -> usize {
+		self.from as usize
+	}
+	fn to(&self) -> usize {
+		self.to as usize
+	}
+	fn step(&self) -> usize {
+		self.step as usize
+	}
+	fn len(&self) -> usize {
+		// TODO: use div_ceil
+		let diff = self.to() - self.from();
+		let rem = diff % self.step();
+		let div = diff / self.step();
+
+		if rem != 0 {
+			div + 1
+		} else {
+			div
+		}
+	}
+}
+
+#[derive(Debug, Clone, Trace)]
 #[force_tracking]
 pub enum ArrValue {
 	Bytes(#[skip_trace] Rc<[u8]>),
@@ -179,6 +210,7 @@
 	Eager(Cc<Vec<Val>>),
 	Extended(Box<(Self, Self)>),
 	Range(i32, i32),
+	Slice(Box<Slice>),
 	Reversed(Box<Self>),
 }
 impl ArrValue {
@@ -190,6 +222,22 @@
 		Self::Range(a, b)
 	}
 
+	pub fn slice(self, from: Option<usize>, to: Option<usize>, step: Option<usize>) -> Self {
+		let len = self.len();
+		let from = from.unwrap_or(0);
+		let to = to.unwrap_or(len).min(len);
+		let step = step.unwrap_or(1);
+		assert!(from < to);
+		assert!(step > 0);
+
+		Self::Slice(Box::new(Slice {
+			inner: self,
+			from: from as u32,
+			to: to as u32,
+			step: step as u32,
+		}))
+	}
+
 	pub fn len(&self) -> usize {
 		match self {
 			Self::Bytes(i) => i.len(),
@@ -198,6 +246,7 @@
 			Self::Extended(v) => v.0.len() + v.1.len(),
 			Self::Range(a, b) => a.abs_diff(*b) as usize,
 			Self::Reversed(i) => i.len(),
+			Self::Slice(s) => s.len(),
 		}
 	}
 
@@ -239,6 +288,13 @@
 				}
 				v.get(len - index - 1)
 			}
+			Self::Slice(s) => {
+				let index = s.from() + index * s.step();
+				if index >= s.to() {
+					return Ok(None);
+				}
+				s.inner.get(index as usize)
+			}
 		}
 	}
 
@@ -272,6 +328,13 @@
 				}
 				v.get_lazy(len - index - 1)
 			}
+			Self::Slice(s) => {
+				let index = s.from() + index * s.step();
+				if index >= s.to() {
+					return None;
+				}
+				s.inner.get_lazy(index as usize)
+			}
 		}
 	}
 
@@ -311,33 +374,43 @@
 				Cc::update_with(&mut r, |v| v.reverse());
 				r
 			}
+			Self::Slice(v) => {
+				let mut out = Vec::with_capacity(v.inner.len());
+				for v in v
+					.inner
+					.iter_lazy()
+					.skip(v.from())
+					.take(v.to() - v.from())
+					.step_by(v.step())
+				{
+					out.push(v.evaluate()?)
+				}
+				Cc::new(out)
+			}
 		})
 	}
 
 	pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {
-		// if let Self::Reversed(v) = self {
-		// 	return v.iter().rev();
-		// }
-		let len = self.len();
-		(0..len).map(move |idx| match self {
+		(0..self.len()).map(move |idx| match self {
 			Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)),
 			Self::Lazy(l) => l[idx].evaluate(),
 			Self::Eager(e) => Ok(e[idx].clone()),
 			Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),
 			Self::Range(..) => self.get(idx).map(|e| e.unwrap()),
-			Self::Reversed(..) => self.get(len - idx - 1).map(|e| e.unwrap()),
+			Self::Reversed(..) => self.get(idx).map(|e| e.unwrap()),
+			Self::Slice(..) => self.get(idx).map(|e| e.unwrap()),
 		})
 	}
 
 	pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {
-		let len = self.len();
-		(0..len).map(move |idx| match self {
+		(0..self.len()).map(move |idx| match self {
 			Self::Bytes(b) => LazyVal::new_resolved(Val::Num(b[idx] as f64)),
 			Self::Lazy(l) => l[idx].clone(),
 			Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),
 			Self::Extended(_) => self.get_lazy(idx).unwrap(),
 			Self::Range(..) => self.get_lazy(idx).unwrap(),
-			Self::Reversed(..) => self.get_lazy(len - idx - 1).unwrap(),
+			Self::Reversed(..) => self.get_lazy(idx).unwrap(),
+			Self::Slice(..) => self.get_lazy(idx).unwrap(),
 		})
 	}
 
@@ -459,17 +532,6 @@
 		}
 	}
 
-	pub fn try_cast_nullable_num(self, context: &'static str) -> Result<Option<f64>> {
-		Ok(match self {
-			Val::Null => None,
-			Val::Num(num) => Some(num),
-			_ => throw!(TypeMismatch(
-				context,
-				vec![ValType::Null, ValType::Num],
-				self.value_type()
-			)),
-		})
-	}
 	pub const fn value_type(&self) -> ValType {
 		match self {
 			Self::Str(..) => ValType::Str,