Fix bug in dotting-indexing.

This commit is contained in:
Stephen Chung 2021-08-17 15:32:48 +08:00
parent 8a8bc2adfb
commit 224a2dfb60
2 changed files with 40 additions and 38 deletions

View File

@ -1697,52 +1697,51 @@ fn make_dot_expr(
(lhs, prop @ Expr::Property(_)) => { (lhs, prop @ Expr::Property(_)) => {
Expr::Dot(BinaryExpr { lhs, rhs: prop }.into(), false, op_pos) Expr::Dot(BinaryExpr { lhs, rhs: prop }.into(), false, op_pos)
} }
// lhs.dot_lhs.dot_rhs // lhs.dot_lhs.dot_rhs or lhs.dot_lhs[idx_rhs]
(lhs, Expr::Dot(x, _, pos)) => match x.lhs { (lhs, rhs @ Expr::Dot(_, _, _)) | (lhs, rhs @ Expr::Index(_, _, _)) => {
Expr::Variable(_, _, _) | Expr::Property(_) => { let (x, term, pos, is_dot) = match rhs {
let rhs = Expr::Dot( Expr::Dot(x, term, pos) => (x, term, pos, true),
BinaryExpr { Expr::Index(x, term, pos) => (x, term, pos, false),
_ => unreachable!(),
};
match x.lhs {
Expr::Variable(_, _, _) | Expr::Property(_) => {
let new_lhs = BinaryExpr {
lhs: x.lhs.into_property(state), lhs: x.lhs.into_property(state),
rhs: x.rhs, rhs: x.rhs,
} }
.into(), .into();
false,
pos,
);
Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos)
}
Expr::FnCall(mut func, func_pos) => {
// Recalculate hash
func.hashes = FnCallHashes::from_script_and_native(
calc_fn_hash(&func.name, func.args.len()),
calc_fn_hash(&func.name, func.args.len() + 1),
);
let rhs = Expr::Dot( let rhs = if is_dot {
BinaryExpr { Expr::Dot(new_lhs, term, pos)
} else {
Expr::Index(new_lhs, term, pos)
};
Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos)
}
Expr::FnCall(mut func, func_pos) => {
// Recalculate hash
func.hashes = FnCallHashes::from_script_and_native(
calc_fn_hash(&func.name, func.args.len()),
calc_fn_hash(&func.name, func.args.len() + 1),
);
let new_lhs = BinaryExpr {
lhs: Expr::FnCall(func, func_pos), lhs: Expr::FnCall(func, func_pos),
rhs: x.rhs, rhs: x.rhs,
} }
.into(), .into();
false,
pos, let rhs = if is_dot {
); Expr::Dot(new_lhs, term, pos)
Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos) } else {
} Expr::Index(new_lhs, term, pos)
_ => unreachable!("invalid dot expression: {:?}", x.lhs), };
}, Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos)
// lhs.idx_lhs[idx_rhs]
(lhs, Expr::Index(x, term, pos)) => {
let rhs = Expr::Index(
BinaryExpr {
lhs: x.lhs.into_property(state),
rhs: x.rhs,
} }
.into(), _ => unreachable!("invalid dot expression: {:?}", x.lhs),
term, }
pos,
);
Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos)
} }
// lhs.nnn::func(...) // lhs.nnn::func(...)
(_, Expr::FnCall(x, _)) if x.is_qualified() => { (_, Expr::FnCall(x, _)) if x.is_qualified() => {

View File

@ -168,6 +168,9 @@ fn test_array_with_structs() -> Result<(), Box<EvalAltResult>> {
fn test_arrays_map_reduce() -> Result<(), Box<EvalAltResult>> { fn test_arrays_map_reduce() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new(); let engine = Engine::new();
assert_eq!(engine.eval::<INT>("[1].map(|x| x + 41)[0]")?, 42);
assert_eq!(engine.eval::<INT>("([1].map(|x| x + 41))[0]")?, 42);
assert_eq!( assert_eq!(
convert_to_vec::<INT>(engine.eval( convert_to_vec::<INT>(engine.eval(
" "