From 804350477672ab4aff5fdd0bbf37a40f6c4ba988 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 21 Mar 2024 12:09:09 +0800 Subject: [PATCH] Fix range indexing bug. --- src/bin/rhai-repl.rs | 1 + src/eval/chaining.rs | 22 +++++++++++++++++--- src/parser.rs | 48 ++++++++++++++++++++++++++------------------ src/types/dynamic.rs | 24 ++++++++++++++++++---- 4 files changed, 68 insertions(+), 27 deletions(-) diff --git a/src/bin/rhai-repl.rs b/src/bin/rhai-repl.rs index 65b826b7b..9c8e6c911 100644 --- a/src/bin/rhai-repl.rs +++ b/src/bin/rhai-repl.rs @@ -563,6 +563,7 @@ fn main() { .compile_with_scope(&scope, &input) .map_err(Into::into) .and_then(|r| { + println!("AST: {r:#?}"); #[cfg(not(feature = "no_optimize"))] { ast_u = r.clone(); diff --git a/src/eval/chaining.rs b/src/eval/chaining.rs index 8efaaf470..40da1156a 100644 --- a/src/eval/chaining.rs +++ b/src/eval/chaining.rs @@ -207,13 +207,25 @@ impl Engine { // val_int[range] let (shift, mask) = if let Some(range) = idx.read_lock::() { let start = range.start; - let end = range.end; + let end = if range.end == crate::INT::MAX { + crate::INT_BITS as crate::INT + } else { + range.end + }; let start = super::calc_index(crate::INT_BITS, start, false, || { ERR::ErrorBitFieldBounds(crate::INT_BITS, start, idx_pos).into() })?; let end = super::calc_index(crate::INT_BITS, end, false, || { - ERR::ErrorBitFieldBounds(crate::INT_BITS, end, idx_pos).into() + if end >= 0 + && end < crate::MAX_USIZE_INT + && (end as usize) <= crate::INT_BITS + { + // Handle largest value + Ok(end as usize) + } else { + ERR::ErrorBitFieldBounds(crate::INT_BITS, end, idx_pos).into() + } })?; #[allow(clippy::cast_possible_truncation)] @@ -233,7 +245,11 @@ impl Engine { } } else if let Some(range) = idx.read_lock::() { let start = *range.start(); - let end = *range.end(); + let end = if *range.end() == crate::INT::MAX { + (crate::INT_BITS - 1) as crate::INT + } else { + *range.end() + }; let start = super::calc_index(crate::INT_BITS, start, false, || { ERR::ErrorBitFieldBounds(crate::INT_BITS, start, idx_pos).into() diff --git a/src/parser.rs b/src/parser.rs index edf7e7557..3ccd5531f 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1314,13 +1314,13 @@ impl Engine { mut settings: ParseSettings, options: ChainingFlags, ) -> ParseResult { - let (token, token_pos) = state.input.peek().unwrap(); + let (next_token, next_token_pos) = state.input.peek().unwrap(); - settings.pos = *token_pos; + settings.pos = *next_token_pos; - let root_expr = match token { - _ if !(state.expr_filter)(token) => { - return Err(LexError::UnexpectedInput(token.to_string()).into_err(settings.pos)) + let root_expr = match next_token { + _ if !(state.expr_filter)(next_token) => { + return Err(LexError::UnexpectedInput(next_token.to_string()).into_err(settings.pos)) } Token::EOF => return Err(PERR::UnexpectedEOF.into_err(settings.pos)), @@ -1700,7 +1700,9 @@ impl Engine { token => unreachable!("Token::LexError expected but gets {:?}", token), }, - _ => return Err(LexError::UnexpectedInput(token.to_string()).into_err(settings.pos)), + _ => { + return Err(LexError::UnexpectedInput(next_token.to_string()).into_err(settings.pos)) + } }; if !(state.expr_filter)(&state.input.peek().unwrap().0) { @@ -2015,13 +2017,6 @@ impl Engine { } .into_fn_call_expr(pos)) } - Token::RightBracket => { - let v = state.input.peek(); - match v { - Some((Token::RightBracket, _)) => Ok(Expr::Unit(settings.pos.clone())), - _ => self.parse_primary(state, settings, ChainingFlags::empty()), - } - } // Token::EOF => Err(PERR::UnexpectedEOF.into_err(settings.pos)), // All other tokens @@ -2335,7 +2330,25 @@ impl Engine { let (op_token, pos) = state.input.next().unwrap(); - let rhs = self.parse_unary(state, settings)?; + // Parse the RHS + let rhs = match op_token { + // [xxx..] | (xxx..) | {xxx..} | xxx.., | xxx..; | xxx.. => + // [xxx..=] | (xxx..=) | {xxx..=} | xxx..=, | xxx..=; | xxx..= => + Token::ExclusiveRange | Token::InclusiveRange => { + let (next_op, next_pos) = state.input.peek().unwrap(); + + match next_op { + Token::RightBracket + | Token::RightParen + | Token::RightBrace + | Token::Comma + | Token::SemiColon + | Token::DoubleArrow => Expr::Unit(*next_pos), + _ => self.parse_unary(state, settings)?, + } + } + _ => self.parse_unary(state, settings)?, + }; let (next_op, next_pos) = state.input.peek().unwrap(); let next_precedence = match next_op { @@ -2420,12 +2433,7 @@ impl Engine { not_base.into_fn_call_expr(pos) } } - Token::ExclusiveRange | Token::InclusiveRange => { - if op_base.args[1].is_unit() { - let _ = op_base.args[1].take(); - } - op_base.into_fn_call_expr(pos) - } + Token::ExclusiveRange | Token::InclusiveRange => op_base.into_fn_call_expr(pos), #[cfg(not(feature = "no_custom_syntax"))] Token::Custom(s) if self.custom_keywords.contains_key(&*s) => { diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index 30ab9409b..dfbd1f24d 100644 --- a/src/types/dynamic.rs +++ b/src/types/dynamic.rs @@ -536,9 +536,17 @@ impl fmt::Display for Dynamic { } if let Some(range) = _value_any.downcast_ref::() { - return write!(f, "{}..{}", range.start, range.end); + return if range.end == INT::MAX { + write!(f, "{}..", range.start) + } else { + write!(f, "{}..{}", range.start, range.end) + }; } else if let Some(range) = _value_any.downcast_ref::() { - return write!(f, "{}..={}", range.start(), range.end()); + return if *range.end() == INT::MAX { + write!(f, "{}..=", range.start()) + } else { + write!(f, "{}..={}", range.start(), range.end()) + }; } f.write_str((***v).type_name()) @@ -696,9 +704,17 @@ impl fmt::Debug for Dynamic { } if let Some(range) = _value_any.downcast_ref::() { - return write!(f, "{}..{}", range.start, range.end); + return if range.end == INT::MAX { + write!(f, "{}..", range.start) + } else { + write!(f, "{}..{}", range.start, range.end) + }; } else if let Some(range) = _value_any.downcast_ref::() { - return write!(f, "{}..={}", range.start(), range.end()); + return if *range.end() == INT::MAX { + write!(f, "{}..=", range.start()) + } else { + write!(f, "{}..={}", range.start(), range.end()) + }; } f.write_str((***v).type_name())