commit
7881f2bde2
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
@ -32,6 +32,7 @@ jobs:
|
||||
- "--features no_module"
|
||||
- "--features no_closure"
|
||||
- "--features unicode-xid-ident"
|
||||
- "--features sync,no_function,no_float,no_optimize,no_module,no_closure,serde,unchecked"
|
||||
toolchain: [stable]
|
||||
experimental: [false]
|
||||
include:
|
||||
|
@ -6,7 +6,7 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "rhai"
|
||||
version = "0.19.6"
|
||||
version = "0.19.7"
|
||||
edition = "2018"
|
||||
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"]
|
||||
description = "Embedded scripting for Rust"
|
||||
|
@ -1,6 +1,10 @@
|
||||
Rhai Release Notes
|
||||
==================
|
||||
|
||||
Version 0.19.7
|
||||
==============
|
||||
|
||||
|
||||
Version 0.19.6
|
||||
==============
|
||||
|
||||
@ -45,6 +49,7 @@ Enhancements
|
||||
------------
|
||||
|
||||
* New constants under `Dynamic` including `UNIT`, `TRUE`, `FALSE`, `ZERO`, `ONE` etc.
|
||||
* Floating-point numbers ending with a decimal point without a trailing `0` are supported.
|
||||
|
||||
|
||||
Version 0.19.5
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "0.19.6",
|
||||
"version": "0.19.7",
|
||||
"repoHome": "https://github.com/jonathandturner/rhai/blob/master",
|
||||
"repoTree": "https://github.com/jonathandturner/rhai/tree/master",
|
||||
"rootUrl": "",
|
||||
|
33
src/ast.rs
33
src/ast.rs
@ -41,7 +41,7 @@ pub enum FnAccess {
|
||||
}
|
||||
|
||||
impl FnAccess {
|
||||
/// Is this access mode private?
|
||||
/// Is this access mode [private][FnAccess::Private]?
|
||||
#[inline(always)]
|
||||
pub fn is_private(self) -> bool {
|
||||
match self {
|
||||
@ -49,7 +49,7 @@ impl FnAccess {
|
||||
Self::Public => false,
|
||||
}
|
||||
}
|
||||
/// Is this access mode public?
|
||||
/// Is this access mode [public][FnAccess::Public]?
|
||||
#[inline(always)]
|
||||
pub fn is_public(self) -> bool {
|
||||
match self {
|
||||
@ -151,6 +151,7 @@ impl AST {
|
||||
&mut self.0
|
||||
}
|
||||
/// Get the internal shared [`Module`] containing all script-defined functions.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[inline(always)]
|
||||
pub(crate) fn shared_lib(&self) -> Shared<Module> {
|
||||
@ -482,7 +483,7 @@ impl AST {
|
||||
#[inline(always)]
|
||||
pub fn iter_functions<'a>(
|
||||
&'a self,
|
||||
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize, Shared<ScriptFnDef>)> + 'a {
|
||||
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize, &ScriptFnDef)> + 'a {
|
||||
self.1.iter_script_fn()
|
||||
}
|
||||
/// Clear all function definitions in the [`AST`].
|
||||
@ -528,7 +529,12 @@ impl AsRef<Module> for AST {
|
||||
}
|
||||
}
|
||||
|
||||
/// An identifier containing a string name and a position.
|
||||
/// _(INTERNALS)_ An identifier containing a [string][String] name and a [position][Position].
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// ## WARNING
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct Ident {
|
||||
pub name: String,
|
||||
@ -542,7 +548,12 @@ impl Ident {
|
||||
}
|
||||
}
|
||||
|
||||
/// An identifier containing an immutable name and a position.
|
||||
/// _(INTERNALS)_ An identifier containing an [immutable string][ImmutableString] name and a [position][Position].
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// ## WARNING
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct IdentX {
|
||||
pub name: ImmutableString,
|
||||
@ -650,7 +661,7 @@ impl Stmt {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
/// Get the [`Position`] of this statement.
|
||||
/// Get the [position][`Position`] of this statement.
|
||||
pub fn position(&self) -> Position {
|
||||
match self {
|
||||
Self::Noop(pos)
|
||||
@ -679,7 +690,7 @@ impl Stmt {
|
||||
Self::Share(x) => x.pos,
|
||||
}
|
||||
}
|
||||
/// Override the [`Position`] of this statement.
|
||||
/// Override the [position][`Position`] of this statement.
|
||||
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
|
||||
match self {
|
||||
Self::Noop(pos)
|
||||
@ -742,6 +753,8 @@ impl Stmt {
|
||||
}
|
||||
}
|
||||
/// Is this statement _pure_?
|
||||
///
|
||||
/// A pure statement has no side effects.
|
||||
pub fn is_pure(&self) -> bool {
|
||||
match self {
|
||||
Self::Noop(_) => true,
|
||||
@ -967,7 +980,7 @@ impl Expr {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
/// Get the [`Position`] of the expression.
|
||||
/// Get the [position][`Position`] of the expression.
|
||||
pub fn position(&self) -> Position {
|
||||
match self {
|
||||
Self::Expr(x) => x.position(),
|
||||
@ -997,7 +1010,7 @@ impl Expr {
|
||||
Self::Custom(_, pos) => *pos,
|
||||
}
|
||||
}
|
||||
/// Override the [`Position`] of the expression.
|
||||
/// Override the [position][`Position`] of the expression.
|
||||
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
|
||||
match self {
|
||||
Self::Expr(x) => {
|
||||
@ -1089,7 +1102,7 @@ impl Expr {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
/// Is a particular token allowed as a postfix operator to this expression?
|
||||
/// Is a particular [token][Token] allowed as a postfix operator to this expression?
|
||||
pub fn is_valid_postfix(&self, token: &Token) -> bool {
|
||||
match self {
|
||||
Self::Expr(x) => x.is_valid_postfix(token),
|
||||
|
@ -43,7 +43,7 @@ mod private {
|
||||
/// Trait to represent any type.
|
||||
///
|
||||
/// Currently, [`Variant`] is not [`Send`] nor [`Sync`], so it can practically be any type.
|
||||
/// Turn on the [`Sync`] feature to restrict it to only types that implement [`Send`] `+` [`Sync`].
|
||||
/// Turn on the `sync` feature to restrict it to only types that implement [`Send`] `+` [`Sync`].
|
||||
#[cfg(not(feature = "sync"))]
|
||||
pub trait Variant: Any + private::Sealed {
|
||||
/// Convert this [`Variant`] trait object to [`&dyn Any`][Any].
|
||||
@ -268,7 +268,7 @@ impl Dynamic {
|
||||
///
|
||||
/// # Panics or Deadlocks When Value is Shared
|
||||
///
|
||||
/// Under the [`Sync`] feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
|
||||
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
|
||||
/// Otherwise, this call panics if the data is currently borrowed for write.
|
||||
pub fn type_id(&self) -> TypeId {
|
||||
match &self.0 {
|
||||
@ -301,7 +301,7 @@ impl Dynamic {
|
||||
///
|
||||
/// # Panics or Deadlocks When Value is Shared
|
||||
///
|
||||
/// Under the [`Sync`] feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
|
||||
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
|
||||
/// Otherwise, this call panics if the data is currently borrowed for write.
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
match &self.0 {
|
||||
@ -654,7 +654,7 @@ impl Dynamic {
|
||||
Self(Union::Variant(Box::new(boxed)))
|
||||
}
|
||||
/// Turn the [`Dynamic`] value into a shared [`Dynamic`] value backed by an [`Rc`][std::rc::Rc]`<`[`RefCell`][std::cell::RefCell]`<`[`Dynamic`]`>>`
|
||||
/// or [`Arc`][std::sync::Arc]`<`[`RwLock`][std::sync::RwLock]`<`[`Dynamic`]`>>` depending on the [`Sync`] feature.
|
||||
/// or [`Arc`][std::sync::Arc]`<`[`RwLock`][std::sync::RwLock]`<`[`Dynamic`]`>>` depending on the `sync` feature.
|
||||
///
|
||||
/// Shared [`Dynamic`] values are relatively cheap to clone as they simply increment the
|
||||
/// reference counts.
|
||||
@ -686,7 +686,7 @@ impl Dynamic {
|
||||
///
|
||||
/// # Panics or Deadlocks
|
||||
///
|
||||
/// Under the [`Sync`] feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
|
||||
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
|
||||
/// Otherwise, this call panics if the data is currently borrowed for write.
|
||||
///
|
||||
/// These normally shouldn't occur since most operations in Rhai is single-threaded.
|
||||
@ -819,7 +819,7 @@ impl Dynamic {
|
||||
/// Panics if the cast fails (e.g. the type of the actual value is not the
|
||||
/// same as the specified type).
|
||||
///
|
||||
/// Under the [`Sync`] feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
|
||||
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
|
||||
/// Otherwise, this call panics if the data is currently borrowed for write.
|
||||
///
|
||||
/// These normally shouldn't occur since most operations in Rhai is single-threaded.
|
||||
@ -900,7 +900,7 @@ impl Dynamic {
|
||||
///
|
||||
/// ## Note
|
||||
///
|
||||
/// Under the [`Sync`] feature, shared values use [`RwLock`][std::sync::RwLock] and they are never locked.
|
||||
/// Under the `sync` feature, shared values use [`RwLock`][std::sync::RwLock] and they are never locked.
|
||||
/// Access just waits until the [`RwLock`][std::sync::RwLock] is released.
|
||||
/// So this method always returns [`false`] under [`Sync`].
|
||||
#[inline(always)]
|
||||
@ -924,7 +924,7 @@ impl Dynamic {
|
||||
///
|
||||
/// # Panics or Deadlocks When Value is Shared
|
||||
///
|
||||
/// Under the [`Sync`] feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
|
||||
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
|
||||
/// Otherwise, this call panics if the data is currently borrowed for write.
|
||||
#[inline(always)]
|
||||
pub fn read_lock<T: Variant + Clone>(&self) -> Option<DynamicReadLock<T>> {
|
||||
@ -956,7 +956,7 @@ impl Dynamic {
|
||||
///
|
||||
/// # Panics or Deadlocks When Value is Shared
|
||||
///
|
||||
/// Under the [`Sync`] feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
|
||||
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
|
||||
/// Otherwise, this call panics if the data is currently borrowed for write.
|
||||
#[inline(always)]
|
||||
pub fn write_lock<T: Variant + Clone>(&mut self) -> Option<DynamicWriteLock<T>> {
|
||||
|
@ -40,7 +40,7 @@ use crate::Map;
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
pub const TYPICAL_MAP_SIZE: usize = 8; // Small maps are typical
|
||||
|
||||
/// _(INTERNALS)_ A stack of imported modules.
|
||||
/// _(INTERNALS)_ A stack of imported [modules][Module].
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// ## WARNING
|
||||
@ -49,21 +49,22 @@ pub const TYPICAL_MAP_SIZE: usize = 8; // Small maps are typical
|
||||
//
|
||||
// # Implementation Notes
|
||||
//
|
||||
// We cannot use &str or Cow<str> here because `eval` may load a module and the module name will live beyond
|
||||
// the AST of the eval script text. The best we can do is a shared reference.
|
||||
// We cannot use &str or Cow<str> here because `eval` may load a [module][Module] and
|
||||
// the module name will live beyond the AST of the eval script text.
|
||||
// The best we can do is a shared reference.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Imports(Option<StaticVec<(ImmutableString, Shared<Module>)>>);
|
||||
|
||||
impl Imports {
|
||||
/// Get the length of this stack of imported modules.
|
||||
/// Get the length of this stack of imported [modules][Module].
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.as_ref().map_or(0, StaticVec::len)
|
||||
}
|
||||
/// Is this stack of imported modules empty?
|
||||
/// Is this stack of imported [modules][Module] empty?
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.as_ref().map_or(true, StaticVec::is_empty)
|
||||
}
|
||||
/// Get the imported module at a particular index.
|
||||
/// Get the imported [modules][Module] at a particular index.
|
||||
pub fn get(&self, index: usize) -> Option<Shared<Module>> {
|
||||
self.0
|
||||
.as_ref()
|
||||
@ -71,7 +72,7 @@ impl Imports {
|
||||
.map(|(_, m)| m)
|
||||
.cloned()
|
||||
}
|
||||
/// Get the index of an imported module by name.
|
||||
/// Get the index of an imported [modules][Module] by name.
|
||||
pub fn find(&self, name: &str) -> Option<usize> {
|
||||
self.0.as_ref().and_then(|x| {
|
||||
x.iter()
|
||||
@ -81,7 +82,7 @@ impl Imports {
|
||||
.map(|(index, _)| index)
|
||||
})
|
||||
}
|
||||
/// Push an imported module onto the stack.
|
||||
/// Push an imported [modules][Module] onto the stack.
|
||||
pub fn push(&mut self, name: impl Into<ImmutableString>, module: impl Into<Shared<Module>>) {
|
||||
if self.0.is_none() {
|
||||
self.0 = Some(Default::default());
|
||||
@ -89,13 +90,13 @@ impl Imports {
|
||||
|
||||
self.0.as_mut().unwrap().push((name.into(), module.into()));
|
||||
}
|
||||
/// Truncate the stack of imported modules to a particular length.
|
||||
/// Truncate the stack of imported [modules][Module] to a particular length.
|
||||
pub fn truncate(&mut self, size: usize) {
|
||||
if self.0.is_some() {
|
||||
self.0.as_mut().unwrap().truncate(size);
|
||||
}
|
||||
}
|
||||
/// Get an iterator to this stack of imported modules in reverse order.
|
||||
/// Get an iterator to this stack of imported [modules][Module] in reverse order.
|
||||
#[allow(dead_code)]
|
||||
pub fn iter<'a>(&'a self) -> impl Iterator<Item = (ImmutableString, Shared<Module>)> + 'a {
|
||||
self.0.iter().flat_map(|lib| {
|
||||
@ -104,22 +105,22 @@ impl Imports {
|
||||
.map(|(name, module)| (name.clone(), module.clone()))
|
||||
})
|
||||
}
|
||||
/// Get an iterator to this stack of imported modules in reverse order.
|
||||
/// Get an iterator to this stack of imported [modules][Module] in reverse order.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn iter_raw<'a>(
|
||||
&'a self,
|
||||
) -> impl Iterator<Item = (ImmutableString, Shared<Module>)> + 'a {
|
||||
self.0.iter().flat_map(|lib| lib.iter().rev().cloned())
|
||||
}
|
||||
/// Get a consuming iterator to this stack of imported modules in reverse order.
|
||||
/// Get a consuming iterator to this stack of imported [modules][Module] in reverse order.
|
||||
pub fn into_iter(self) -> impl Iterator<Item = (ImmutableString, Shared<Module>)> {
|
||||
self.0.into_iter().flat_map(|lib| lib.into_iter().rev())
|
||||
}
|
||||
/// Add a stream of imported modules.
|
||||
/// Add a stream of imported [modules][Module].
|
||||
pub fn extend(&mut self, stream: impl Iterator<Item = (ImmutableString, Shared<Module>)>) {
|
||||
self.0.as_mut().unwrap().extend(stream)
|
||||
}
|
||||
/// Does the specified function hash key exist in this stack of imported modules?
|
||||
/// Does the specified function hash key exist in this stack of imported [modules][Module]?
|
||||
#[allow(dead_code)]
|
||||
pub fn contains_fn(&self, hash: u64) -> bool {
|
||||
self.0.as_ref().map_or(false, |x| {
|
||||
@ -132,14 +133,14 @@ impl Imports {
|
||||
.as_ref()
|
||||
.and_then(|x| x.iter().rev().find_map(|(_, m)| m.get_qualified_fn(hash)))
|
||||
}
|
||||
/// Does the specified TypeId iterator exist in this stack of imported modules?
|
||||
/// Does the specified [`TypeId`][std::any::TypeId] iterator exist in this stack of imported [modules][Module]?
|
||||
#[allow(dead_code)]
|
||||
pub fn contains_iter(&self, id: TypeId) -> bool {
|
||||
self.0.as_ref().map_or(false, |x| {
|
||||
x.iter().any(|(_, m)| m.contains_qualified_iter(id))
|
||||
})
|
||||
}
|
||||
/// Get the specified TypeId iterator.
|
||||
/// Get the specified [`TypeId`][std::any::TypeId] iterator.
|
||||
pub fn get_iter(&self, id: TypeId) -> Option<IteratorFn> {
|
||||
self.0
|
||||
.as_ref()
|
||||
@ -462,7 +463,7 @@ impl<T: Into<Dynamic>> From<T> for Target<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// _(INTERNALS)_ A type that holds all the current states of the Engine.
|
||||
/// _(INTERNALS)_ A type that holds all the current states of the [`Engine`].
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// ## WARNING
|
||||
@ -512,17 +513,17 @@ pub struct Limits {
|
||||
pub max_function_expr_depth: usize,
|
||||
/// Maximum number of operations allowed to run (0 = unlimited).
|
||||
pub max_operations: u64,
|
||||
/// Maximum number of modules allowed to load.
|
||||
/// Maximum number of [modules][Module] allowed to load.
|
||||
/// Not available under `no_module`.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
pub max_modules: usize,
|
||||
/// Maximum length of a string (0 = unlimited).
|
||||
/// Maximum length of a [string][ImmutableString] (0 = unlimited).
|
||||
pub max_string_size: usize,
|
||||
/// Maximum length of an array (0 = unlimited).
|
||||
/// Maximum length of an [array][Array] (0 = unlimited).
|
||||
/// Not available under `no_index`.
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
pub max_array_size: usize,
|
||||
/// Maximum number of properties in a map (0 = unlimited).
|
||||
/// Maximum number of properties in an [object map][Map] (0 = unlimited).
|
||||
/// Not available under `no_object`.
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
pub max_map_size: usize,
|
||||
@ -578,7 +579,7 @@ impl<'e, 'x, 'px, 'a, 's, 'm, 'pm, 't, 'pt> EvalContext<'e, 'x, 'px, 'a, 's, 'm,
|
||||
/// [`Engine`] is re-entrant.
|
||||
///
|
||||
/// Currently, [`Engine`] is neither [`Send`] nor [`Sync`].
|
||||
/// Use the [`Sync`] feature to make it [`Send`] `+` [`Sync`].
|
||||
/// Use the `sync` feature to make it [`Send`] `+` [`Sync`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -37,10 +37,10 @@ impl Engine {
|
||||
///
|
||||
/// ## WARNING - Low Level API
|
||||
///
|
||||
/// This function is very low level. It takes a list of [`TypeId`]'s indicating the actual types of the parameters.
|
||||
/// This function is very low level. It takes a list of [`TypeId`][std::any::TypeId]'s indicating the actual types of the parameters.
|
||||
///
|
||||
/// Arguments are simply passed in as a mutable array of [`&mut Dynamic`][Dynamic],
|
||||
/// The arguments are guaranteed to be of the correct types matching the [`TypeId`]'s.
|
||||
/// The arguments are guaranteed to be of the correct types matching the [`TypeId`][std::any::TypeId]'s.
|
||||
///
|
||||
/// To access a primary parameter value (i.e. cloning is cheap), use: `args[n].clone().cast::<T>()`
|
||||
///
|
||||
@ -1639,7 +1639,7 @@ impl Engine {
|
||||
.lib()
|
||||
.iter_fn()
|
||||
.filter(|f| f.func.is_script())
|
||||
.map(|f| (**f.func.get_fn_def()).clone())
|
||||
.map(|f| f.func.get_fn_def().clone())
|
||||
.collect();
|
||||
|
||||
#[cfg(feature = "no_function")]
|
||||
|
@ -72,7 +72,7 @@ impl Engine {
|
||||
pub fn max_operations(&self) -> u64 {
|
||||
self.limits.max_operations
|
||||
}
|
||||
/// Set the maximum number of imported modules allowed for a script.
|
||||
/// Set the maximum number of imported [modules][crate::Module] allowed for a script.
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[inline(always)]
|
||||
@ -80,7 +80,7 @@ impl Engine {
|
||||
self.limits.max_modules = modules;
|
||||
self
|
||||
}
|
||||
/// The maximum number of imported modules allowed for a script.
|
||||
/// The maximum number of imported [modules][crate::Module] allowed for a script.
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[inline(always)]
|
||||
@ -123,20 +123,20 @@ impl Engine {
|
||||
pub fn max_function_expr_depth(&self) -> usize {
|
||||
self.limits.max_function_expr_depth
|
||||
}
|
||||
/// Set the maximum length of strings (0 for unlimited).
|
||||
/// Set the maximum length of [strings][crate::ImmutableString] (0 for unlimited).
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[inline(always)]
|
||||
pub fn set_max_string_size(&mut self, max_size: usize) -> &mut Self {
|
||||
self.limits.max_string_size = if max_size == usize::MAX { 0 } else { max_size };
|
||||
self
|
||||
}
|
||||
/// The maximum length of strings (0 for unlimited).
|
||||
/// The maximum length of [strings][crate::ImmutableString] (0 for unlimited).
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[inline(always)]
|
||||
pub fn max_string_size(&self) -> usize {
|
||||
self.limits.max_string_size
|
||||
}
|
||||
/// Set the maximum length of arrays (0 for unlimited).
|
||||
/// Set the maximum length of [arrays][crate::Array] (0 for unlimited).
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
#[inline(always)]
|
||||
@ -144,14 +144,14 @@ impl Engine {
|
||||
self.limits.max_array_size = if max_size == usize::MAX { 0 } else { max_size };
|
||||
self
|
||||
}
|
||||
/// The maximum length of arrays (0 for unlimited).
|
||||
/// The maximum length of [arrays][crate::Array] (0 for unlimited).
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
#[inline(always)]
|
||||
pub fn max_array_size(&self) -> usize {
|
||||
self.limits.max_array_size
|
||||
}
|
||||
/// Set the maximum length of object maps (0 for unlimited).
|
||||
/// Set the maximum length of [object maps][crate::Map] (0 for unlimited).
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
#[inline(always)]
|
||||
@ -159,7 +159,7 @@ impl Engine {
|
||||
self.limits.max_map_size = if max_size == usize::MAX { 0 } else { max_size };
|
||||
self
|
||||
}
|
||||
/// The maximum length of object maps (0 for unlimited).
|
||||
/// The maximum length of [object maps][crate::Map] (0 for unlimited).
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
#[inline(always)]
|
||||
|
@ -6,7 +6,7 @@ use crate::dynamic::Variant;
|
||||
use crate::{Dynamic, StaticVec};
|
||||
|
||||
/// Trait that represents arguments to a function call.
|
||||
/// Any data type that can be converted into a `Vec<Dynamic>` can be used
|
||||
/// Any data type that can be converted into a [`Vec`]`<`[`Dynamic`]`>` can be used
|
||||
/// as arguments to a function call.
|
||||
pub trait FuncArgs {
|
||||
/// Convert to a [`StaticVec`]`<`[`Dynamic`]`>` of the function call arguments.
|
||||
|
@ -1166,7 +1166,7 @@ impl Engine {
|
||||
}
|
||||
}
|
||||
|
||||
f.get_native_fn().clone()((self, &*mods, lib).into(), args.as_mut())
|
||||
f.get_native_fn()((self, &*mods, lib).into(), args.as_mut())
|
||||
}
|
||||
Some(_) => unreachable!(),
|
||||
None if def_val.is_some() => Ok(def_val.unwrap().clone()),
|
||||
|
@ -37,15 +37,15 @@ pub type Shared<T> = Rc<T>;
|
||||
pub type Shared<T> = Arc<T>;
|
||||
|
||||
/// Synchronized shared object.
|
||||
#[cfg(any(not(feature = "no_closure"), not(feature = "no_module")))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
pub type Locked<T> = crate::stdlib::cell::RefCell<T>;
|
||||
/// Synchronized shared object.
|
||||
#[cfg(any(not(feature = "no_closure"), not(feature = "no_module")))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(feature = "sync")]
|
||||
pub type Locked<T> = crate::stdlib::sync::RwLock<T>;
|
||||
|
||||
/// Context of native Rust function call.
|
||||
/// Context of a native Rust function call.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct NativeCallContext<'e, 'a, 'm, 'pm: 'm> {
|
||||
engine: &'e Engine,
|
||||
@ -207,6 +207,7 @@ pub fn shared_take<T>(value: Shared<T>) -> T {
|
||||
shared_try_take(value).map_err(|_| ()).unwrap()
|
||||
}
|
||||
|
||||
/// Arguments to a function call, which is a list of [`&mut Dynamic`][Dynamic].
|
||||
pub type FnCallArgs<'a> = [&'a mut Dynamic];
|
||||
|
||||
/// A general function pointer, which may carry additional (i.e. curried) argument values
|
||||
@ -488,9 +489,9 @@ impl CallableFunction {
|
||||
///
|
||||
/// Panics if the [`CallableFunction`] is not [`Pure`][CallableFunction::Pure] or
|
||||
/// [`Method`][CallableFunction::Method].
|
||||
pub fn get_native_fn(&self) -> &Shared<FnAny> {
|
||||
pub fn get_native_fn(&self) -> &FnAny {
|
||||
match self {
|
||||
Self::Pure(f) | Self::Method(f) => f,
|
||||
Self::Pure(f) | Self::Method(f) => f.as_ref(),
|
||||
Self::Iterator(_) | Self::Plugin(_) => unreachable!(),
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
@ -503,10 +504,10 @@ impl CallableFunction {
|
||||
///
|
||||
/// Panics if the [`CallableFunction`] is not [`Script`][CallableFunction::Script].
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
pub fn get_fn_def(&self) -> &Shared<ScriptFnDef> {
|
||||
pub fn get_fn_def(&self) -> &ScriptFnDef {
|
||||
match self {
|
||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) | Self::Plugin(_) => unreachable!(),
|
||||
Self::Script(f) => f,
|
||||
Self::Script(f) => f.as_ref(),
|
||||
}
|
||||
}
|
||||
/// Get a reference to an iterator function.
|
||||
@ -528,9 +529,9 @@ impl CallableFunction {
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the [`CallableFunction`] is not [`Plugin`][CallableFunction::Plugin].
|
||||
pub fn get_plugin_fn<'s>(&'s self) -> &Shared<FnPlugin> {
|
||||
pub fn get_plugin_fn<'s>(&'s self) -> &FnPlugin {
|
||||
match self {
|
||||
Self::Plugin(f) => f,
|
||||
Self::Plugin(f) => f.as_ref(),
|
||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => unreachable!(),
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
|
@ -10,9 +10,9 @@ use crate::{
|
||||
Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, ImmutableString, NativeCallContext,
|
||||
};
|
||||
|
||||
/// Trait to register custom functions with the `Engine`.
|
||||
/// Trait to register custom functions with the [`Engine`].
|
||||
pub trait RegisterFn<FN, ARGS, RET> {
|
||||
/// Register a custom function with the `Engine`.
|
||||
/// Register a custom function with the [`Engine`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@ -42,9 +42,9 @@ pub trait RegisterFn<FN, ARGS, RET> {
|
||||
fn register_fn(&mut self, name: &str, f: FN) -> &mut Self;
|
||||
}
|
||||
|
||||
/// Trait to register fallible custom functions returning `Result<Dynamic, Box<EvalAltResult>>` with the `Engine`.
|
||||
/// Trait to register fallible custom functions returning [`Result`]`<`[`Dynamic`]`, `[`Box`]`<`[`EvalAltResult`]`>>` with the [`Engine`].
|
||||
pub trait RegisterResultFn<FN, ARGS> {
|
||||
/// Register a custom fallible function with the `Engine`.
|
||||
/// Register a custom fallible function with the [`Engine`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@ -75,7 +75,7 @@ pub trait RegisterResultFn<FN, ARGS> {
|
||||
// These types are used to build a unique _marker_ tuple type for each combination
|
||||
// of function parameter types in order to make each trait implementation unique.
|
||||
// That is because stable Rust currently does not allow distinguishing implementations
|
||||
// based purely on parameter types of traits (Fn, FnOnce and FnMut).
|
||||
// based purely on parameter types of traits (`Fn`, `FnOnce` and `FnMut`).
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
|
36
src/lib.rs
36
src/lib.rs
@ -83,20 +83,22 @@ mod token;
|
||||
mod r#unsafe;
|
||||
mod utils;
|
||||
|
||||
/// The system integer type. It is defined as `i64`.
|
||||
/// The system integer type. It is defined as [`i64`].
|
||||
///
|
||||
/// If the `only_i32` feature is enabled, this will be `i32` instead.
|
||||
/// If the `only_i32` feature is enabled, this will be [`i32`] instead.
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
pub type INT = i64;
|
||||
|
||||
/// The system integer type.
|
||||
/// It is defined as `i32` since the `only_i32` feature is used.
|
||||
/// It is defined as [`i32`] since the `only_i32` feature is used.
|
||||
///
|
||||
/// If the `only_i32` feature is not enabled, this will be `i64` instead.
|
||||
/// If the `only_i32` feature is not used, this will be `i64` instead.
|
||||
#[cfg(feature = "only_i32")]
|
||||
pub type INT = i32;
|
||||
|
||||
/// The system floating-point type. It is defined as `f64`.
|
||||
/// The system floating-point type. It is defined as [`f64`].
|
||||
///
|
||||
/// If the `f32_float` feature is enabled, this will be [`i32`] instead.
|
||||
///
|
||||
/// Not available under the `no_float` feature.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
@ -104,7 +106,9 @@ pub type INT = i32;
|
||||
pub type FLOAT = f64;
|
||||
|
||||
/// The system floating-point type.
|
||||
/// It is defined as `f32` since the `f32_float` feature is used.
|
||||
/// It is defined as [`f32`] since the `f32_float` feature is used.
|
||||
///
|
||||
/// If the `f32_float` feature is not used, this will be `f64` instead.
|
||||
///
|
||||
/// Not available under the `no_float` feature.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
@ -114,7 +118,7 @@ pub type FLOAT = f32;
|
||||
pub use ast::{FnAccess, AST};
|
||||
pub use dynamic::Dynamic;
|
||||
pub use engine::{Engine, EvalContext};
|
||||
pub use fn_native::{FnPtr, NativeCallContext};
|
||||
pub use fn_native::{FnPtr, NativeCallContext, Shared};
|
||||
pub use fn_register::{RegisterFn, RegisterResultFn};
|
||||
pub use module::{FnNamespace, Module};
|
||||
pub use parse_error::{LexError, ParseError, ParseErrorType};
|
||||
@ -124,8 +128,8 @@ pub use syntax::Expression;
|
||||
pub use token::Position;
|
||||
pub use utils::ImmutableString;
|
||||
|
||||
#[allow(dead_code)]
|
||||
use fn_native::{Locked, Shared};
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
use fn_native::Locked;
|
||||
|
||||
#[cfg(feature = "internals")]
|
||||
pub use utils::{calc_native_fn_hash, calc_script_fn_hash};
|
||||
@ -138,13 +142,13 @@ pub use rhai_codegen::*;
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
pub use fn_func::Func;
|
||||
|
||||
/// Variable-sized array of `Dynamic` values.
|
||||
/// Variable-sized array of [`Dynamic`] values.
|
||||
///
|
||||
/// Not available under the `no_index` feature.
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
pub type Array = stdlib::vec::Vec<Dynamic>;
|
||||
|
||||
/// Hash map of `Dynamic` values with `ImmutableString` keys.
|
||||
/// Hash map of [`Dynamic`] values with [`ImmutableString`] keys.
|
||||
///
|
||||
/// Not available under the `no_object` feature.
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
@ -181,20 +185,24 @@ pub use ast::{
|
||||
|
||||
#[cfg(feature = "internals")]
|
||||
#[deprecated(note = "this type is volatile and may change")]
|
||||
pub use engine::{Imports, Limits, State as EvalState};
|
||||
pub use engine::{Imports, State as EvalState};
|
||||
|
||||
#[cfg(feature = "internals")]
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
pub use engine::Limits;
|
||||
|
||||
#[cfg(feature = "internals")]
|
||||
#[deprecated(note = "this type is volatile and may change")]
|
||||
pub use module::NamespaceRef;
|
||||
|
||||
/// _(INTERNALS)_ Alias to [`smallvec::SmallVec<[T; 4]>`](https://crates.io/crates/smallvec),
|
||||
/// which is a specialized `Vec` backed by a small, fixed-size array when there are <= 4 items stored.
|
||||
/// which is a specialized [`Vec`] backed by a small, fixed-size array when there are <= 4 items stored.
|
||||
/// Exported under the `internals` feature only.
|
||||
#[cfg(not(feature = "internals"))]
|
||||
type StaticVec<T> = smallvec::SmallVec<[T; 4]>;
|
||||
|
||||
/// _(INTERNALS)_ Alias to [`smallvec::SmallVec<[T; 4]>`](https://crates.io/crates/smallvec),
|
||||
/// which is a specialized `Vec` backed by a small, fixed-size array when there are <= 4 items stored.
|
||||
/// which is a specialized [`Vec`] backed by a small, fixed-size array when there are <= 4 items stored.
|
||||
/// Exported under the `internals` feature only.
|
||||
#[cfg(feature = "internals")]
|
||||
pub type StaticVec<T> = smallvec::SmallVec<[T; 4]>;
|
||||
|
@ -9,7 +9,7 @@ use crate::stdlib::{
|
||||
boxed::Box,
|
||||
collections::HashMap,
|
||||
fmt, format,
|
||||
iter::{empty, once},
|
||||
iter::empty,
|
||||
num::NonZeroUsize,
|
||||
ops::{Add, AddAssign, Deref, DerefMut},
|
||||
string::{String, ToString},
|
||||
@ -21,6 +21,9 @@ use crate::{
|
||||
Dynamic, EvalAltResult, ImmutableString, NativeCallContext, Position, Shared, StaticVec,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
use crate::ast::ScriptFnDef;
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::Array;
|
||||
|
||||
@ -28,9 +31,6 @@ use crate::Array;
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::Map;
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
pub type SharedScriptFnDef = Shared<crate::ast::ScriptFnDef>;
|
||||
|
||||
/// A type representing the namespace of a function.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub enum FnNamespace {
|
||||
@ -47,7 +47,7 @@ impl Default for FnNamespace {
|
||||
}
|
||||
|
||||
impl FnNamespace {
|
||||
/// Is this namespace global?
|
||||
/// Is this namespace [global][FnNamespace::Global]?
|
||||
#[inline(always)]
|
||||
pub fn is_global(self) -> bool {
|
||||
match self {
|
||||
@ -55,7 +55,7 @@ impl FnNamespace {
|
||||
Self::Internal => false,
|
||||
}
|
||||
}
|
||||
/// Is this namespace internal?
|
||||
/// Is this namespace [internal][FnNamespace::Internal]?
|
||||
#[inline(always)]
|
||||
pub fn is_internal(self) -> bool {
|
||||
match self {
|
||||
@ -357,10 +357,14 @@ impl Module {
|
||||
/// If there is an existing function of the same name and number of arguments, it is replaced.
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[inline]
|
||||
pub(crate) fn set_script_fn(&mut self, fn_def: SharedScriptFnDef) -> u64 {
|
||||
pub(crate) fn set_script_fn(&mut self, fn_def: impl Into<Shared<ScriptFnDef>>) -> u64 {
|
||||
let fn_def = fn_def.into();
|
||||
|
||||
// None + function name + number of arguments.
|
||||
let num_params = fn_def.params.len();
|
||||
let hash_script = crate::calc_script_fn_hash(empty(), &fn_def.name, num_params);
|
||||
let mut param_names: StaticVec<_> = fn_def.params.iter().cloned().collect();
|
||||
param_names.push("Dynamic".into());
|
||||
self.functions.insert(
|
||||
hash_script,
|
||||
FuncInfo {
|
||||
@ -369,14 +373,7 @@ impl Module {
|
||||
access: fn_def.access,
|
||||
params: num_params,
|
||||
param_types: None,
|
||||
param_names: Some(
|
||||
fn_def
|
||||
.params
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(once("Dynamic".into()))
|
||||
.collect(),
|
||||
),
|
||||
param_names: Some(param_names),
|
||||
func: fn_def.into(),
|
||||
},
|
||||
);
|
||||
@ -392,7 +389,7 @@ impl Module {
|
||||
name: &str,
|
||||
num_params: usize,
|
||||
public_only: bool,
|
||||
) -> Option<&SharedScriptFnDef> {
|
||||
) -> Option<&ScriptFnDef> {
|
||||
self.functions
|
||||
.values()
|
||||
.find(
|
||||
@ -1527,12 +1524,12 @@ impl Module {
|
||||
/// 2) Access mode ([`FnAccess::Public`] or [`FnAccess::Private`]).
|
||||
/// 3) Function name (as string slice).
|
||||
/// 4) Number of parameters.
|
||||
/// 5) Shared reference to function definition [`ScriptFnDef`][crate::ScriptFnDef].
|
||||
/// 5) Shared reference to function definition [`ScriptFnDef`][crate::ast::ScriptFnDef].
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[inline(always)]
|
||||
pub(crate) fn iter_script_fn<'a>(
|
||||
&'a self,
|
||||
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize, SharedScriptFnDef)> + 'a {
|
||||
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize, &ScriptFnDef)> + 'a {
|
||||
self.functions.values().filter(|f| f.func.is_script()).map(
|
||||
|FuncInfo {
|
||||
namespace,
|
||||
@ -1547,7 +1544,7 @@ impl Module {
|
||||
*access,
|
||||
name.as_str(),
|
||||
*params,
|
||||
func.get_fn_def().clone(),
|
||||
func.get_fn_def(),
|
||||
)
|
||||
},
|
||||
)
|
||||
@ -1584,14 +1581,14 @@ impl Module {
|
||||
/// 2) Access mode ([`FnAccess::Public`] or [`FnAccess::Private`]).
|
||||
/// 3) Function name (as string slice).
|
||||
/// 4) Number of parameters.
|
||||
/// 5) _(INTERNALS)_ Shared reference to function definition [`ScriptFnDef`][crate::ScriptFnDef].
|
||||
/// 5) _(INTERNALS)_ Shared reference to function definition [`ScriptFnDef`][crate::ast::ScriptFnDef].
|
||||
/// Exported under the `internals` feature only.
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[cfg(feature = "internals")]
|
||||
#[inline(always)]
|
||||
pub fn iter_script_fn_info(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize, SharedScriptFnDef)> {
|
||||
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize, &ScriptFnDef)> {
|
||||
self.iter_script_fn()
|
||||
}
|
||||
|
||||
@ -1653,14 +1650,16 @@ impl Module {
|
||||
// Non-private functions defined become module functions
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
{
|
||||
ast.iter_functions()
|
||||
.filter(|(_, access, _, _, _)| !access.is_private())
|
||||
.for_each(|(_, _, _, _, func)| {
|
||||
ast.lib()
|
||||
.functions
|
||||
.values()
|
||||
.filter(|FuncInfo { access, func, .. }| !access.is_private() && func.is_script())
|
||||
.for_each(|FuncInfo { func, .. }| {
|
||||
// Encapsulate AST environment
|
||||
let mut func = func.as_ref().clone();
|
||||
let mut func = func.get_fn_def().clone();
|
||||
func.lib = Some(ast.shared_lib());
|
||||
func.mods = func_mods.clone();
|
||||
module.set_script_fn(func.into());
|
||||
module.set_script_fn(func);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1827,7 +1826,7 @@ impl Module {
|
||||
}
|
||||
}
|
||||
|
||||
/// _(INTERNALS)_ A chain of module names to namespace-qualify a variable or function call.
|
||||
/// _(INTERNALS)_ A chain of [module][Module] names to namespace-qualify a variable or function call.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// A [`u64`] hash key is cached for quick search purposes.
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::stdlib::{
|
||||
boxed::Box, collections::HashMap, io::Error as IoError, path::PathBuf, string::String,
|
||||
};
|
||||
use crate::{Engine, EvalAltResult, Locked, Module, ModuleResolver, Position, Shared};
|
||||
use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared};
|
||||
|
||||
/// Module resolution service that loads module script files from the file system.
|
||||
///
|
||||
@ -37,7 +37,11 @@ use crate::{Engine, EvalAltResult, Locked, Module, ModuleResolver, Position, Sha
|
||||
pub struct FileModuleResolver {
|
||||
path: PathBuf,
|
||||
extension: String,
|
||||
cache: Locked<HashMap<PathBuf, Shared<Module>>>,
|
||||
|
||||
#[cfg(not(feature = "sync"))]
|
||||
cache: crate::stdlib::cell::RefCell<HashMap<PathBuf, Shared<Module>>>,
|
||||
#[cfg(feature = "sync")]
|
||||
cache: crate::stdlib::sync::RwLock<HashMap<PathBuf, Shared<Module>>>,
|
||||
}
|
||||
|
||||
impl Default for FileModuleResolver {
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Module implementing the AST optimizer.
|
||||
//! Module implementing the [`AST`] optimizer.
|
||||
|
||||
use crate::ast::{Expr, ScriptFnDef, Stmt};
|
||||
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
||||
@ -32,19 +32,20 @@ pub enum OptimizationLevel {
|
||||
}
|
||||
|
||||
impl OptimizationLevel {
|
||||
/// Is the `OptimizationLevel` None.
|
||||
/// Is the `OptimizationLevel` [`None`][OptimizationLevel::None]?
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub fn is_none(self) -> bool {
|
||||
self == Self::None
|
||||
}
|
||||
/// Is the `OptimizationLevel` Simple.
|
||||
#[cfg(not(feature = "no_optimize"))]
|
||||
/// Is the `OptimizationLevel` [`Simple`][OptimizationLevel::Simple]?
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub fn is_simple(self) -> bool {
|
||||
self == Self::Simple
|
||||
}
|
||||
/// Is the `OptimizationLevel` Full.
|
||||
#[cfg(not(feature = "no_optimize"))]
|
||||
/// Is the `OptimizationLevel` [`Full`][OptimizationLevel::Full]?
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub fn is_full(self) -> bool {
|
||||
self == Self::Full
|
||||
@ -54,13 +55,13 @@ impl OptimizationLevel {
|
||||
/// Mutable state throughout an optimization pass.
|
||||
#[derive(Debug, Clone)]
|
||||
struct State<'a> {
|
||||
/// Has the AST been changed during this pass?
|
||||
/// Has the [`AST`] been changed during this pass?
|
||||
changed: bool,
|
||||
/// Collection of constants to use for eager function evaluations.
|
||||
constants: Vec<(String, Expr)>,
|
||||
/// An `Engine` instance for eager function evaluation.
|
||||
/// An [`Engine`] instance for eager function evaluation.
|
||||
engine: &'a Engine,
|
||||
/// Library of script-defined functions.
|
||||
/// [Module] containing script-defined functions.
|
||||
lib: &'a [&'a Module],
|
||||
/// Optimization level.
|
||||
optimization_level: OptimizationLevel,
|
||||
@ -83,12 +84,12 @@ impl<'a> State<'a> {
|
||||
pub fn reset(&mut self) {
|
||||
self.changed = false;
|
||||
}
|
||||
/// Set the AST state to be dirty (i.e. changed).
|
||||
/// Set the [`AST`] state to be dirty (i.e. changed).
|
||||
#[inline(always)]
|
||||
pub fn set_dirty(&mut self) {
|
||||
self.changed = true;
|
||||
}
|
||||
/// Is the AST dirty (i.e. changed)?
|
||||
/// Is the [`AST`] dirty (i.e. changed)?
|
||||
#[inline(always)]
|
||||
pub fn is_dirty(&self) -> bool {
|
||||
self.changed
|
||||
@ -147,7 +148,7 @@ fn call_fn_with_constant_arguments(
|
||||
.map(|(v, _)| v)
|
||||
}
|
||||
|
||||
/// Optimize a block of statements.
|
||||
/// Optimize a block of [statements][crate::ast::Stmt].
|
||||
fn optimize_stmt_block(
|
||||
mut statements: Vec<Stmt>,
|
||||
pos: Position,
|
||||
@ -264,7 +265,7 @@ fn optimize_stmt_block(
|
||||
}
|
||||
}
|
||||
|
||||
/// Optimize a statement.
|
||||
/// Optimize a [statement][crate::ast::Stmt].
|
||||
fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
||||
match stmt {
|
||||
// expr op= expr
|
||||
@ -460,7 +461,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Optimize an expression.
|
||||
/// Optimize an [expression][crate::ast::Expr].
|
||||
fn optimize_expr(expr: &mut Expr, state: &mut State) {
|
||||
// These keywords are handled specially
|
||||
const DONT_EVAL_KEYWORDS: &[&str] = &[
|
||||
@ -724,7 +725,8 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
|
||||
}
|
||||
}
|
||||
|
||||
fn optimize(
|
||||
/// Optimize a block of [statements][crate::ast::Stmt] at top level.
|
||||
fn optimize_top_level(
|
||||
mut statements: Vec<Stmt>,
|
||||
engine: &Engine,
|
||||
scope: &Scope,
|
||||
@ -815,7 +817,7 @@ fn optimize(
|
||||
statements
|
||||
}
|
||||
|
||||
/// Optimize an AST.
|
||||
/// Optimize an [`AST`].
|
||||
pub fn optimize_into_ast(
|
||||
engine: &Engine,
|
||||
scope: &Scope,
|
||||
@ -839,8 +841,7 @@ pub fn optimize_into_ast(
|
||||
|
||||
_functions
|
||||
.iter()
|
||||
.map(|fn_def| {
|
||||
ScriptFnDef {
|
||||
.map(|fn_def| ScriptFnDef {
|
||||
name: fn_def.name.clone(),
|
||||
access: fn_def.access,
|
||||
body: Default::default(),
|
||||
@ -850,8 +851,6 @@ pub fn optimize_into_ast(
|
||||
lib: None,
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
mods: Default::default(),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
.for_each(|fn_def| {
|
||||
lib2.set_script_fn(fn_def);
|
||||
@ -863,8 +862,13 @@ pub fn optimize_into_ast(
|
||||
let pos = fn_def.body.position();
|
||||
|
||||
// Optimize the function body
|
||||
let mut body =
|
||||
optimize(vec![fn_def.body], engine, &Scope::new(), &[&lib2], level);
|
||||
let mut body = optimize_top_level(
|
||||
vec![fn_def.body],
|
||||
engine,
|
||||
&Scope::new(),
|
||||
&[&lib2],
|
||||
level,
|
||||
);
|
||||
|
||||
// {} -> Noop
|
||||
fn_def.body = match body.pop().unwrap_or_else(|| Stmt::Noop(pos)) {
|
||||
@ -879,14 +883,14 @@ pub fn optimize_into_ast(
|
||||
// All others
|
||||
stmt => stmt,
|
||||
};
|
||||
fn_def.into()
|
||||
fn_def
|
||||
})
|
||||
.for_each(|fn_def| {
|
||||
module.set_script_fn(fn_def);
|
||||
});
|
||||
} else {
|
||||
_functions.into_iter().for_each(|fn_def| {
|
||||
module.set_script_fn(fn_def.into());
|
||||
module.set_script_fn(fn_def);
|
||||
});
|
||||
}
|
||||
|
||||
@ -902,7 +906,7 @@ pub fn optimize_into_ast(
|
||||
match level {
|
||||
OptimizationLevel::None => statements,
|
||||
OptimizationLevel::Simple | OptimizationLevel::Full => {
|
||||
optimize(statements, engine, &scope, &[&lib], level)
|
||||
optimize_top_level(statements, engine, &scope, &[&lib], level)
|
||||
}
|
||||
},
|
||||
lib,
|
||||
|
@ -1,11 +1,10 @@
|
||||
use crate::plugin::*;
|
||||
use crate::stdlib::iter::empty;
|
||||
use crate::{calc_script_fn_hash, def_package, FnPtr, ImmutableString, NativeCallContext, INT};
|
||||
use crate::{def_package, FnPtr, ImmutableString, NativeCallContext};
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::{module::SharedScriptFnDef, stdlib::collections::HashMap, Array, Map};
|
||||
use crate::{ast::ScriptFnDef, stdlib::collections::HashMap, Array, Map};
|
||||
|
||||
def_package!(crate:BasicFnPackage:"Basic Fn functions.", lib, {
|
||||
combine_with_exported_module!(lib, "FnPtr", fn_ptr_functions);
|
||||
@ -20,6 +19,8 @@ mod fn_ptr_functions {
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
pub mod functions {
|
||||
use crate::{calc_script_fn_hash, stdlib::iter::empty, INT};
|
||||
|
||||
#[rhai_fn(name = "is_anonymous", get = "is_anonymous")]
|
||||
pub fn is_anonymous(f: &mut FnPtr) -> bool {
|
||||
f.is_anonymous()
|
||||
@ -54,7 +55,7 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> Array {
|
||||
fn make_metadata(
|
||||
dict: &HashMap<&str, ImmutableString>,
|
||||
namespace: Option<ImmutableString>,
|
||||
f: SharedScriptFnDef,
|
||||
f: &ScriptFnDef,
|
||||
) -> Map {
|
||||
let mut map = Map::with_capacity(6);
|
||||
|
||||
|
@ -26,7 +26,7 @@ where
|
||||
fn next(&mut self) -> Option<T> {
|
||||
if self.0 < self.1 {
|
||||
let v = self.0.clone();
|
||||
self.0 = &v + &self.2;
|
||||
self.0 = self.0.add(&self.2);
|
||||
Some(v)
|
||||
} else {
|
||||
None
|
||||
|
@ -68,10 +68,10 @@ impl LexError {
|
||||
Self::ImproperSymbol(_, _) => "Invalid symbol encountered",
|
||||
}
|
||||
}
|
||||
/// Convert a `&LexError` into a [`ParseError`].
|
||||
/// Convert a [`LexError`] into a [`ParseError`].
|
||||
#[inline(always)]
|
||||
pub fn into_err(&self, pos: Position) -> ParseError {
|
||||
ParseError(Box::new(self.clone().into()), pos)
|
||||
pub fn into_err(self, pos: Position) -> ParseError {
|
||||
ParseError(Box::new(self.into()), pos)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,20 +25,24 @@ use crate::syntax::CustomSyntax;
|
||||
use crate::token::{is_keyword_function, is_valid_identifier, Token, TokenStream};
|
||||
use crate::utils::{get_hasher, StraightHasherBuilder};
|
||||
use crate::{
|
||||
calc_script_fn_hash, Dynamic, Engine, FnAccess, ImmutableString, LexError, ParseError,
|
||||
ParseErrorType, Position, Scope, StaticVec, AST,
|
||||
calc_script_fn_hash, Dynamic, Engine, ImmutableString, LexError, ParseError, ParseErrorType,
|
||||
Position, Scope, StaticVec, AST,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use crate::FLOAT;
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
use crate::FnAccess;
|
||||
|
||||
type PERR = ParseErrorType;
|
||||
|
||||
type FunctionsLib = HashMap<u64, ScriptFnDef, StraightHasherBuilder>;
|
||||
|
||||
/// A type that encapsulates the current state of the parser.
|
||||
#[derive(Debug)]
|
||||
struct ParseState<'e> {
|
||||
/// Reference to the scripting `Engine`.
|
||||
/// Reference to the scripting [`Engine`].
|
||||
engine: &'e Engine,
|
||||
/// Hash that uniquely identifies a script.
|
||||
script_hash: u64,
|
||||
@ -57,7 +61,7 @@ struct ParseState<'e> {
|
||||
/// All consequent calls to `access_var` will not be affected
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
allow_capture: bool,
|
||||
/// Encapsulates a local stack with imported module names.
|
||||
/// Encapsulates a local stack with imported [module][crate::Module] names.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
modules: StaticVec<ImmutableString>,
|
||||
/// Maximum levels of expression nesting.
|
||||
@ -70,7 +74,7 @@ struct ParseState<'e> {
|
||||
}
|
||||
|
||||
impl<'e> ParseState<'e> {
|
||||
/// Create a new `ParseState`.
|
||||
/// Create a new [`ParseState`].
|
||||
#[inline(always)]
|
||||
pub fn new(
|
||||
engine: &'e Engine,
|
||||
@ -100,12 +104,12 @@ impl<'e> ParseState<'e> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Find explicitly declared variable by name in the `ParseState`, searching in reverse order.
|
||||
/// Find explicitly declared variable by name in the [`ParseState`], searching in reverse order.
|
||||
///
|
||||
/// If the variable is not present in the scope adds it to the list of external variables
|
||||
///
|
||||
/// The return value is the offset to be deducted from `Stack::len`,
|
||||
/// i.e. the top element of the `ParseState` is offset 1.
|
||||
/// i.e. the top element of the [`ParseState`] is offset 1.
|
||||
///
|
||||
/// Return `None` when the variable name is not found in the `stack`.
|
||||
#[inline]
|
||||
@ -144,12 +148,12 @@ impl<'e> ParseState<'e> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Find a module by name in the `ParseState`, searching in reverse.
|
||||
/// Find a module by name in the [`ParseState`], searching in reverse.
|
||||
///
|
||||
/// Returns the offset to be deducted from `Stack::len`,
|
||||
/// i.e. the top element of the `ParseState` is offset 1.
|
||||
/// i.e. the top element of the [`ParseState`] is offset 1.
|
||||
///
|
||||
/// Returns `None` when the variable name is not found in the `ParseState`.
|
||||
/// Returns `None` when the variable name is not found in the [`ParseState`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
@ -183,8 +187,8 @@ impl<'e> ParseState<'e> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
/// A type that encapsulates all the settings for a particular parsing function.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
struct ParseSettings {
|
||||
/// Current position.
|
||||
pos: Position,
|
||||
@ -230,7 +234,8 @@ impl ParseSettings {
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
/// Convert a `Variable` into a `Property`. All other variants are untouched.
|
||||
/// Convert a [`Variable`][Expr::Variable] into a [`Property`][Expr::Property].
|
||||
/// All other variants are untouched.
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
#[inline]
|
||||
fn into_property(self, state: &mut ParseState) -> Self {
|
||||
@ -246,7 +251,7 @@ impl Expr {
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume a particular token, checking that it is the expected one.
|
||||
/// Consume a particular [token][Token], checking that it is the expected one.
|
||||
fn eat_token(input: &mut TokenStream, token: Token) -> Position {
|
||||
let (t, pos) = input.next().unwrap();
|
||||
|
||||
@ -261,7 +266,7 @@ fn eat_token(input: &mut TokenStream, token: Token) -> Position {
|
||||
pos
|
||||
}
|
||||
|
||||
/// Match a particular token, consuming it if matched.
|
||||
/// Match a particular [token][Token], consuming it if matched.
|
||||
fn match_token(input: &mut TokenStream, token: Token) -> (bool, Position) {
|
||||
let (t, pos) = input.peek().unwrap();
|
||||
if *t == token {
|
||||
@ -328,7 +333,7 @@ fn parse_fn_call(
|
||||
.into_err(*token_pos))
|
||||
}
|
||||
// id( <error>
|
||||
Token::LexError(err) => return Err(err.into_err(*token_pos)),
|
||||
Token::LexError(err) => return Err(err.clone().into_err(*token_pos)),
|
||||
// id()
|
||||
Token::RightParen => {
|
||||
eat_token(input, Token::RightParen);
|
||||
@ -422,7 +427,7 @@ fn parse_fn_call(
|
||||
.into_err(*pos))
|
||||
}
|
||||
// id(...args <error>
|
||||
(Token::LexError(err), pos) => return Err(err.into_err(*pos)),
|
||||
(Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
|
||||
// id(...args ???
|
||||
(_, pos) => {
|
||||
return Err(PERR::MissingToken(
|
||||
@ -610,7 +615,7 @@ fn parse_index_chain(
|
||||
}
|
||||
}
|
||||
}
|
||||
(Token::LexError(err), pos) => return Err(err.into_err(*pos)),
|
||||
(Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
|
||||
(_, pos) => Err(PERR::MissingToken(
|
||||
Token::RightBracket.into(),
|
||||
"for a matching [ in this index expression".into(),
|
||||
@ -672,7 +677,7 @@ fn parse_array_literal(
|
||||
.into_err(*pos),
|
||||
)
|
||||
}
|
||||
(Token::LexError(err), pos) => return Err(err.into_err(*pos)),
|
||||
(Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
|
||||
(_, pos) => {
|
||||
return Err(PERR::MissingToken(
|
||||
Token::Comma.into(),
|
||||
@ -781,7 +786,7 @@ fn parse_map_literal(
|
||||
)
|
||||
.into_err(*pos))
|
||||
}
|
||||
(Token::LexError(err), pos) => return Err(err.into_err(*pos)),
|
||||
(Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
|
||||
(_, pos) => {
|
||||
return Err(
|
||||
PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into())
|
||||
@ -899,7 +904,7 @@ fn parse_switch(
|
||||
.into_err(*pos),
|
||||
)
|
||||
}
|
||||
(Token::LexError(err), pos) => return Err(err.into_err(*pos)),
|
||||
(Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
|
||||
(_, pos) if need_comma => {
|
||||
return Err(PERR::MissingToken(
|
||||
Token::Comma.into(),
|
||||
@ -2342,7 +2347,7 @@ fn parse_block(
|
||||
// { ... { stmt } ???
|
||||
(_, _) if !need_semicolon => (),
|
||||
// { ... stmt <error>
|
||||
(Token::LexError(err), pos) => return Err(err.into_err(*pos)),
|
||||
(Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
|
||||
// { ... stmt ???
|
||||
(_, pos) => {
|
||||
// Semicolons are not optional between statements
|
||||
@ -2960,7 +2965,7 @@ impl Engine {
|
||||
// { stmt } ???
|
||||
(_, _) if !need_semicolon => (),
|
||||
// stmt <error>
|
||||
(Token::LexError(err), pos) => return Err(err.into_err(*pos)),
|
||||
(Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
|
||||
// stmt ???
|
||||
(_, pos) => {
|
||||
// Semicolons are not optional between statements
|
||||
|
@ -36,10 +36,10 @@ pub enum EvalAltResult {
|
||||
/// An error has occurred inside a called function.
|
||||
/// Wrapped values are the function name and the interior error.
|
||||
ErrorInFunctionCall(String, Box<EvalAltResult>, Position),
|
||||
/// Usage of an unknown module. Wrapped value is the module name.
|
||||
/// Usage of an unknown [module][crate::Module]. Wrapped value is the [module][crate::Module] name.
|
||||
ErrorModuleNotFound(String, Position),
|
||||
/// An error has occurred while loading a module.
|
||||
/// Wrapped value are the module name and the interior error.
|
||||
/// An error has occurred while loading a [module][crate::Module].
|
||||
/// Wrapped value are the [module][crate::Module] name and the interior error.
|
||||
ErrorInModule(String, Box<EvalAltResult>, Position),
|
||||
/// Access to `this` that is not bound.
|
||||
ErrorUnboundThis(Position),
|
||||
@ -72,7 +72,7 @@ pub enum EvalAltResult {
|
||||
ErrorArithmetic(String, Position),
|
||||
/// Number of operations over maximum limit.
|
||||
ErrorTooManyOperations(Position),
|
||||
/// Modules over maximum limit.
|
||||
/// [Modules][crate::Module] over maximum limit.
|
||||
ErrorTooManyModules(Position),
|
||||
/// Call stack over maximum limit.
|
||||
ErrorStackOverflow(Position),
|
||||
@ -314,7 +314,7 @@ impl EvalAltResult {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
/// Get the [`Position`] of this error.
|
||||
/// Get the [position][Position] of this error.
|
||||
pub fn position(&self) -> Position {
|
||||
match self {
|
||||
Self::ErrorSystem(_, _) => Position::NONE,
|
||||
@ -347,7 +347,7 @@ impl EvalAltResult {
|
||||
| Self::Return(_, pos) => *pos,
|
||||
}
|
||||
}
|
||||
/// Override the [`Position`] of this error.
|
||||
/// Override the [position][Position] of this error.
|
||||
pub fn set_position(&mut self, new_position: Position) {
|
||||
match self {
|
||||
Self::ErrorSystem(_, _) => (),
|
||||
|
@ -30,7 +30,7 @@ impl EntryType {
|
||||
/// # Thread Safety
|
||||
///
|
||||
/// Currently, [`Scope`] is neither [`Send`] nor [`Sync`].
|
||||
/// Turn on the [`Sync`] feature to make it [`Send`] `+` [`Sync`].
|
||||
/// Turn on the `sync` feature to make it [`Send`] `+` [`Sync`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -61,7 +61,7 @@ impl Expression<'_> {
|
||||
}
|
||||
|
||||
impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_, '_> {
|
||||
/// Evaluate an expression tree.
|
||||
/// Evaluate an [expression tree][Expression].
|
||||
///
|
||||
/// ## WARNING - Low Level API
|
||||
///
|
||||
|
Loading…
Reference in New Issue
Block a user