Fix bug in parsing index chains.

This commit is contained in:
Stephen Chung 2023-04-19 23:17:54 +08:00
parent 0699f47ff9
commit fb88b79178
3 changed files with 31 additions and 8 deletions

View File

@ -11,6 +11,7 @@ Buf fixes
* `is_shared` is a reserved keyword and is now handled properly (e.g. it cannot be the target of a function pointer). * `is_shared` is a reserved keyword and is now handled properly (e.g. it cannot be the target of a function pointer).
* Re-optimizing an AST via `optimize_ast` with constants now works correctly for closures. Previously the hidden `Share` nodes are not removed and causes variable-not-found errors during runtime if the constants are not available in the scope. * Re-optimizing an AST via `optimize_ast` with constants now works correctly for closures. Previously the hidden `Share` nodes are not removed and causes variable-not-found errors during runtime if the constants are not available in the scope.
* Expressions such as `(v[0].func()).prop` now parse correctly.
New features New features
------------ ------------

View File

@ -1728,6 +1728,9 @@ impl Engine {
) -> ParseResult<Expr> { ) -> ParseResult<Expr> {
let mut settings = settings; let mut settings = settings;
// Break just in case `lhs` is `Expr::Dot` or `Expr::Index`
let mut parent_options = ASTFlags::BREAK;
// Tail processing all possible postfix operators // Tail processing all possible postfix operators
loop { loop {
let (tail_token, ..) = input.peek().expect(NEVER_ENDS); let (tail_token, ..) = input.peek().expect(NEVER_ENDS);
@ -1842,13 +1845,16 @@ impl Engine {
let rhs = let rhs =
self.parse_primary(input, state, lib, settings.level_up()?, options)?; self.parse_primary(input, state, lib, settings.level_up()?, options)?;
Self::make_dot_expr(state, expr, rhs, ASTFlags::empty(), op_flags, tail_pos)? Self::make_dot_expr(state, expr, rhs, parent_options, op_flags, tail_pos)?
} }
// Unknown postfix operator // Unknown postfix operator
(expr, token) => { (expr, token) => {
unreachable!("unknown postfix operator '{}' for {:?}", token, expr) unreachable!("unknown postfix operator '{}' for {:?}", token, expr)
} }
} };
// The chain is now extended
parent_options = ASTFlags::empty();
} }
// Cache the hash key for namespace-qualified variables // Cache the hash key for namespace-qualified variables

View File

@ -203,6 +203,22 @@ fn test_arrays() -> Result<(), Box<EvalAltResult>> {
Ok(()) Ok(())
} }
#[cfg(not(feature = "no_float"))]
#[cfg(not(feature = "no_object"))]
#[test]
fn test_array_chaining() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new();
assert!(engine.eval::<bool>(
"
let v = [ PI() ];
( v[0].cos() ).sin() == v[0].cos().sin()
"
)?);
Ok(())
}
#[test] #[test]
fn test_array_index_types() -> Result<(), Box<EvalAltResult>> { fn test_array_index_types() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new(); let engine = Engine::new();
@ -508,9 +524,9 @@ fn test_arrays_map_reduce() -> Result<(), Box<EvalAltResult>> {
engine.eval::<()>( engine.eval::<()>(
" "
let x = [1, 2, 3, 2, 1]; let x = [1, 2, 3, 2, 1];
x.find(|v| v > 4) x.find(|v| v > 4)
", ",
)?; )?;
assert_eq!( assert_eq!(
@ -525,9 +541,9 @@ fn test_arrays_map_reduce() -> Result<(), Box<EvalAltResult>> {
engine.eval::<()>( engine.eval::<()>(
" "
let x = [#{alice: 1}, #{bob: 2}, #{clara: 3}]; let x = [#{alice: 1}, #{bob: 2}, #{clara: 3}];
x.find_map(|v| v.dave) x.find_map(|v| v.dave)
", ",
)?; )?;
Ok(()) Ok(())