diff --git a/core/expression/src/vm/error.rs b/core/expression/src/vm/error.rs index 9ef60f52..fe7638f7 100644 --- a/core/expression/src/vm/error.rs +++ b/core/expression/src/vm/error.rs @@ -2,7 +2,7 @@ use thiserror::Error; #[derive(Debug, PartialEq, Eq, Clone, Error)] pub enum VMError { - #[error("Unsupported opcode type")] + #[error("Unsupported opcode type in '{opcode}'")] OpcodeErr { opcode: String, message: String }, #[error("Opcode out of bounds")] diff --git a/core/expression/src/vm/variable.rs b/core/expression/src/vm/variable.rs index 1be6ff22..57ef9339 100644 --- a/core/expression/src/vm/variable.rs +++ b/core/expression/src/vm/variable.rs @@ -55,4 +55,24 @@ impl IntervalObject { left, }) } + + pub(crate) fn to_array(&self) -> Option> { + let start = match &self.left_bracket { + Bracket::LeftParenthesis => self.left.as_number()?.to_usize()? + 1, + Bracket::LeftSquareBracket => self.left.as_number()?.to_usize()?, + _ => return None, + }; + + let end = match &self.right_bracket { + Bracket::RightParenthesis => self.right.as_number()?.to_usize()? - 1, + Bracket::RightSquareBracket => self.right.as_number()?.to_usize()?, + _ => return None, + }; + + let list = (start..=end) + .map(|n| Variable::Number(Decimal::from(n))) + .collect::>(); + + Some(list) + } } diff --git a/core/expression/src/vm/vm.rs b/core/expression/src/vm/vm.rs index 4971d822..fcc91c8c 100644 --- a/core/expression/src/vm/vm.rs +++ b/core/expression/src/vm/vm.rs @@ -1601,29 +1601,39 @@ impl<'arena, 'parent_ref, 'bytecode_ref> VMInner<'parent_ref, 'bytecode_ref> { } } Opcode::Begin => { - let a = self.pop()?; - let arr_len = match &a { + let var = self.pop()?; + let maybe_scope = match &var { Array(a) => { let arr = a.borrow(); - Some(arr.len()) - } - _ => None, - }; - - match arr_len { - Some(len) => self.scopes.push(Scope { - array: a, - count: 0, - len, - iter: 0, - }), - None => { - return Err(OpcodeErr { - opcode: "Begin".into(), - message: "Unsupported type".into(), + Some(Scope { + len: arr.len(), + array: var.clone(), + count: 0, + iter: 0, }) } - } + _ => match IntervalObject::try_from_object(var) + .map(|s| s.to_array()) + .flatten() + { + None => None, + Some(arr) => Some(Scope { + len: arr.len(), + array: Variable::from_array(arr), + count: 0, + iter: 0, + }), + }, + }; + + let Some(scope) = maybe_scope else { + return Err(OpcodeErr { + opcode: "Begin".into(), + message: "Unsupported type".into(), + }); + }; + + self.scopes.push(scope); } Opcode::End => { self.scopes.pop(); diff --git a/core/expression/tests/data/standard.csv b/core/expression/tests/data/standard.csv index 58fc840f..484bcf08 100644 --- a/core/expression/tests/data/standard.csv +++ b/core/expression/tests/data/standard.csv @@ -276,6 +276,12 @@ values(customer);{"customer": {"firstName": "John"}};["John"] values(customer);{"customer": {"lastName": "Doe"}};["Doe"] {};;{} +# Interval iterator +map([0..3], #);[0, 1, 2, 3] +map((0..3], #);[1, 2, 3] +map([0..3), #);[0, 1, 2] +map((0..3), #);[1, 2] + # Nullish coalescing null ?? 'hello';;'hello' null ?? 123 ?? 321;;123