Merge pull request #458 from schungx/master

Version 1.1.0
This commit is contained in:
Stephen Chung 2021-10-11 17:43:34 +08:00 committed by GitHub
commit 3c40c302d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 55 additions and 55 deletions

View File

@ -44,6 +44,7 @@ Enhancements
* `SmartString` now uses `LazyCompact` instead of `Compact` to minimize allocations. * `SmartString` now uses `LazyCompact` instead of `Compact` to minimize allocations.
* Added `pop` for strings. * Added `pop` for strings.
* Added `ImmutableString::ptr_eq` to test if two strings point to the same allocation. * Added `ImmutableString::ptr_eq` to test if two strings point to the same allocation.
* The `serde` feature of `SmartString` is turned on under `metadata` to make `Map` serializable.
### `Scope` API ### `Scope` API

View File

@ -40,7 +40,7 @@ no_closure = [] # no automatic sharing and capture of anonymous
no_module = [] # no modules no_module = [] # no modules
internals = [] # expose internal data structures internals = [] # expose internal data structures
unicode-xid-ident = ["unicode-xid"] # allow Unicode Standard Annex #31 for identifiers. unicode-xid-ident = ["unicode-xid"] # allow Unicode Standard Annex #31 for identifiers.
metadata = ["serde", "serde_json", "rhai_codegen/metadata"] # enable exporting functions metadata metadata = ["serde", "serde_json", "rhai_codegen/metadata", "smartstring/serde"] # enable exporting functions metadata
no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "ahash/compile-time-rng"] no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "ahash/compile-time-rng"]

View File

@ -79,8 +79,8 @@ The [`scripts`](https://github.com/rhaiscript/rhai/tree/master/scripts) subdirec
Below is the standard _Fibonacci_ example for scripting languages: Below is the standard _Fibonacci_ example for scripting languages:
```js ```js
// This Rhai script calculates the n-th Fibonacci number using a really dumb algorithm // This Rhai script calculates the n-th Fibonacci number using a
// to test the speed of the scripting engine. // really dumb algorithm to test the speed of the scripting engine.
const TARGET = 28; const TARGET = 28;
const REPEAT = 5; const REPEAT = 5;

View File

@ -3,7 +3,7 @@
use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, Stmt, AST_OPTION_FLAGS::*}; use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, Stmt, AST_OPTION_FLAGS::*};
use crate::custom_syntax::CustomSyntax; use crate::custom_syntax::CustomSyntax;
use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant}; use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant};
use crate::fn_hash::{calc_fn_hash, get_hasher}; use crate::fn_hash::get_hasher;
use crate::fn_native::{ use crate::fn_native::{
CallableFunction, IteratorFn, OnDebugCallback, OnParseTokenCallback, OnPrintCallback, CallableFunction, IteratorFn, OnDebugCallback, OnParseTokenCallback, OnPrintCallback,
OnVarCallback, OnVarCallback,
@ -682,6 +682,9 @@ pub struct EvalState {
/// Embedded module resolver. /// Embedded module resolver.
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
pub embedded_module_resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>, pub embedded_module_resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>,
/// Function call hashes to FN_IDX_GET and FN_IDX_SET
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
fn_hash_indexing: (u64, u64),
} }
impl EvalState { impl EvalState {
@ -698,6 +701,8 @@ impl EvalState {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
embedded_module_resolver: None, embedded_module_resolver: None,
fn_resolution_caches: StaticVec::new(), fn_resolution_caches: StaticVec::new(),
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
fn_hash_indexing: (0, 0),
} }
} }
/// Is the state currently at global (root) level? /// Is the state currently at global (root) level?
@ -735,6 +740,32 @@ impl EvalState {
.pop() .pop()
.expect("at least one function resolution cache"); .expect("at least one function resolution cache");
} }
/// Get the pre-calculated index getter hash.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[must_use]
pub fn fn_hash_idx_get(&mut self) -> u64 {
if self.fn_hash_indexing != (0, 0) {
self.fn_hash_indexing.0
} else {
let n1 = crate::calc_fn_hash(FN_IDX_GET, 2);
let n2 = crate::calc_fn_hash(FN_IDX_SET, 3);
self.fn_hash_indexing = (n1, n2);
n1
}
}
/// Get the pre-calculated index setter hash.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[must_use]
pub fn fn_hash_idx_set(&mut self) -> u64 {
if self.fn_hash_indexing != (0, 0) {
self.fn_hash_indexing.1
} else {
let n1 = crate::calc_fn_hash(FN_IDX_GET, 2);
let n2 = crate::calc_fn_hash(FN_IDX_SET, 3);
self.fn_hash_indexing = (n1, n2);
n2
}
}
} }
/// _(internals)_ A type containing all the limits imposed by the [`Engine`]. /// _(internals)_ A type containing all the limits imposed by the [`Engine`].
@ -804,31 +835,6 @@ impl Default for Limits {
} }
} }
/// A type containing useful constants for the [`Engine`].
#[derive(Debug)]
pub struct GlobalConstants {
/// An empty [`ImmutableString`] for cloning purposes.
pub(crate) empty_string: ImmutableString,
/// Function call hash to FN_IDX_GET
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
pub(crate) fn_hash_idx_get: u64,
/// Function call hash to FN_IDX_SET
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
pub(crate) fn_hash_idx_set: u64,
}
impl Default for GlobalConstants {
fn default() -> Self {
Self {
empty_string: Default::default(),
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
fn_hash_idx_get: calc_fn_hash(FN_IDX_GET, 2),
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
fn_hash_idx_set: calc_fn_hash(FN_IDX_SET, 3),
}
}
}
/// Context of a script evaluation process. /// Context of a script evaluation process.
#[derive(Debug)] #[derive(Debug)]
pub struct EvalContext<'a, 'x, 'px, 'm, 's, 'b, 't, 'pt> { pub struct EvalContext<'a, 'x, 'px, 'm, 's, 'b, 't, 'pt> {
@ -950,8 +956,8 @@ pub struct Engine {
/// A map mapping type names to pretty-print names. /// A map mapping type names to pretty-print names.
pub(crate) type_names: BTreeMap<Identifier, Box<Identifier>>, pub(crate) type_names: BTreeMap<Identifier, Box<Identifier>>,
/// Useful constants /// An empty [`ImmutableString`] for cloning purposes.
pub(crate) constants: GlobalConstants, pub(crate) empty_string: ImmutableString,
/// A set of symbols to disable. /// A set of symbols to disable.
pub(crate) disabled_symbols: BTreeSet<Identifier>, pub(crate) disabled_symbols: BTreeSet<Identifier>,
@ -1081,7 +1087,7 @@ impl Engine {
module_resolver: None, module_resolver: None,
type_names: Default::default(), type_names: Default::default(),
constants: Default::default(), empty_string: Default::default(),
disabled_symbols: Default::default(), disabled_symbols: Default::default(),
custom_keywords: Default::default(), custom_keywords: Default::default(),
custom_syntax: Default::default(), custom_syntax: Default::default(),
@ -1116,7 +1122,7 @@ impl Engine {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn const_empty_string(&self) -> ImmutableString { pub fn const_empty_string(&self) -> ImmutableString {
self.constants.empty_string.clone() self.empty_string.clone()
} }
/// Search for a module within an imports stack. /// Search for a module within an imports stack.
@ -1328,8 +1334,7 @@ impl Engine {
if let Some(mut new_val) = try_setter { if let Some(mut new_val) = try_setter {
// Try to call index setter if value is changed // Try to call index setter if value is changed
let hash_set = let hash_set = FnCallHashes::from_native(state.fn_hash_idx_set());
FnCallHashes::from_native(self.constants.fn_hash_idx_set);
let args = &mut [target, &mut idx_val_for_setter, &mut new_val]; let args = &mut [target, &mut idx_val_for_setter, &mut new_val];
if let Err(err) = self.exec_fn_call( if let Err(err) = self.exec_fn_call(
@ -1376,8 +1381,7 @@ impl Engine {
if let Some(mut new_val) = try_setter { if let Some(mut new_val) = try_setter {
// Try to call index setter // Try to call index setter
let hash_set = let hash_set = FnCallHashes::from_native(state.fn_hash_idx_set());
FnCallHashes::from_native(self.constants.fn_hash_idx_set);
let args = &mut [target, &mut idx_val_for_setter, &mut new_val]; let args = &mut [target, &mut idx_val_for_setter, &mut new_val];
self.exec_fn_call( self.exec_fn_call(
@ -1508,8 +1512,7 @@ impl Engine {
// Try an indexer if property does not exist // Try an indexer if property does not exist
EvalAltResult::ErrorDotExpr(_, _) => { EvalAltResult::ErrorDotExpr(_, _) => {
let args = &mut [target, &mut name.into(), &mut new_val]; let args = &mut [target, &mut name.into(), &mut new_val];
let hash_set = let hash_set = FnCallHashes::from_native(state.fn_hash_idx_set());
FnCallHashes::from_native(self.constants.fn_hash_idx_set);
let pos = Position::NONE; let pos = Position::NONE;
self.exec_fn_call( self.exec_fn_call(
@ -1668,7 +1671,7 @@ impl Engine {
let args = let args =
&mut [target.as_mut(), &mut name.into(), val]; &mut [target.as_mut(), &mut name.into(), val];
let hash_set = FnCallHashes::from_native( let hash_set = FnCallHashes::from_native(
self.constants.fn_hash_idx_set, state.fn_hash_idx_set(),
); );
self.exec_fn_call( self.exec_fn_call(
mods, state, lib, FN_IDX_SET, hash_set, args, mods, state, lib, FN_IDX_SET, hash_set, args,
@ -1956,12 +1959,11 @@ impl Engine {
- index - index
.checked_abs() .checked_abs()
.ok_or_else(|| { .ok_or_else(|| {
Box::new(EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos)) EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos).into()
}) })
.and_then(|n| { .and_then(|n| {
if n as usize > arr_len { if n as usize > arr_len {
Err(EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos) EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos).into()
.into())
} else { } else {
Ok(n as usize) Ok(n as usize)
} }
@ -2072,7 +2074,7 @@ impl Engine {
_ if use_indexers => { _ if use_indexers => {
let args = &mut [target, &mut idx]; let args = &mut [target, &mut idx];
let hash_get = FnCallHashes::from_native(self.constants.fn_hash_idx_get); let hash_get = FnCallHashes::from_native(state.fn_hash_idx_get());
let idx_pos = Position::NONE; let idx_pos = Position::NONE;
self.exec_fn_call( self.exec_fn_call(
@ -3096,7 +3098,7 @@ impl Engine {
// Concentrate all empty strings into one instance to save memory // Concentrate all empty strings into one instance to save memory
if let Dynamic(crate::dynamic::Union::Str(s, _, _)) = r { if let Dynamic(crate::dynamic::Union::Str(s, _, _)) = r {
if s.is_empty() { if s.is_empty() {
if !s.ptr_eq(&self.constants.empty_string) { if !s.ptr_eq(&self.empty_string) {
*s = self.const_empty_string(); *s = self.const_empty_string();
} }
return result; return result;

View File

@ -225,10 +225,7 @@ impl<T: AsRef<str>> From<T> for EvalAltResult {
impl<T: AsRef<str>> From<T> for Box<EvalAltResult> { impl<T: AsRef<str>> From<T> for Box<EvalAltResult> {
#[inline(always)] #[inline(always)]
fn from(err: T) -> Self { fn from(err: T) -> Self {
Box::new(EvalAltResult::ErrorRuntime( EvalAltResult::ErrorRuntime(err.as_ref().to_string().into(), Position::NONE).into()
err.as_ref().to_string().into(),
Position::NONE,
))
} }
} }

View File

@ -681,12 +681,12 @@ impl Engine {
return Ok(( return Ok((
if num_params < 0 { if num_params < 0 {
Dynamic::FALSE false
} else { } else {
let hash_script = calc_fn_hash(fn_name.as_str(), num_params as usize); let hash_script = calc_fn_hash(fn_name.as_str(), num_params as usize);
self.has_script_fn(Some(mods), state, lib, hash_script) self.has_script_fn(Some(mods), state, lib, hash_script)
.into() }
}, .into(),
false, false,
)); ));
} }
@ -1189,12 +1189,12 @@ impl Engine {
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, arg_pos))?; .map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, arg_pos))?;
return Ok(if num_params < 0 { return Ok(if num_params < 0 {
Dynamic::FALSE false
} else { } else {
let hash_script = calc_fn_hash(&fn_name, num_params as usize); let hash_script = calc_fn_hash(&fn_name, num_params as usize);
self.has_script_fn(Some(mods), state, lib, hash_script) self.has_script_fn(Some(mods), state, lib, hash_script)
.into() }
}); .into());
} }
// Handle is_def_var() // Handle is_def_var()