commit
3c40c302d1
@ -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
|
||||||
|
|
||||||
|
@ -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"]
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user