Fix bug with wrong method call hash.
This commit is contained in:
parent
33c9be7efc
commit
2e28967565
@ -767,6 +767,7 @@ fn parse_call_expr<'a>(
|
|||||||
// id(...args)
|
// id(...args)
|
||||||
(Token::RightParen, _) => {
|
(Token::RightParen, _) => {
|
||||||
eat_token(input, Token::RightParen);
|
eat_token(input, Token::RightParen);
|
||||||
|
let args_iter = repeat(EMPTY_TYPE_ID()).take(args.len());
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let hash_fn_def = {
|
let hash_fn_def = {
|
||||||
@ -779,19 +780,14 @@ fn parse_call_expr<'a>(
|
|||||||
// 2) Calculate a second hash with no qualifiers, empty function name, and
|
// 2) Calculate a second hash with no qualifiers, empty function name, and
|
||||||
// the actual list of parameter `TypeId`'.s
|
// the actual list of parameter `TypeId`'.s
|
||||||
// 3) The final hash is the XOR of the two hashes.
|
// 3) The final hash is the XOR of the two hashes.
|
||||||
calc_fn_hash(
|
calc_fn_hash(modules.iter().map(|(m, _)| m.as_str()), &id, args_iter)
|
||||||
modules.iter().map(|(m, _)| m.as_str()),
|
|
||||||
&id,
|
|
||||||
repeat(EMPTY_TYPE_ID()).take(args.len()),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
calc_fn_hash(empty(), &id, repeat(EMPTY_TYPE_ID()).take(args.len()))
|
calc_fn_hash(empty(), &id, args_iter)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Qualifiers (none) + function name + dummy parameter types (one for each parameter).
|
// Qualifiers (none) + function name + dummy parameter types (one for each parameter).
|
||||||
#[cfg(feature = "no_module")]
|
#[cfg(feature = "no_module")]
|
||||||
let hash_fn_def =
|
let hash_fn_def = calc_fn_hash(empty(), &id, args_iter);
|
||||||
calc_fn_hash(empty(), &id, repeat(EMPTY_TYPE_ID()).take(args.len()));
|
|
||||||
|
|
||||||
return Ok(Expr::FnCall(Box::new((
|
return Ok(Expr::FnCall(Box::new((
|
||||||
(id.into(), begin),
|
(id.into(), begin),
|
||||||
@ -1204,10 +1200,7 @@ fn parse_primary<'a>(
|
|||||||
let ((name, pos), modules, _, _) = *x;
|
let ((name, pos), modules, _, _) = *x;
|
||||||
parse_call_expr(input, stack, name, modules, pos, allow_stmt_expr)?
|
parse_call_expr(input, stack, name, modules, pos, allow_stmt_expr)?
|
||||||
}
|
}
|
||||||
(Expr::Property(x), Token::LeftParen) => {
|
(Expr::Property(_), _) => unreachable!(),
|
||||||
let (name, pos) = *x;
|
|
||||||
parse_call_expr(input, stack, name, None, pos, allow_stmt_expr)?
|
|
||||||
}
|
|
||||||
// module access
|
// module access
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
(Expr::Variable(x), Token::DoubleColon) => match input.next().unwrap() {
|
(Expr::Variable(x), Token::DoubleColon) => match input.next().unwrap() {
|
||||||
@ -1742,8 +1735,20 @@ fn parse_binary_op<'a>(
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Token::Period => {
|
Token::Period => {
|
||||||
let rhs = args.pop().unwrap();
|
let mut rhs = args.pop().unwrap();
|
||||||
let current_lhs = args.pop().unwrap();
|
let current_lhs = args.pop().unwrap();
|
||||||
|
|
||||||
|
match &mut rhs {
|
||||||
|
// current_lhs.rhs(...) - method call
|
||||||
|
Expr::FnCall(x) => {
|
||||||
|
let ((id, _), _, hash, args, _) = x.as_mut();
|
||||||
|
// Recalculate function call hash because there is an additional argument
|
||||||
|
let args_iter = repeat(EMPTY_TYPE_ID()).take(args.len() + 1);
|
||||||
|
*hash = calc_fn_hash(empty(), id, args_iter);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
make_dot_expr(current_lhs, rhs, pos, false)?
|
make_dot_expr(current_lhs, rhs, pos, false)?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
25
tests/functions.rs
Normal file
25
tests/functions.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#![cfg(not(feature = "no_function"))]
|
||||||
|
use rhai::{Engine, EvalAltResult, Func, ParseErrorType, Scope, INT};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_functions() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
let engine = Engine::new();
|
||||||
|
|
||||||
|
assert_eq!(engine.eval::<i64>("fn add(x, n) { x + n } add(40, 2)")?, 42);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<i64>("fn add(x, n) { x + n } let x = 40; x.add(2)")?,
|
||||||
|
42
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(engine.eval::<i64>("fn mul2(x) { x * 2 } mul2(21)")?, 42);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<i64>("fn mul2(x) { x * 2 } let x = 21; x.mul2()")?,
|
||||||
|
42
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -10,8 +10,8 @@ fn test_method_call() -> Result<(), Box<EvalAltResult>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TestStruct {
|
impl TestStruct {
|
||||||
fn update(&mut self) {
|
fn update(&mut self, n: INT) {
|
||||||
self.x += 1000;
|
self.x += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
@ -27,12 +27,12 @@ fn test_method_call() -> Result<(), Box<EvalAltResult>> {
|
|||||||
engine.register_fn("new_ts", TestStruct::new);
|
engine.register_fn("new_ts", TestStruct::new);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<TestStruct>("let x = new_ts(); x.update(); x")?,
|
engine.eval::<TestStruct>("let x = new_ts(); x.update(1000); x")?,
|
||||||
TestStruct { x: 1001 }
|
TestStruct { x: 1001 }
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<TestStruct>("let x = new_ts(); update(x); x")?,
|
engine.eval::<TestStruct>("let x = new_ts(); update(x, 1000); x")?,
|
||||||
TestStruct { x: 1 }
|
TestStruct { x: 1 }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user