Merge branch 'master' into plugins
This commit is contained in:
commit
d03f6ed983
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rhai"
|
name = "rhai"
|
||||||
version = "0.16.0"
|
version = "0.15.1"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung"]
|
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung"]
|
||||||
description = "Embedded scripting for Rust"
|
description = "Embedded scripting for Rust"
|
||||||
|
25
README.md
25
README.md
@ -37,7 +37,7 @@ Features
|
|||||||
to do checked arithmetic operations); for [`no-std`](#optional-features) builds, a number of additional dependencies are
|
to do checked arithmetic operations); for [`no-std`](#optional-features) builds, a number of additional dependencies are
|
||||||
pulled in to provide for functionalities that used to be in `std`.
|
pulled in to provide for functionalities that used to be in `std`.
|
||||||
|
|
||||||
**Note:** Currently, the version is `0.16.0`, so the language and API's may change before they stabilize.
|
**Note:** Currently, the version is `0.15.1`, so the language and API's may change before they stabilize.
|
||||||
|
|
||||||
What Rhai doesn't do
|
What Rhai doesn't do
|
||||||
--------------------
|
--------------------
|
||||||
@ -71,7 +71,7 @@ Install the Rhai crate on [`crates.io`](https::/crates.io/crates/rhai/) by addin
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rhai = "0.16.0"
|
rhai = "0.15.1"
|
||||||
```
|
```
|
||||||
|
|
||||||
Use the latest released crate version on [`crates.io`](https::/crates.io/crates/rhai/):
|
Use the latest released crate version on [`crates.io`](https::/crates.io/crates/rhai/):
|
||||||
@ -179,13 +179,14 @@ A number of examples can be found in the `examples` folder:
|
|||||||
|
|
||||||
| Example | Description |
|
| Example | Description |
|
||||||
| ------------------------------------------------------------------ | --------------------------------------------------------------------------- |
|
| ------------------------------------------------------------------ | --------------------------------------------------------------------------- |
|
||||||
| [`arrays_and_structs`](examples/arrays_and_structs.rs) | demonstrates registering a new type to Rhai and the usage of [arrays] on it |
|
| [`arrays_and_structs`](examples/arrays_and_structs.rs) | shows how to register a custom Rust type and using [arrays] on it |
|
||||||
| [`custom_types_and_methods`](examples/custom_types_and_methods.rs) | shows how to register a type and methods for it |
|
| [`custom_types_and_methods`](examples/custom_types_and_methods.rs) | shows how to register a custom Rust type and methods for it |
|
||||||
| [`hello`](examples/hello.rs) | simple example that evaluates an expression and prints the result |
|
| [`hello`](examples/hello.rs) | simple example that evaluates an expression and prints the result |
|
||||||
| [`no_std`](examples/no_std.rs) | example to test out `no-std` builds |
|
| [`no_std`](examples/no_std.rs) | example to test out `no-std` builds |
|
||||||
| [`reuse_scope`](examples/reuse_scope.rs) | evaluates two pieces of code in separate runs, but using a common [`Scope`] |
|
| [`reuse_scope`](examples/reuse_scope.rs) | evaluates two pieces of code in separate runs, but using a common [`Scope`] |
|
||||||
| [`rhai_runner`](examples/rhai_runner.rs) | runs each filename passed to it as a Rhai script |
|
| [`rhai_runner`](examples/rhai_runner.rs) | runs each filename passed to it as a Rhai script |
|
||||||
| [`simple_fn`](examples/simple_fn.rs) | shows how to register a Rust function to a Rhai [`Engine`] |
|
| [`simple_fn`](examples/simple_fn.rs) | shows how to register a simple function |
|
||||||
|
| [`strings`](examples/strings.rs) | shows different ways to register functions taking string arguments |
|
||||||
| [`repl`](examples/repl.rs) | a simple REPL, interactively evaluate statements from stdin |
|
| [`repl`](examples/repl.rs) | a simple REPL, interactively evaluate statements from stdin |
|
||||||
|
|
||||||
Examples can be run with the following command:
|
Examples can be run with the following command:
|
||||||
@ -314,7 +315,7 @@ Functions declared with `private` are hidden and cannot be called from Rust (see
|
|||||||
```rust
|
```rust
|
||||||
// Define functions in a script.
|
// Define functions in a script.
|
||||||
let ast = engine.compile(true,
|
let ast = engine.compile(true,
|
||||||
r"
|
r#"
|
||||||
// a function with two parameters: String and i64
|
// a function with two parameters: String and i64
|
||||||
fn hello(x, y) {
|
fn hello(x, y) {
|
||||||
x.len + y
|
x.len + y
|
||||||
@ -334,7 +335,7 @@ let ast = engine.compile(true,
|
|||||||
private hidden() {
|
private hidden() {
|
||||||
throw "you shouldn't see me!";
|
throw "you shouldn't see me!";
|
||||||
}
|
}
|
||||||
")?;
|
"#)?;
|
||||||
|
|
||||||
// A custom scope can also contain any variables/constants available to the functions
|
// A custom scope can also contain any variables/constants available to the functions
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
@ -521,7 +522,7 @@ The following primitive types are supported natively:
|
|||||||
| **Floating-point number** (disabled with [`no_float`]) | `f32`, `f64` _(default)_ | `"f32"` or `"f64"` | `"123.4567"` etc. |
|
| **Floating-point number** (disabled with [`no_float`]) | `f32`, `f64` _(default)_ | `"f32"` or `"f64"` | `"123.4567"` etc. |
|
||||||
| **Boolean value** | `bool` | `"bool"` | `"true"` or `"false"` |
|
| **Boolean value** | `bool` | `"bool"` | `"true"` or `"false"` |
|
||||||
| **Unicode character** | `char` | `"char"` | `"A"`, `"x"` etc. |
|
| **Unicode character** | `char` | `"char"` | `"A"`, `"x"` etc. |
|
||||||
| **Immutable Unicode string** | `rhai::ImmutableString` (implemented as `Rc<String>` or `Arc<String>`, _not_ `&str`) | `"string"` | `"hello"` etc. |
|
| **Immutable Unicode string** | `rhai::ImmutableString` (implemented as `Rc<String>` or `Arc<String>`) | `"string"` | `"hello"` etc. |
|
||||||
| **Array** (disabled with [`no_index`]) | `rhai::Array` | `"array"` | `"[ ?, ?, ? ]"` |
|
| **Array** (disabled with [`no_index`]) | `rhai::Array` | `"array"` | `"[ ?, ?, ? ]"` |
|
||||||
| **Object map** (disabled with [`no_object`]) | `rhai::Map` | `"map"` | `#{ "a": 1, "b": 2 }` |
|
| **Object map** (disabled with [`no_object`]) | `rhai::Map` | `"map"` | `#{ "a": 1, "b": 2 }` |
|
||||||
| **Timestamp** (implemented in the [`BasicTimePackage`](#packages)) | `std::time::Instant` | `"timestamp"` | _not supported_ |
|
| **Timestamp** (implemented in the [`BasicTimePackage`](#packages)) | `std::time::Instant` | `"timestamp"` | _not supported_ |
|
||||||
@ -1038,13 +1039,13 @@ struct TestStruct {
|
|||||||
field: String
|
field: String
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember Rhai uses 'ImmutableString' instead of 'String'
|
|
||||||
impl TestStruct {
|
impl TestStruct {
|
||||||
fn get_field(&mut self) -> ImmutableString {
|
// Returning a 'String' is OK - Rhai converts it into 'ImmutableString'
|
||||||
// Make an 'ImmutableString' from a 'String'
|
fn get_field(&mut self) -> String {
|
||||||
self.field.into(0)
|
self.field.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remember Rhai uses 'ImmutableString' or '&str' instead of 'String'
|
||||||
fn set_field(&mut self, new_val: ImmutableString) {
|
fn set_field(&mut self, new_val: ImmutableString) {
|
||||||
// Get a 'String' from an 'ImmutableString'
|
// Get a 'String' from an 'ImmutableString'
|
||||||
self.field = (*new_val).clone();
|
self.field = (*new_val).clone();
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
Rhai Release Notes
|
Rhai Release Notes
|
||||||
==================
|
==================
|
||||||
|
|
||||||
Version 0.16.0
|
Version 0.15.1
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
This is a minor release which enables updating indexers (via registered indexer setters) and supports functions
|
||||||
|
with `&str` parameters (maps transparently to `ImmutableString`).
|
||||||
|
|
||||||
Breaking changes
|
Breaking changes
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
@ -14,13 +17,15 @@ Breaking changes
|
|||||||
New features
|
New features
|
||||||
------------
|
------------
|
||||||
|
|
||||||
* Indexers are now split into getters ans setters (which now support updates). The API is split into `Engine::register_indexer_get` and `Engine::register_indexer_set` with `Engine::register_indexer_get_set` being a shorthand. Similarly, `Module::set_indexer_get_fn` and `Module::set_indexer_set_fn` are added.
|
* Indexers are now split into getters and setters (which now support updates). The API is split into `Engine::register_indexer_get` and `Engine::register_indexer_set` with `Engine::register_indexer_get_set` being a shorthand. Similarly, `Module::set_indexer_get_fn` and `Module::set_indexer_set_fn` are added.
|
||||||
* `Engine:register_fn` and `Engine:register_result_fn` accepts functions that take parameters of type `&str` (immutable string slice), which maps directly to `ImmutableString`. This is to avoid needing wrappers for functions taking string parameters.
|
* `Engine:register_fn` and `Engine:register_result_fn` accepts functions that take parameters of type `&str` (immutable string slice), which maps directly to `ImmutableString`. This is to avoid needing wrappers for functions taking string parameters.
|
||||||
|
|
||||||
|
|
||||||
Version 0.15.0
|
Version 0.15.0
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
This version uses immutable strings (`ImmutableString` type) and built-in operator functions (e.g. `+`, `>`, `+=`) to improve speed, plus some bug fixes.
|
||||||
|
|
||||||
Regression fix
|
Regression fix
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
77
examples/strings.rs
Normal file
77
examples/strings.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
///! This example registers a variety of functions that operate on strings.
|
||||||
|
///! Remember to use `ImmutableString` or `&str` instead of `String` as parameters.
|
||||||
|
use rhai::{Engine, EvalAltResult, ImmutableString, RegisterFn, Scope, INT};
|
||||||
|
use std::io::{stdin, stdout, Write};
|
||||||
|
|
||||||
|
/// Trim whitespace from a string. The original string argument is changed.
|
||||||
|
///
|
||||||
|
/// This version uses `&mut ImmutableString`
|
||||||
|
fn trim_string(s: &mut ImmutableString) {
|
||||||
|
*s = s.trim().into();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Notice this is different from the built-in Rhai 'len' function for strings
|
||||||
|
/// which counts the actual number of Unicode _characters_ in a string.
|
||||||
|
/// This version simply counts the number of _bytes_ in the UTF-8 representation.
|
||||||
|
///
|
||||||
|
/// This version uses `&str`.
|
||||||
|
fn count_string_bytes(s: &str) -> INT {
|
||||||
|
s.len() as INT
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This version uses `ImmutableString` and `&str`.
|
||||||
|
fn find_substring(s: ImmutableString, sub: &str) -> INT {
|
||||||
|
s.as_str().find(sub).map(|x| x as INT).unwrap_or(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
// Create a `raw` Engine with no built-in string functions.
|
||||||
|
let mut engine = Engine::new_raw();
|
||||||
|
|
||||||
|
// Register string functions
|
||||||
|
engine.register_fn("trim", trim_string);
|
||||||
|
engine.register_fn("len", count_string_bytes);
|
||||||
|
engine.register_fn("index_of", find_substring);
|
||||||
|
|
||||||
|
// Register string functions using closures
|
||||||
|
engine.register_fn("display", |label: &str, x: INT| {
|
||||||
|
println!("{}: {}", label, x)
|
||||||
|
});
|
||||||
|
engine.register_fn("display", |label: ImmutableString, x: &str| {
|
||||||
|
println!(r#"{}: "{}""#, label, x) // Quote the input string
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut scope = Scope::new();
|
||||||
|
let mut input = String::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
scope.clear();
|
||||||
|
|
||||||
|
println!("Type something. Press Ctrl-C to exit.");
|
||||||
|
print!("strings> ");
|
||||||
|
stdout().flush().expect("couldn't flush stdout");
|
||||||
|
|
||||||
|
input.clear();
|
||||||
|
|
||||||
|
if let Err(err) = stdin().read_line(&mut input) {
|
||||||
|
panic!("input error: {}", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.push("x", input.clone());
|
||||||
|
|
||||||
|
println!("Line: {}", input.replace('\r', "\\r").replace('\n', "\\n"));
|
||||||
|
|
||||||
|
engine.consume_with_scope(
|
||||||
|
&mut scope,
|
||||||
|
r#"
|
||||||
|
display("Length", x.len());
|
||||||
|
x.trim();
|
||||||
|
display("Trimmed", x);
|
||||||
|
display("Trimmed Length", x.len());
|
||||||
|
display("Index of \"!!!\"", x.index_of("!!!"));
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
59
src/any.rs
59
src/any.rs
@ -1,5 +1,6 @@
|
|||||||
//! Helper module which defines the `Any` trait to to allow dynamic value handling.
|
//! Helper module which defines the `Any` trait to to allow dynamic value handling.
|
||||||
|
|
||||||
|
use crate::fn_native::SendSync;
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::parser::{ImmutableString, INT};
|
use crate::parser::{ImmutableString, INT};
|
||||||
use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast};
|
use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast};
|
||||||
@ -54,31 +55,6 @@ pub trait Variant: Any {
|
|||||||
fn _closed(&self) -> _Private;
|
fn _closed(&self) -> _Private;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))]
|
|
||||||
impl<T: Any + Clone> Variant for T {
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
|
||||||
self as &dyn Any
|
|
||||||
}
|
|
||||||
fn as_mut_any(&mut self) -> &mut dyn Any {
|
|
||||||
self as &mut dyn Any
|
|
||||||
}
|
|
||||||
fn as_box_any(self: Box<Self>) -> Box<dyn Any> {
|
|
||||||
self as Box<dyn Any>
|
|
||||||
}
|
|
||||||
fn type_name(&self) -> &'static str {
|
|
||||||
type_name::<T>()
|
|
||||||
}
|
|
||||||
fn into_dynamic(self) -> Dynamic {
|
|
||||||
Dynamic::from(self)
|
|
||||||
}
|
|
||||||
fn clone_into_dynamic(&self) -> Dynamic {
|
|
||||||
Dynamic::from(self.clone())
|
|
||||||
}
|
|
||||||
fn _closed(&self) -> _Private {
|
|
||||||
_Private
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait to represent any type.
|
/// Trait to represent any type.
|
||||||
///
|
///
|
||||||
/// `From<_>` is implemented for `i64` (`i32` if `only_i32`), `f64` (if not `no_float`),
|
/// `From<_>` is implemented for `i64` (`i32` if `only_i32`), `f64` (if not `no_float`),
|
||||||
@ -108,8 +84,7 @@ pub trait Variant: Any + Send + Sync {
|
|||||||
fn _closed(&self) -> _Private;
|
fn _closed(&self) -> _Private;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "sync")]
|
impl<T: Any + Clone + SendSync> Variant for T {
|
||||||
impl<T: Any + Clone + Send + Sync> Variant for T {
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
self as &dyn Any
|
self as &dyn Any
|
||||||
}
|
}
|
||||||
@ -227,17 +202,17 @@ impl fmt::Display for Dynamic {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
Union::Unit(_) => write!(f, ""),
|
Union::Unit(_) => write!(f, ""),
|
||||||
Union::Bool(value) => write!(f, "{}", value),
|
Union::Bool(value) => fmt::Display::fmt(value, f),
|
||||||
Union::Str(value) => write!(f, "{}", value),
|
Union::Str(value) => fmt::Display::fmt(value, f),
|
||||||
Union::Char(value) => write!(f, "{}", value),
|
Union::Char(value) => fmt::Display::fmt(value, f),
|
||||||
Union::Int(value) => write!(f, "{}", value),
|
Union::Int(value) => fmt::Display::fmt(value, f),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Union::Float(value) => write!(f, "{}", value),
|
Union::Float(value) => fmt::Display::fmt(value, f),
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(value) => write!(f, "{:?}", value),
|
Union::Array(value) => fmt::Debug::fmt(value, f),
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(value) => write!(f, "#{:?}", value),
|
Union::Map(value) => write!(f, "#{:?}", value),
|
||||||
Union::Module(value) => write!(f, "{:?}", value),
|
Union::Module(value) => fmt::Debug::fmt(value, f),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"),
|
Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"),
|
||||||
@ -249,18 +224,18 @@ impl fmt::Display for Dynamic {
|
|||||||
impl fmt::Debug for Dynamic {
|
impl fmt::Debug for Dynamic {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
Union::Unit(value) => write!(f, "{:?}", value),
|
Union::Unit(value) => fmt::Debug::fmt(value, f),
|
||||||
Union::Bool(value) => write!(f, "{:?}", value),
|
Union::Bool(value) => fmt::Debug::fmt(value, f),
|
||||||
Union::Str(value) => write!(f, "{:?}", value),
|
Union::Str(value) => fmt::Debug::fmt(value, f),
|
||||||
Union::Char(value) => write!(f, "{:?}", value),
|
Union::Char(value) => fmt::Debug::fmt(value, f),
|
||||||
Union::Int(value) => write!(f, "{:?}", value),
|
Union::Int(value) => fmt::Debug::fmt(value, f),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Union::Float(value) => write!(f, "{:?}", value),
|
Union::Float(value) => fmt::Debug::fmt(value, f),
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(value) => write!(f, "{:?}", value),
|
Union::Array(value) => fmt::Debug::fmt(value, f),
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(value) => write!(f, "#{:?}", value),
|
Union::Map(value) => write!(f, "#{:?}", value),
|
||||||
Union::Module(value) => write!(f, "{:?}", value),
|
Union::Module(value) => fmt::Debug::fmt(value, f),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"),
|
Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"),
|
||||||
|
@ -200,8 +200,8 @@ pub fn get_script_function_by_signature<'a>(
|
|||||||
public_only: bool,
|
public_only: bool,
|
||||||
) -> Option<&'a ScriptFnDef> {
|
) -> Option<&'a ScriptFnDef> {
|
||||||
// Qualifiers (none) + function name + number of arguments.
|
// Qualifiers (none) + function name + number of arguments.
|
||||||
let hash_fn_def = calc_fn_hash(empty(), name, params, empty());
|
let hash_script = calc_fn_hash(empty(), name, params, empty());
|
||||||
let func = module.get_fn(hash_fn_def)?;
|
let func = module.get_fn(hash_script)?;
|
||||||
if !func.is_script() {
|
if !func.is_script() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -228,7 +228,7 @@ pub fn get_script_function_by_signature<'a>(
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Currently, `Engine` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
|
/// Currently, `Engine` is neither `Send` nor `Sync`. Use the `sync` feature to make it `Send + Sync`.
|
||||||
pub struct Engine {
|
pub struct Engine {
|
||||||
/// A module containing all functions directly loaded into the Engine.
|
/// A module containing all functions directly loaded into the Engine.
|
||||||
pub(crate) global_module: Module,
|
pub(crate) global_module: Module,
|
||||||
@ -524,7 +524,7 @@ impl Engine {
|
|||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &Module,
|
lib: &Module,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
hashes: (u64, u64),
|
(hash_fn, hash_script): (u64, u64),
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
is_ref: bool,
|
is_ref: bool,
|
||||||
def_val: Option<&Dynamic>,
|
def_val: Option<&Dynamic>,
|
||||||
@ -532,7 +532,7 @@ impl Engine {
|
|||||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||||
self.inc_operations(state)?;
|
self.inc_operations(state)?;
|
||||||
|
|
||||||
let native_only = hashes.1 == 0;
|
let native_only = hash_script == 0;
|
||||||
|
|
||||||
// Check for stack overflow
|
// Check for stack overflow
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
@ -587,14 +587,14 @@ impl Engine {
|
|||||||
// Then search packages
|
// Then search packages
|
||||||
// NOTE: We skip script functions for global_module and packages, and native functions for lib
|
// NOTE: We skip script functions for global_module and packages, and native functions for lib
|
||||||
let func = if !native_only {
|
let func = if !native_only {
|
||||||
lib.get_fn(hashes.1) //.or_else(|| lib.get_fn(hashes.0))
|
lib.get_fn(hash_script) //.or_else(|| lib.get_fn(hash_fn))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
//.or_else(|| self.global_module.get_fn(hashes.1))
|
//.or_else(|| self.global_module.get_fn(hash_script))
|
||||||
.or_else(|| self.global_module.get_fn(hashes.0))
|
.or_else(|| self.global_module.get_fn(hash_fn))
|
||||||
//.or_else(|| self.packages.get_fn(hashes.1))
|
//.or_else(|| self.packages.get_fn(hash_script))
|
||||||
.or_else(|| self.packages.get_fn(hashes.0));
|
.or_else(|| self.packages.get_fn(hash_fn));
|
||||||
|
|
||||||
if let Some(func) = func {
|
if let Some(func) = func {
|
||||||
// Calling pure function in method-call?
|
// Calling pure function in method-call?
|
||||||
@ -784,18 +784,18 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has a system function an override?
|
// Has a system function an override?
|
||||||
fn has_override(&self, lib: &Module, hashes: (u64, u64)) -> bool {
|
fn has_override(&self, lib: &Module, (hash_fn, hash_script): (u64, u64)) -> bool {
|
||||||
// NOTE: We skip script functions for global_module and packages, and native functions for lib
|
// NOTE: We skip script functions for global_module and packages, and native functions for lib
|
||||||
|
|
||||||
// First check script-defined functions
|
// First check script-defined functions
|
||||||
lib.contains_fn(hashes.1)
|
lib.contains_fn(hash_script)
|
||||||
//|| lib.contains_fn(hashes.0)
|
//|| lib.contains_fn(hash_fn)
|
||||||
// Then check registered functions
|
// Then check registered functions
|
||||||
//|| self.global_module.contains_fn(hashes.1)
|
//|| self.global_module.contains_fn(hash_script)
|
||||||
|| self.global_module.contains_fn(hashes.0)
|
|| self.global_module.contains_fn(hash_fn)
|
||||||
// Then check packages
|
// Then check packages
|
||||||
//|| self.packages.contains_fn(hashes.1)
|
//|| self.packages.contains_fn(hash_script)
|
||||||
|| self.packages.contains_fn(hashes.0)
|
|| self.packages.contains_fn(hash_fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform an actual function call, taking care of special functions
|
/// Perform an actual function call, taking care of special functions
|
||||||
@ -812,7 +812,7 @@ impl Engine {
|
|||||||
lib: &Module,
|
lib: &Module,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
native_only: bool,
|
native_only: bool,
|
||||||
hash_fn_def: u64,
|
hash_script: u64,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
is_ref: bool,
|
is_ref: bool,
|
||||||
def_val: Option<&Dynamic>,
|
def_val: Option<&Dynamic>,
|
||||||
@ -821,7 +821,7 @@ impl Engine {
|
|||||||
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
|
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
|
||||||
let arg_types = args.iter().map(|a| a.type_id());
|
let arg_types = args.iter().map(|a| a.type_id());
|
||||||
let hash_fn = calc_fn_hash(empty(), fn_name, args.len(), arg_types);
|
let hash_fn = calc_fn_hash(empty(), fn_name, args.len(), arg_types);
|
||||||
let hashes = (hash_fn, if native_only { 0 } else { hash_fn_def });
|
let hashes = (hash_fn, if native_only { 0 } else { hash_script });
|
||||||
|
|
||||||
match fn_name {
|
match fn_name {
|
||||||
// type_of
|
// type_of
|
||||||
@ -1412,7 +1412,7 @@ impl Engine {
|
|||||||
Expr::Property(_) => unreachable!(),
|
Expr::Property(_) => unreachable!(),
|
||||||
|
|
||||||
// Statement block
|
// Statement block
|
||||||
Expr::Stmt(stmt) => self.eval_stmt(scope, state, lib, &stmt.0, level),
|
Expr::Stmt(x) => self.eval_stmt(scope, state, lib, &x.0, level),
|
||||||
|
|
||||||
// var op= rhs
|
// var op= rhs
|
||||||
Expr::Assignment(x) if matches!(x.0, Expr::Variable(_)) => {
|
Expr::Assignment(x) if matches!(x.0, Expr::Variable(_)) => {
|
||||||
@ -1625,7 +1625,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Module-qualified function call
|
// Module-qualified function call
|
||||||
Expr::FnCall(x) if x.1.is_some() => {
|
Expr::FnCall(x) if x.1.is_some() => {
|
||||||
let ((name, _, pos), modules, hash_fn_def, args_expr, def_val) = x.as_ref();
|
let ((name, _, pos), modules, hash_script, args_expr, def_val) = x.as_ref();
|
||||||
let modules = modules.as_ref().unwrap();
|
let modules = modules.as_ref().unwrap();
|
||||||
|
|
||||||
let mut arg_values = args_expr
|
let mut arg_values = args_expr
|
||||||
@ -1650,13 +1650,13 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// First search in script-defined functions (can override built-in)
|
// First search in script-defined functions (can override built-in)
|
||||||
let func = match module.get_qualified_fn(name, *hash_fn_def) {
|
let func = match module.get_qualified_fn(name, *hash_script) {
|
||||||
Err(err) if matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) => {
|
Err(err) if matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) => {
|
||||||
// Then search in Rust functions
|
// Then search in Rust functions
|
||||||
self.inc_operations(state)
|
self.inc_operations(state)
|
||||||
.map_err(|err| EvalAltResult::new_position(err, *pos))?;
|
.map_err(|err| EvalAltResult::new_position(err, *pos))?;
|
||||||
|
|
||||||
// Rust functions are indexed in two steps:
|
// Qualified Rust functions are indexed in two steps:
|
||||||
// 1) Calculate a hash in a similar manner to script-defined functions,
|
// 1) Calculate a hash in a similar manner to script-defined functions,
|
||||||
// i.e. qualifiers + function name + number of arguments.
|
// i.e. qualifiers + function name + number of arguments.
|
||||||
// 2) Calculate a second hash with no qualifiers, empty function name,
|
// 2) Calculate a second hash with no qualifiers, empty function name,
|
||||||
@ -1664,9 +1664,9 @@ impl Engine {
|
|||||||
let hash_fn_args =
|
let hash_fn_args =
|
||||||
calc_fn_hash(empty(), "", 0, args.iter().map(|a| a.type_id()));
|
calc_fn_hash(empty(), "", 0, args.iter().map(|a| a.type_id()));
|
||||||
// 3) The final hash is the XOR of the two hashes.
|
// 3) The final hash is the XOR of the two hashes.
|
||||||
let hash_fn_native = *hash_fn_def ^ hash_fn_args;
|
let hash_qualified_fn = *hash_script ^ hash_fn_args;
|
||||||
|
|
||||||
module.get_qualified_fn(name, hash_fn_native)
|
module.get_qualified_fn(name, hash_qualified_fn)
|
||||||
}
|
}
|
||||||
r => r,
|
r => r,
|
||||||
};
|
};
|
||||||
|
@ -89,9 +89,9 @@ impl fmt::Debug for CallableFunction {
|
|||||||
match self {
|
match self {
|
||||||
Self::Pure(_) => write!(f, "NativePureFunction"),
|
Self::Pure(_) => write!(f, "NativePureFunction"),
|
||||||
Self::Method(_) => write!(f, "NativeMethod"),
|
Self::Method(_) => write!(f, "NativeMethod"),
|
||||||
Self::Iterator(_) => write!(f, "IteratorFunction"),
|
Self::Iterator(_) => write!(f, "NativeIterator"),
|
||||||
Self::Plugin(_) => write!(f, "PluginFunction"),
|
Self::Plugin(_) => write!(f, "PluginFunction"),
|
||||||
Self::Script(fn_def) => write!(f, "{:?}", fn_def),
|
Self::Script(fn_def) => fmt::Debug::fmt(fn_def, f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs};
|
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, SendSync};
|
||||||
use crate::parser::FnAccess;
|
use crate::parser::FnAccess;
|
||||||
use crate::plugin::Plugin;
|
use crate::plugin::Plugin;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
@ -264,13 +264,7 @@ macro_rules! def_register {
|
|||||||
// ^ dereferencing function
|
// ^ dereferencing function
|
||||||
impl<
|
impl<
|
||||||
$($par: Variant + Clone,)*
|
$($par: Variant + Clone,)*
|
||||||
|
FN: Fn($($param),*) -> RET + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")]
|
|
||||||
FN: Fn($($param),*) -> RET + Send + Sync + 'static,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))]
|
|
||||||
FN: Fn($($param),*) -> RET + 'static,
|
|
||||||
|
|
||||||
RET: Variant + Clone
|
RET: Variant + Clone
|
||||||
> RegisterFn<FN, ($($mark,)*), RET> for Engine
|
> RegisterFn<FN, ($($mark,)*), RET> for Engine
|
||||||
{
|
{
|
||||||
@ -284,11 +278,7 @@ macro_rules! def_register {
|
|||||||
|
|
||||||
impl<
|
impl<
|
||||||
$($par: Variant + Clone,)*
|
$($par: Variant + Clone,)*
|
||||||
|
FN: Fn($($param),*) -> Result<Dynamic, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")]
|
|
||||||
FN: Fn($($param),*) -> Result<Dynamic, Box<EvalAltResult>> + Send + Sync + 'static,
|
|
||||||
#[cfg(not(feature = "sync"))]
|
|
||||||
FN: Fn($($param),*) -> Result<Dynamic, Box<EvalAltResult>> + 'static,
|
|
||||||
> RegisterResultFn<FN, ($($mark,)*)> for Engine
|
> RegisterResultFn<FN, ($($mark,)*)> for Engine
|
||||||
{
|
{
|
||||||
fn register_result_fn(&mut self, name: &str, f: FN) {
|
fn register_result_fn(&mut self, name: &str, f: FN) {
|
||||||
|
@ -65,7 +65,7 @@ impl fmt::Debug for Module {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"<module {:?}, functions={}>",
|
"<module vars={:?}, functions={}>",
|
||||||
self.variables,
|
self.variables,
|
||||||
self.functions.len(),
|
self.functions.len(),
|
||||||
)
|
)
|
||||||
@ -187,9 +187,9 @@ impl Module {
|
|||||||
/// If there is an existing function of the same name and number of arguments, it is replaced.
|
/// If there is an existing function of the same name and number of arguments, it is replaced.
|
||||||
pub(crate) fn set_script_fn(&mut self, fn_def: ScriptFnDef) {
|
pub(crate) fn set_script_fn(&mut self, fn_def: ScriptFnDef) {
|
||||||
// None + function name + number of arguments.
|
// None + function name + number of arguments.
|
||||||
let hash_fn_def = calc_fn_hash(empty(), &fn_def.name, fn_def.params.len(), empty());
|
let hash_script = calc_fn_hash(empty(), &fn_def.name, fn_def.params.len(), empty());
|
||||||
self.functions.insert(
|
self.functions.insert(
|
||||||
hash_fn_def,
|
hash_script,
|
||||||
(
|
(
|
||||||
fn_def.name.to_string(),
|
fn_def.name.to_string(),
|
||||||
fn_def.access,
|
fn_def.access,
|
||||||
@ -321,8 +321,7 @@ impl Module {
|
|||||||
pub fn set_fn_0<T: Variant + Clone>(
|
pub fn set_fn_0<T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn() -> FuncReturn<T> + 'static,
|
func: impl Fn() -> FuncReturn<T> + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn() -> FuncReturn<T> + Send + Sync + 'static,
|
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |_: &mut FnCallArgs| func().map(Dynamic::from);
|
let f = move |_: &mut FnCallArgs| func().map(Dynamic::from);
|
||||||
let args = [];
|
let args = [];
|
||||||
@ -350,8 +349,7 @@ impl Module {
|
|||||||
pub fn set_fn_1<A: Variant + Clone, T: Variant + Clone>(
|
pub fn set_fn_1<A: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(A) -> FuncReturn<T> + 'static,
|
func: impl Fn(A) -> FuncReturn<T> + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn(A) -> FuncReturn<T> + Send + Sync + 'static,
|
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f =
|
let f =
|
||||||
move |args: &mut FnCallArgs| func(mem::take(args[0]).cast::<A>()).map(Dynamic::from);
|
move |args: &mut FnCallArgs| func(mem::take(args[0]).cast::<A>()).map(Dynamic::from);
|
||||||
@ -380,8 +378,7 @@ impl Module {
|
|||||||
pub fn set_fn_1_mut<A: Variant + Clone, T: Variant + Clone>(
|
pub fn set_fn_1_mut<A: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A) -> FuncReturn<T> + 'static,
|
func: impl Fn(&mut A) -> FuncReturn<T> + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn(&mut A) -> FuncReturn<T> + Send + Sync + 'static,
|
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |args: &mut FnCallArgs| {
|
let f = move |args: &mut FnCallArgs| {
|
||||||
func(args[0].downcast_mut::<A>().unwrap()).map(Dynamic::from)
|
func(args[0].downcast_mut::<A>().unwrap()).map(Dynamic::from)
|
||||||
@ -412,8 +409,7 @@ impl Module {
|
|||||||
pub fn set_getter_fn<A: Variant + Clone, T: Variant + Clone>(
|
pub fn set_getter_fn<A: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A) -> FuncReturn<T> + 'static,
|
func: impl Fn(&mut A) -> FuncReturn<T> + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn(&mut A) -> FuncReturn<T> + Send + Sync + 'static,
|
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
self.set_fn_1_mut(make_getter(&name.into()), func)
|
self.set_fn_1_mut(make_getter(&name.into()), func)
|
||||||
}
|
}
|
||||||
@ -436,8 +432,7 @@ impl Module {
|
|||||||
pub fn set_fn_2<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
pub fn set_fn_2<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(A, B) -> FuncReturn<T> + 'static,
|
func: impl Fn(A, B) -> FuncReturn<T> + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn(A, B) -> FuncReturn<T> + Send + Sync + 'static,
|
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |args: &mut FnCallArgs| {
|
let f = move |args: &mut FnCallArgs| {
|
||||||
let a = mem::take(args[0]).cast::<A>();
|
let a = mem::take(args[0]).cast::<A>();
|
||||||
@ -473,8 +468,7 @@ impl Module {
|
|||||||
pub fn set_fn_2_mut<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
pub fn set_fn_2_mut<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B) -> FuncReturn<T> + 'static,
|
func: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn(&mut A, B) -> FuncReturn<T> + Send + Sync + 'static,
|
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |args: &mut FnCallArgs| {
|
let f = move |args: &mut FnCallArgs| {
|
||||||
let b = mem::take(args[1]).cast::<B>();
|
let b = mem::take(args[1]).cast::<B>();
|
||||||
@ -512,8 +506,7 @@ impl Module {
|
|||||||
pub fn set_setter_fn<A: Variant + Clone, B: Variant + Clone>(
|
pub fn set_setter_fn<A: Variant + Clone, B: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B) -> FuncReturn<()> + 'static,
|
func: impl Fn(&mut A, B) -> FuncReturn<()> + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn(&mut A, B) -> FuncReturn<()> + Send + Sync + 'static,
|
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
self.set_fn_2_mut(make_setter(&name.into()), func)
|
self.set_fn_2_mut(make_setter(&name.into()), func)
|
||||||
}
|
}
|
||||||
@ -538,8 +531,7 @@ impl Module {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub fn set_indexer_get_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
pub fn set_indexer_get_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B) -> FuncReturn<T> + 'static,
|
func: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn(&mut A, B) -> FuncReturn<T> + Send + Sync + 'static,
|
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
self.set_fn_2_mut(FUNC_INDEXER_GET, func)
|
self.set_fn_2_mut(FUNC_INDEXER_GET, func)
|
||||||
}
|
}
|
||||||
@ -567,8 +559,7 @@ impl Module {
|
|||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(A, B, C) -> FuncReturn<T> + 'static,
|
func: impl Fn(A, B, C) -> FuncReturn<T> + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn(A, B, C) -> FuncReturn<T> + Send + Sync + 'static,
|
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |args: &mut FnCallArgs| {
|
let f = move |args: &mut FnCallArgs| {
|
||||||
let a = mem::take(args[0]).cast::<A>();
|
let a = mem::take(args[0]).cast::<A>();
|
||||||
@ -610,8 +601,7 @@ impl Module {
|
|||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B, C) -> FuncReturn<T> + 'static,
|
func: impl Fn(&mut A, B, C) -> FuncReturn<T> + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn(&mut A, B, C) -> FuncReturn<T> + Send + Sync + 'static,
|
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |args: &mut FnCallArgs| {
|
let f = move |args: &mut FnCallArgs| {
|
||||||
let b = mem::take(args[1]).cast::<B>();
|
let b = mem::take(args[1]).cast::<B>();
|
||||||
@ -648,8 +638,7 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone>(
|
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B, A) -> FuncReturn<()> + 'static,
|
func: impl Fn(&mut A, B, A) -> FuncReturn<()> + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn(&mut A, B, A) -> FuncReturn<()> + Send + Sync + 'static,
|
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |args: &mut FnCallArgs| {
|
let f = move |args: &mut FnCallArgs| {
|
||||||
let b = mem::take(args[1]).cast::<B>();
|
let b = mem::take(args[1]).cast::<B>();
|
||||||
@ -691,8 +680,7 @@ impl Module {
|
|||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(A, B, C, D) -> FuncReturn<T> + 'static,
|
func: impl Fn(A, B, C, D) -> FuncReturn<T> + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn(A, B, C, D) -> FuncReturn<T> + Send + Sync + 'static,
|
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |args: &mut FnCallArgs| {
|
let f = move |args: &mut FnCallArgs| {
|
||||||
let a = mem::take(args[0]).cast::<A>();
|
let a = mem::take(args[0]).cast::<A>();
|
||||||
@ -741,8 +729,7 @@ impl Module {
|
|||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B, C, D) -> FuncReturn<T> + 'static,
|
func: impl Fn(&mut A, B, C, D) -> FuncReturn<T> + SendSync + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn(&mut A, B, C, D) -> FuncReturn<T> + Send + Sync + 'static,
|
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |args: &mut FnCallArgs| {
|
let f = move |args: &mut FnCallArgs| {
|
||||||
let b = mem::take(args[1]).cast::<B>();
|
let b = mem::take(args[1]).cast::<B>();
|
||||||
@ -791,9 +778,9 @@ impl Module {
|
|||||||
pub(crate) fn get_qualified_fn(
|
pub(crate) fn get_qualified_fn(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
hash_fn_native: u64,
|
hash_qualified_fn: u64,
|
||||||
) -> Result<&CallableFunction, Box<EvalAltResult>> {
|
) -> Result<&CallableFunction, Box<EvalAltResult>> {
|
||||||
self.all_functions.get(&hash_fn_native).ok_or_else(|| {
|
self.all_functions.get(&hash_qualified_fn).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorFunctionNotFound(
|
Box::new(EvalAltResult::ErrorFunctionNotFound(
|
||||||
name.to_string(),
|
name.to_string(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
@ -920,26 +907,26 @@ impl Module {
|
|||||||
if func.is_script() {
|
if func.is_script() {
|
||||||
let fn_def = func.get_shared_fn_def();
|
let fn_def = func.get_shared_fn_def();
|
||||||
// Qualifiers + function name + number of arguments.
|
// Qualifiers + function name + number of arguments.
|
||||||
let hash_fn_def = calc_fn_hash(
|
let hash_qualified_script = calc_fn_hash(
|
||||||
qualifiers.iter().map(|&v| v),
|
qualifiers.iter().map(|&v| v),
|
||||||
&fn_def.name,
|
&fn_def.name,
|
||||||
fn_def.params.len(),
|
fn_def.params.len(),
|
||||||
empty(),
|
empty(),
|
||||||
);
|
);
|
||||||
functions.push((hash_fn_def, fn_def.into()));
|
functions.push((hash_qualified_script, fn_def.into()));
|
||||||
} else {
|
} else {
|
||||||
// Rust functions are indexed in two steps:
|
// Qualified Rust functions are indexed in two steps:
|
||||||
// 1) Calculate a hash in a similar manner to script-defined functions,
|
// 1) Calculate a hash in a similar manner to script-defined functions,
|
||||||
// i.e. qualifiers + function name + number of arguments.
|
// i.e. qualifiers + function name + number of arguments.
|
||||||
let hash_fn_def =
|
let hash_qualified_script =
|
||||||
calc_fn_hash(qualifiers.iter().map(|&v| v), name, params.len(), empty());
|
calc_fn_hash(qualifiers.iter().map(|&v| v), name, params.len(), empty());
|
||||||
// 2) Calculate a second hash with no qualifiers, empty function name,
|
// 2) Calculate a second hash with no qualifiers, empty function name,
|
||||||
// zero number of arguments, and the actual list of argument `TypeId`'.s
|
// zero number of arguments, and the actual list of argument `TypeId`'.s
|
||||||
let hash_fn_args = calc_fn_hash(empty(), "", 0, params.iter().cloned());
|
let hash_fn_args = calc_fn_hash(empty(), "", 0, params.iter().cloned());
|
||||||
// 3) The final hash is the XOR of the two hashes.
|
// 3) The final hash is the XOR of the two hashes.
|
||||||
let hash_fn_native = hash_fn_def ^ hash_fn_args;
|
let hash_qualified_fn = hash_qualified_script ^ hash_fn_args;
|
||||||
|
|
||||||
functions.push((hash_fn_native, func.clone()));
|
functions.push((hash_qualified_fn, func.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
646
src/parser.rs
646
src/parser.rs
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,8 @@ use crate::stdlib::{
|
|||||||
|
|
||||||
type LERR = LexError;
|
type LERR = LexError;
|
||||||
|
|
||||||
|
pub type TokenStream<'a> = Peekable<TokenIterator<'a>>;
|
||||||
|
|
||||||
/// A location (line number + character position) in the input script.
|
/// A location (line number + character position) in the input script.
|
||||||
///
|
///
|
||||||
/// In order to keep footprint small, both line number and character position have 16-bit unsigned resolution,
|
/// In order to keep footprint small, both line number and character position have 16-bit unsigned resolution,
|
||||||
|
@ -542,9 +542,7 @@ impl<T: Default> StaticVec<T> {
|
|||||||
|
|
||||||
impl<T: fmt::Debug> fmt::Debug for StaticVec<T> {
|
impl<T: fmt::Debug> fmt::Debug for StaticVec<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "[ ")?;
|
fmt::Debug::fmt(&self.iter().collect::<Vec<_>>(), f)
|
||||||
self.iter().try_for_each(|v| write!(f, "{:?}, ", v))?;
|
|
||||||
write!(f, "]")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ fn test_decrement() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.eval::<String>(r#"let s = "test"; s -= "ing"; s"#).expect_err("expects error"),
|
*engine.eval::<String>(r#"let s = "test"; s -= "ing"; s"#).expect_err("expects error"),
|
||||||
EvalAltResult::ErrorFunctionNotFound(err, _) if err == "- (string, string)"
|
EvalAltResult::ErrorFunctionNotFound(err, _) if err == "- (&str | ImmutableString, &str | ImmutableString)"
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -168,7 +168,7 @@ fn test_string_fn() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.eval::<INT>(r#"foo3("hello")"#).expect_err("should error"),
|
*engine.eval::<INT>(r#"foo3("hello")"#).expect_err("should error"),
|
||||||
EvalAltResult::ErrorFunctionNotFound(ref x, _) if x == "foo3 (&str | ImmutableString)"
|
EvalAltResult::ErrorFunctionNotFound(err, _) if err == "foo3 (&str | ImmutableString)"
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
Loading…
Reference in New Issue
Block a user