From 8d0623d07f8b100f6e26d7489fbb7be9bbabf40c Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 31 Jul 2020 18:43:34 +0800 Subject: [PATCH] Add is_shared function. --- doc/src/appendix/keywords.md | 1 + doc/src/language/keywords.md | 3 +-- src/engine.rs | 5 +++-- src/fn_call.rs | 19 +++++++++++++++++-- src/token.rs | 28 +++++++++++----------------- tests/shared.rs | 5 +++++ 6 files changed, 38 insertions(+), 23 deletions(-) diff --git a/doc/src/appendix/keywords.md b/doc/src/appendix/keywords.md index 8aee03b1..a1e20fed 100644 --- a/doc/src/appendix/keywords.md +++ b/doc/src/appendix/keywords.md @@ -9,6 +9,7 @@ Keywords List | `false` | Boolean false literal | | No | | `let` | Variable declaration | | No | | `const` | Constant declaration | | No | +| `is_shared` | Is a value shared? | | No | | `shared` | Share value | [`no_shared`] | No | | `take` | Un-share value | [`no_shared`] | No | | `if` | If statement | | No | diff --git a/doc/src/language/keywords.md b/doc/src/language/keywords.md index a5142007..0683386e 100644 --- a/doc/src/language/keywords.md +++ b/doc/src/language/keywords.md @@ -9,7 +9,7 @@ The following are reserved keywords in Rhai: | ------------------------------------------------- | ------------------------------------------------ | --------------------- | :--------------------: | | `true`, `false` | | Boolean constants | | | `let`, `const` | `var`, `static` | Variable declarations | | -| `shared`, `take` | | Shared values | [`no_shared`] | +| `shared`, `take`, `is_shared` | | Shared values | [`no_shared`] | | `if`, `else` | `then`, `goto`, `exit` | Control flow | | | | `switch`, `match`, `case` | Matching | | | `while`, `loop`, `for`, `in`, `continue`, `break` | `do`, `each` | Looping | | @@ -23,4 +23,3 @@ The following are reserved keywords in Rhai: | | `default`, `void`, `null`, `nil` | Special values | | Keywords cannot become the name of a [function] or [variable], even when they are disabled. - diff --git a/src/engine.rs b/src/engine.rs index f9017d96..bd778e4e 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -99,6 +99,7 @@ pub const KEYWORD_FN_PTR_CALL: &str = "call"; pub const KEYWORD_FN_PTR_CURRY: &str = "curry"; pub const KEYWORD_SHARED: &str = "shared"; pub const KEYWORD_TAKE: &str = "take"; +pub const KEYWORD_IS_SHARED: &str = "is_shared"; pub const KEYWORD_THIS: &str = "this"; pub const FN_TO_STRING: &str = "to_string"; #[cfg(not(feature = "no_object"))] @@ -181,10 +182,10 @@ impl Target<'_> { /// Get the value of the `Target` as a `Dynamic`, cloning a referenced value if necessary. pub fn clone_into_dynamic(self) -> Dynamic { match self { - Self::Ref(r) => r.clone(), // Referenced value is cloned + Self::Ref(r) => r.clone(), // Referenced value is cloned #[cfg(not(feature = "no_shared"))] Self::LockGuard((_, orig)) => orig, // Original value is simply taken - Self::Value(v) => v, // Owned value is simply taken + Self::Value(v) => v, // Owned value is simply taken #[cfg(not(feature = "no_index"))] Self::StringChar(_, _, ch) => ch, // Character is taken } diff --git a/src/fn_call.rs b/src/fn_call.rs index 6015d59f..d680800a 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -4,8 +4,8 @@ use crate::any::Dynamic; use crate::calc_fn_hash; use crate::engine::{ search_imports, search_namespace, search_scope_only, Engine, Imports, State, KEYWORD_DEBUG, - KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_PRINT, - KEYWORD_SHARED, KEYWORD_TAKE, KEYWORD_TYPE_OF, + KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_SHARED, + KEYWORD_PRINT, KEYWORD_SHARED, KEYWORD_TAKE, KEYWORD_TYPE_OF, }; use crate::error::ParseErrorType; use crate::fn_native::{FnCallArgs, FnPtr}; @@ -451,6 +451,12 @@ impl Engine { ))) } + // Fn + KEYWORD_IS_SHARED if args.len() == 1 => Err(Box::new(EvalAltResult::ErrorRuntime( + "'is_shared' should not be called in method style. Try is_shared(...);".into(), + Position::none(), + ))), + // eval - reaching this point it must be a method-style call KEYWORD_EVAL if args.len() == 1 && !self.has_override(lib, hash_fn, hash_script, pub_only) => @@ -783,6 +789,15 @@ impl Engine { .into()); } + // Handle is_shared() + #[cfg(not(feature = "no_shared"))] + if name == KEYWORD_IS_SHARED && args_expr.len() == 1 { + let expr = args_expr.get(0).unwrap(); + let value = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?; + + return Ok(value.is_shared().into()); + } + // Handle shared() #[cfg(not(feature = "no_shared"))] if name == KEYWORD_SHARED && args_expr.len() == 1 { diff --git a/src/token.rs b/src/token.rs index 571ddf10..dfd50c27 100644 --- a/src/token.rs +++ b/src/token.rs @@ -2,7 +2,7 @@ use crate::engine::{ Engine, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, - KEYWORD_PRINT, KEYWORD_SHARED, KEYWORD_TAKE, KEYWORD_THIS, KEYWORD_TYPE_OF, + KEYWORD_IS_SHARED, KEYWORD_PRINT, KEYWORD_SHARED, KEYWORD_TAKE, KEYWORD_THIS, KEYWORD_TYPE_OF, }; use crate::error::LexError; @@ -1431,28 +1431,22 @@ fn get_identifier( /// Is this keyword allowed as a function? #[inline(always)] pub fn is_keyword_function(name: &str) -> bool { - #[cfg(not(feature = "no_shared"))] - if name == KEYWORD_SHARED || name == KEYWORD_TAKE { - return true; + match name { + #[cfg(not(feature = "no_shared"))] + KEYWORD_SHARED | KEYWORD_TAKE | KEYWORD_IS_SHARED => true, + KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR + | KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY => true, + _ => false, } - - name == KEYWORD_PRINT - || name == KEYWORD_DEBUG - || name == KEYWORD_TYPE_OF - || name == KEYWORD_EVAL - || name == KEYWORD_FN_PTR - || name == KEYWORD_FN_PTR_CALL - || name == KEYWORD_FN_PTR_CURRY } /// Can this keyword be overridden as a function? #[inline(always)] pub fn can_override_keyword(name: &str) -> bool { - name == KEYWORD_PRINT - || name == KEYWORD_DEBUG - || name == KEYWORD_TYPE_OF - || name == KEYWORD_EVAL - || name == KEYWORD_FN_PTR + match name { + KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR => true, + _ => false, + } } pub fn is_valid_identifier(name: impl Iterator) -> bool { diff --git a/tests/shared.rs b/tests/shared.rs index e35de3d0..7cd7af86 100644 --- a/tests/shared.rs +++ b/tests/shared.rs @@ -18,6 +18,11 @@ fn test_shared() -> Result<(), Box> { assert_eq!(engine.eval::("shared('x')")?, 'x'); + assert!(engine.eval::("is_shared(shared(42))")?); + + #[cfg(not(feature = "no_object"))] + assert!(engine.eval::("shared(42).is_shared()")?); + #[cfg(not(feature = "no_index"))] { assert_eq!(