Skip to content

Commit

Permalink
Merge pull request #849 from schungx/master
Browse files Browse the repository at this point in the history
Fix range indexing bug.
  • Loading branch information
schungx committed Mar 21, 2024
2 parents 10951b7 + 8043504 commit 4ea9b74
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 27 deletions.
1 change: 1 addition & 0 deletions src/bin/rhai-repl.rs
Expand Up @@ -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();
Expand Down
22 changes: 19 additions & 3 deletions src/eval/chaining.rs
Expand Up @@ -207,13 +207,25 @@ impl Engine {
// val_int[range]
let (shift, mask) = if let Some(range) = idx.read_lock::<crate::ExclusiveRange>() {
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)]
Expand All @@ -233,7 +245,11 @@ impl Engine {
}
} else if let Some(range) = idx.read_lock::<crate::InclusiveRange>() {
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()
Expand Down
48 changes: 28 additions & 20 deletions src/parser.rs
Expand Up @@ -1314,13 +1314,13 @@ impl Engine {
mut settings: ParseSettings,
options: ChainingFlags,
) -> ParseResult<Expr> {
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)),
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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()),
}
}
// <EOF>
Token::EOF => Err(PERR::UnexpectedEOF.into_err(settings.pos)),
// All other tokens
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) => {
Expand Down
24 changes: 20 additions & 4 deletions src/types/dynamic.rs
Expand Up @@ -536,9 +536,17 @@ impl fmt::Display for Dynamic {
}

if let Some(range) = _value_any.downcast_ref::<ExclusiveRange>() {
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::<InclusiveRange>() {
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())
Expand Down Expand Up @@ -696,9 +704,17 @@ impl fmt::Debug for Dynamic {
}

if let Some(range) = _value_any.downcast_ref::<ExclusiveRange>() {
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::<InclusiveRange>() {
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())
Expand Down

0 comments on commit 4ea9b74

Please sign in to comment.