diff --git a/src/any.rs b/src/any.rs index 7990ff10..db2ada1b 100644 --- a/src/any.rs +++ b/src/any.rs @@ -1031,7 +1031,7 @@ impl Dynamic { _ => Err(cell.value_type_name), } #[cfg(feature = "sync")] - match &cell.container.read().deref().0 { + match &cell.container.read().unwrap().deref().0 { Union::Str(s) => Ok(s.clone()), Union::FnPtr(f) => Ok(f.clone().take_data().0), _ => Err(cell.value_type_name), diff --git a/src/parser.rs b/src/parser.rs index 2128f38c..1d9f26dd 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2182,12 +2182,9 @@ fn parse_binary_op( let (op_token, pos) = input.next().unwrap(); - let next = input.peek().unwrap(); - let next_precedence = next.0.precedence(custom); - #[cfg(any(not(feature = "no_object"), not(feature = "no_capture")))] if op_token == Token::Period { - if let (Token::Identifier(_), _) = next { + if let (Token::Identifier(_), _) = input.peek().unwrap() { // prevents capturing of the object properties as vars: xxx. state.capture = false; } @@ -2195,6 +2192,8 @@ fn parse_binary_op( let rhs = parse_unary(input, state, lib, settings)?; + let next_precedence = input.peek().unwrap().0.precedence(custom); + // Bind to right if the next operator has higher precedence // If same precedence, then check if the operator binds right let rhs = if (precedence == next_precedence && bind_right) || precedence < next_precedence { diff --git a/tests/closures.rs b/tests/closures.rs index ae0c6535..25166ee1 100644 --- a/tests/closures.rs +++ b/tests/closures.rs @@ -1,5 +1,5 @@ #![cfg(not(feature = "no_function"))] -use rhai::{Dynamic, Engine, EvalAltResult, FnPtr, Module, INT, Array}; +use rhai::{Dynamic, Engine, EvalAltResult, RegisterFn, FnPtr, Module, INT, Array}; use std::any::{TypeId, Any}; #[test] @@ -62,146 +62,241 @@ fn test_closures() -> Result<(), Box> { #[test] #[cfg(not(feature = "no_shared"))] fn test_shared() -> Result<(), Box> { - let engine = Engine::new(); + let mut engine = Engine::new(); - // assert_eq!( - // engine.eval::( - // r#" - // shared(42) - // "# - // )?, - // 42 - // ); - // - // assert_eq!( - // engine.eval::( - // r#" - // shared(true) - // "# - // )?, - // true - // ); - // - // #[cfg(not(feature = "no_float"))] - // assert_eq!( - // engine.eval::( - // r#" - // shared(4.2) - // "# - // )?, - // 4.2 - // ); - // - // assert_eq!( - // engine.eval::( - // r#" - // shared("test") - // "# - // )?, - // "test" - // ); - // - // #[cfg(not(feature = "no_index"))] - // { - // assert_eq!( - // engine.eval::( - // r#" - // let x = shared([1, 2, 3]); - // let y = shared([4, 5]); - // x + y - // "# - // )?.len(), - // 5 - // ); - // - // assert_eq!( - // engine.eval::( - // r" - // let x = shared([2, 9]); - // x.insert(-1, 1); - // x.insert(999, 3); - // - // let r = x.remove(2); - // - // let y = shared([4, 5]); - // x.append(y); - // - // x.len + r - // " - // )?, - // 14 - // ); - // - // assert_eq!( - // engine.eval::( - // r#" - // let x = shared([1, 2, 3]); - // - // if x[0] + x[2] == 4 { - // true - // } else { - // false - // } - // "# - // )?, - // true - // ); - // } - // - // #[cfg(not(feature = "no_object"))] - // assert_eq!( - // engine.eval::(r#" - // let y = shared(#{a: 1, b: 2, c: 3}); - // y.c = shared(5); - // y.c - // "#)?, - // 5 - // ); - // - // #[cfg(not(feature = "no_object"))] - // assert_eq!( - // engine.eval::(r#" - // let y = shared(#{a: 1, b: 2, c: shared(3)}); - // let c = y.c; - // c = 5;// "c" still holds Dynamic Shared - // y.c - // "#)?, - // 5 - // ); - // - // #[cfg(not(feature = "no_capture"))] - // assert_eq!( - // engine.eval::(r#" - // let x = shared(1); - // (|| x = x + 41).call(); - // x - // "#)?, - // 42 - // ); + assert_eq!( + engine.eval::( + r#" + shared(42) + "# + )?, + 42 + ); - #[cfg(all(not(feature = "no_object"), not(feature = "no_capture")))] + assert_eq!( + engine.eval::( + r#" + shared(true) + "# + )?, + true + ); + + #[cfg(not(feature = "no_float"))] + assert_eq!( + engine.eval::( + r#" + shared(4.2) + "# + )?, + 4.2 + ); + + assert_eq!( + engine.eval::( + r#" + shared("test") + "# + )?, + "test" + ); + + assert_eq!( + engine.eval::( + r#" + shared('x') + "# + )?, + 'x' + ); + + assert_eq!( + engine.eval::( + r#" + let s = shared("test"); + let i = shared(0); + i = 2; + + s[i] = 'S'; + s + "# + )?, + "teSt" + ); + + #[cfg(not(feature = "no_index"))] + { + assert_eq!( + engine.eval::( + r#" + let x = shared([1, 2, 3]); + let y = shared([4, 5]); + x + y + "# + )?.len(), + 5 + ); + + assert_eq!( + engine.eval::( + r" + let x = shared([2, 9]); + x.insert(-1, 1); + x.insert(999, 3); + + let r = x.remove(2); + + let y = shared([4, 5]); + x.append(y); + + x.len + r + " + )?, + 14 + ); + + assert_eq!( + engine.eval::( + r#" + let x = shared([1, 2, 3]); + + if x[0] + x[2] == 4 { + true + } else { + false + } + "# + )?, + true + ); + + assert_eq!( + engine.eval::( + r#" + let x = shared([1, 2, 3]); + let y = shared(()); + + (|| { + for i in x { + y = i * 10; + } + }).call(); + + y + "# + )?, + 30 + ); + } + + #[cfg(not(feature = "no_object"))] assert_eq!( engine.eval::(r#" - // let x = shared(#{a: 1, b: shared(2), c: 3}); - // let a = x.a; - // let b = x.b; - // a = 100; - // b = 20; - // - // let f = |a| { - // x.c = x.a + x.b;// + a; - // }; - // - // f.call(20); - // - // x.c + let y = shared(#{a: 1, b: 2, c: 3}); + y.c = shared(5); + y.c + "#)?, + 5 + ); - let x = #{a: 1, b: 2}; + #[cfg(not(feature = "no_object"))] + assert_eq!( + engine.eval::(r#" + let y = shared(#{a: 1, b: 2, c: shared(3)}); + let c = y.c; + c = 5;// "c" holds Dynamic Shared + y.c + "#)?, + 5 + ); - x.a + x.b + #[cfg(not(feature = "no_capture"))] + assert_eq!( + engine.eval::(r#" + let x = shared(1); + (|| x = x + 41).call(); + x "#)?, 42 ); + #[cfg(all(not(feature = "no_object"), not(feature = "no_capture")))] + assert_eq!( + engine.eval::(r#" + let x = shared(#{a: 1, b: shared(2), c: 3}); + let a = x.a; + let b = x.b; + a = 100; // does not hold reference to x.a + b = 20; // does hold reference to x.b + + let f = |a| { + x.c = x.a + x.b + a; + }; + + f.call(21); + + x.c + "#)?, + 42 + ); + + // Register a binary function named `foo` + engine.register_fn("custom_addition", |x: INT, y: INT| x + y); + + assert_eq!( + engine.eval::(r#" + custom_addition(shared(20), shared(22)) + "#)?, + 42 + ); + + #[derive(Clone)] + struct TestStruct { + x: INT, + } + + impl TestStruct { + fn update(&mut self) { + self.x += 1000; + } + + fn merge(&mut self, other: Self) { + self.x += other.x; + } + + fn get_x(&mut self) -> INT { + self.x + } + + fn set_x(&mut self, new_x: INT) { + self.x = new_x; + } + + fn new() -> Self { + TestStruct { x: 1 } + } + } + + engine.register_type::(); + + engine.register_get_set("x", TestStruct::get_x, TestStruct::set_x); + engine.register_fn("update", TestStruct::update); + engine.register_fn("merge", TestStruct::merge); + engine.register_fn("new_ts", TestStruct::new); + + assert_eq!( + engine.eval::( + r" + let a = shared(new_ts()); + + a.x = 100; + a.update(); + // a.merge(a); + a.x + " + )?, + 1100 + ); + Ok(()) }