commit
d0fc90d577
5
.github/workflows/build.yml
vendored
5
.github/workflows/build.yml
vendored
@ -4,7 +4,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- closures
|
|
||||||
pull_request: {}
|
pull_request: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@ -23,7 +22,7 @@ jobs:
|
|||||||
- "--features sync"
|
- "--features sync"
|
||||||
- "--features no_optimize"
|
- "--features no_optimize"
|
||||||
- "--features no_float"
|
- "--features no_float"
|
||||||
- "--features only_i32"
|
- "--tests --features only_i32"
|
||||||
- "--features only_i64"
|
- "--features only_i64"
|
||||||
- "--features no_index"
|
- "--features no_index"
|
||||||
- "--features no_object"
|
- "--features no_object"
|
||||||
@ -51,7 +50,7 @@ jobs:
|
|||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: --all {{matrix.flags}}
|
args: --all ${{matrix.flags}}
|
||||||
# no-std builds are a bit more extensive to test
|
# no-std builds are a bit more extensive to test
|
||||||
no_std_build:
|
no_std_build:
|
||||||
name: NoStdBuild
|
name: NoStdBuild
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rhai"
|
name = "rhai"
|
||||||
version = "0.18.0"
|
version = "0.19.0"
|
||||||
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"
|
||||||
@ -23,7 +23,6 @@ smallvec = { version = "1.4.1", default-features = false }
|
|||||||
[features]
|
[features]
|
||||||
#default = ["unchecked", "sync", "no_optimize", "no_float", "only_i32", "no_index", "no_object", "no_function", "no_module"]
|
#default = ["unchecked", "sync", "no_optimize", "no_float", "only_i32", "no_index", "no_object", "no_function", "no_module"]
|
||||||
default = []
|
default = []
|
||||||
plugins = [] # custom plugins support
|
|
||||||
unchecked = [] # unchecked arithmetic
|
unchecked = [] # unchecked arithmetic
|
||||||
sync = [] # restrict to only types that implement Send + Sync
|
sync = [] # restrict to only types that implement Send + Sync
|
||||||
no_optimize = [] # no script optimizer
|
no_optimize = [] # no script optimizer
|
||||||
@ -32,7 +31,7 @@ only_i32 = [] # set INT=i32 (useful for 32-bit systems)
|
|||||||
only_i64 = [] # set INT=i64 (default) and disable support for all other integer types
|
only_i64 = [] # set INT=i64 (default) and disable support for all other integer types
|
||||||
no_index = [] # no arrays and indexing
|
no_index = [] # no arrays and indexing
|
||||||
no_object = [] # no custom objects
|
no_object = [] # no custom objects
|
||||||
no_function = [] # no script-defined functions
|
no_function = [ "no_closure" ] # no script-defined functions (meaning no closures)
|
||||||
no_closure = [] # no automatic sharing and capture of anonymous functions to external variables
|
no_closure = [] # no automatic sharing and capture of anonymous functions to external variables
|
||||||
no_module = [] # no modules
|
no_module = [] # no modules
|
||||||
internals = [] # expose internal data structures
|
internals = [] # expose internal data structures
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
Rhai Release Notes
|
Rhai Release Notes
|
||||||
==================
|
==================
|
||||||
|
|
||||||
Version 0.18.0
|
Version 0.19.0
|
||||||
|
==============
|
||||||
|
|
||||||
|
|
||||||
|
Version 0.18.1
|
||||||
==============
|
==============
|
||||||
|
|
||||||
This version adds:
|
This version adds:
|
||||||
|
|
||||||
* Anonymous functions (in Rust closure syntax). Simplifies creation of single-use ad-hoc functions.
|
* Anonymous functions (in Rust closure syntax). Simplifies creation of single-use ad-hoc functions.
|
||||||
* Currying of function pointers.
|
* Currying of function pointers.
|
||||||
* Closures - auto-currying of anonymous functions to capture shared variables from the external scope.
|
* Closures - auto-currying of anonymous functions to capture shared variables from the external scope. Use the `no_closure` feature to disable sharing values and capturing.
|
||||||
* Binding the `this` pointer in a function pointer `call`.
|
* Binding the `this` pointer in a function pointer `call`.
|
||||||
* Capturing call scope via `func!(...)` syntax.
|
* Capturing call scope via `func!(...)` syntax.
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "0.18.0",
|
"version": "0.19.0",
|
||||||
"repoHome": "https://github.com/jonathandturner/rhai/blob/master",
|
"repoHome": "https://github.com/jonathandturner/rhai/blob/master",
|
||||||
"repoTree": "https://github.com/jonathandturner/rhai/tree/master",
|
"repoTree": "https://github.com/jonathandturner/rhai/tree/master",
|
||||||
"rootUrl": "",
|
"rootUrl": "",
|
||||||
|
@ -200,8 +200,10 @@ fn implementation_func(
|
|||||||
|
|
||||||
// Evaluate the condition expression
|
// Evaluate the condition expression
|
||||||
let stop = !engine.eval_expression_tree(context, scope, condition)?
|
let stop = !engine.eval_expression_tree(context, scope, condition)?
|
||||||
.as_bool().map_err(|_| EvalAltResult::ErrorBooleanArgMismatch(
|
.as_bool()
|
||||||
"do-while".into(), expr.position()))?;
|
.map_err(|_| EvalAltResult::ErrorBooleanArgMismatch(
|
||||||
|
"do-while".into(), expr.position()
|
||||||
|
))?;
|
||||||
|
|
||||||
if stop {
|
if stop {
|
||||||
break;
|
break;
|
||||||
|
@ -36,6 +36,8 @@ update(array[0]); // <- 'array[0]' is an expression returning a calculated val
|
|||||||
array[0].update(); // <- call in method-call style will update 'a'
|
array[0].update(); // <- call in method-call style will update 'a'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**IMPORTANT: Rhai does NOT support normal references (i.e. `&T`) as parameters.**
|
||||||
|
|
||||||
|
|
||||||
Number of Parameters
|
Number of Parameters
|
||||||
--------------------
|
--------------------
|
||||||
@ -51,8 +53,8 @@ The following table illustrates the differences:
|
|||||||
| Rhai script | _n_ | `this` | `fn method(x, y) {}` |
|
| Rhai script | _n_ | `this` | `fn method(x, y) {}` |
|
||||||
|
|
||||||
|
|
||||||
`&mut` is Efficient (Except for `ImmutableString`)
|
`&mut` is Efficient, Except for `ImmutableString`
|
||||||
------------------------------------------------
|
-----------------------------------------------
|
||||||
|
|
||||||
Using a `&mut` first parameter is highly encouraged when using types that are expensive to clone,
|
Using a `&mut` first parameter is highly encouraged when using types that are expensive to clone,
|
||||||
even when the intention is not to mutate that argument, because it avoids cloning that argument value.
|
even when the intention is not to mutate that argument, because it avoids cloning that argument value.
|
||||||
|
@ -7,10 +7,17 @@ Import a Module
|
|||||||
`import` Statement
|
`import` Statement
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
A module can be _imported_ via the `import` statement, and its members are accessed via '`::`' similar to C++.
|
A module can be _imported_ via the `import` statement, and be given a name.
|
||||||
|
Its members can be accessed via '`::`' similar to C++.
|
||||||
|
|
||||||
|
A module that is only `import`-ed but not under any module name is commonly used for initialization purposes,
|
||||||
|
where the module script contains initialization statements that puts the functions registered with the
|
||||||
|
[`Engine`] into a particular state.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
import "crypto" as lock; // import the script file 'crypto.rhai' as a module named 'lock'
|
import "crypto_init"; // run the script file 'crypto_init.rhai' without creating an imported module
|
||||||
|
|
||||||
|
import "crypto" as lock; // run the script file 'crypto.rhai' and import it as a module named 'lock'
|
||||||
|
|
||||||
lock::encrypt(secret); // use functions defined under the module via '::'
|
lock::encrypt(secret); // use functions defined under the module via '::'
|
||||||
|
|
||||||
|
@ -83,6 +83,8 @@ engine
|
|||||||
***Note**: Rhai follows the convention that methods of custom types take a `&mut` first parameter
|
***Note**: Rhai follows the convention that methods of custom types take a `&mut` first parameter
|
||||||
so that invoking methods can update the types. All other parameters in Rhai are passed by value (i.e. clones).*
|
so that invoking methods can update the types. All other parameters in Rhai are passed by value (i.e. clones).*
|
||||||
|
|
||||||
|
**IMPORTANT: Rhai does NOT support normal references (i.e. `&T`) as parameters.**
|
||||||
|
|
||||||
Use the Custom Type in Scripts
|
Use the Custom Type in Scripts
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
@ -125,8 +127,8 @@ Under [`no_object`], however, the _method_ style of function calls
|
|||||||
let result = engine.eval::<()>("let x = [1, 2, 3]; x.clear()")?;
|
let result = engine.eval::<()>("let x = [1, 2, 3]; x.clear()")?;
|
||||||
```
|
```
|
||||||
|
|
||||||
[`type_of()`]
|
`type_of()` a Custom Type
|
||||||
-------------
|
-------------------------
|
||||||
|
|
||||||
[`type_of()`] works fine with custom types and returns the name of the type.
|
[`type_of()`] works fine with custom types and returns the name of the type.
|
||||||
|
|
||||||
|
@ -42,3 +42,5 @@ let result = engine.eval::<String>(r#"let a = new_ts(); a.xyz = "42"; a.xyz"#)?;
|
|||||||
|
|
||||||
println!("Answer: {}", result); // prints 42
|
println!("Answer: {}", result); // prints 42
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**IMPORTANT: Rhai does NOT support normal references (i.e. `&T`) as parameters.**
|
||||||
|
@ -38,7 +38,7 @@ impl ModuleResolver for MyModuleResolver {
|
|||||||
let module: Module = load_secret_module(path);
|
let module: Module = load_secret_module(path);
|
||||||
Ok(module)
|
Ok(module)
|
||||||
} else {
|
} else {
|
||||||
Err(Box::new(EvalAltResult::ErrorModuleNotFound(path.into(), pos)))
|
Err(EvalAltResult::ErrorModuleNotFound(path.into(), pos).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,10 +95,11 @@ When there is a mutable reference to the `this` object (i.e. the first argument)
|
|||||||
there can be no other immutable references to `args`, otherwise the Rust borrow checker will complain.
|
there can be no other immutable references to `args`, otherwise the Rust borrow checker will complain.
|
||||||
|
|
||||||
|
|
||||||
Example - Passing a Function Pointer to a Rust Function
|
Example - Passing a Callback to a Rust Function
|
||||||
------------------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
The low-level API is useful when there is a need to interact with the scripting [`Engine`] within a function.
|
The low-level API is useful when there is a need to interact with the scripting [`Engine`]
|
||||||
|
within a function.
|
||||||
|
|
||||||
The following example registers a function that takes a [function pointer] as an argument,
|
The following example registers a function that takes a [function pointer] as an argument,
|
||||||
then calls it within the same [`Engine`]. This way, a _callback_ function can be provided
|
then calls it within the same [`Engine`]. This way, a _callback_ function can be provided
|
||||||
@ -140,6 +141,24 @@ let result = engine.eval::<i64>(r#"
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
TL;DR - Why `read_lock` and `write_lock`
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
The `Dynamic` API that casts it to a reference to a particular data type is `read_lock`
|
||||||
|
(for an immutable reference) and `write_lock` (for a mutable reference).
|
||||||
|
|
||||||
|
As the naming shows, something is _locked_ in order to allow this access, and that something
|
||||||
|
is a _shared value_ created by [capturing][automatic currying] variables from [closures].
|
||||||
|
|
||||||
|
Shared values are implemented as `Rc<RefCell<Dynamic>>` (`Arc<RwLock<Dynamic>>` under [`sync`]).
|
||||||
|
|
||||||
|
If the value is _not_ a shared value, or if running under [`no_closure`] where there is
|
||||||
|
no [capturing][automatic currying], this API de-sugars to a simple `downcast_ref` and `downcast_mut`.
|
||||||
|
|
||||||
|
If the value is a shared value, then it is first locked and the returned lock guard
|
||||||
|
then allows access to the underlying value in the specified type.
|
||||||
|
|
||||||
|
|
||||||
Hold Multiple References
|
Hold Multiple References
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
@ -152,9 +171,9 @@ to partition the slice:
|
|||||||
let (first, rest) = args.split_at_mut(1);
|
let (first, rest) = args.split_at_mut(1);
|
||||||
|
|
||||||
// Mutable reference to the first parameter
|
// Mutable reference to the first parameter
|
||||||
let this_ptr = first[0].downcast_mut::<A>().unwrap();
|
let this_ptr: &mut Dynamic = &mut *first[0].write_lock::<A>().unwrap();
|
||||||
|
|
||||||
// Immutable reference to the second value parameter
|
// Immutable reference to the second value parameter
|
||||||
// This can be mutable but there is no point because the parameter is passed by value
|
// This can be mutable but there is no point because the parameter is passed by value
|
||||||
let value_ref = rest[0].read_lock::<B>().unwrap();
|
let value_ref: &Dynamic = &*rest[0].read_lock::<B>().unwrap();
|
||||||
```
|
```
|
||||||
|
@ -410,7 +410,7 @@ impl fmt::Display for Dynamic {
|
|||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
Union::Shared(cell) => fmt::Display::fmt(*cell.read_lock().unwrap(), f),
|
Union::Shared(cell) => fmt::Display::fmt(&*cell.read().unwrap(), f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -448,7 +448,7 @@ impl fmt::Debug for Dynamic {
|
|||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
Union::Shared(cell) => fmt::Display::fmt(*cell.read_lock().unwrap(), f),
|
Union::Shared(cell) => fmt::Debug::fmt(&*cell.read().unwrap(), f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
46
src/api.rs
46
src/api.rs
@ -3,10 +3,9 @@
|
|||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::engine::{Engine, Imports, State};
|
use crate::engine::{Engine, Imports, State};
|
||||||
use crate::error::ParseError;
|
use crate::error::ParseError;
|
||||||
use crate::fn_call::ensure_no_data_race;
|
|
||||||
use crate::fn_native::{IteratorFn, SendSync};
|
use crate::fn_native::{IteratorFn, SendSync};
|
||||||
use crate::module::{FuncReturn, Module};
|
use crate::module::{FuncReturn, Module};
|
||||||
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::parser::AST;
|
use crate::parser::AST;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
@ -24,14 +23,22 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::{engine::get_script_function_by_signature, fn_args::FuncArgs, utils::StaticVec};
|
use crate::{
|
||||||
|
engine::get_script_function_by_signature, fn_args::FuncArgs, fn_call::ensure_no_data_race,
|
||||||
|
utils::StaticVec,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
|
use crate::optimize::optimize_into_ast;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::{type_name, TypeId},
|
any::{type_name, TypeId},
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
mem,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
|
use crate::stdlib::mem;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use crate::stdlib::{fs::File, io::prelude::*, path::PathBuf};
|
use crate::stdlib::{fs::File, io::prelude::*, path::PathBuf};
|
||||||
@ -601,21 +608,13 @@ impl Engine {
|
|||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
fn read_file(path: PathBuf) -> Result<String, Box<EvalAltResult>> {
|
fn read_file(path: PathBuf) -> Result<String, Box<EvalAltResult>> {
|
||||||
let mut f = File::open(path.clone()).map_err(|err| {
|
let mut f = File::open(path.clone()).map_err(|err| {
|
||||||
Box::new(EvalAltResult::ErrorReadingScriptFile(
|
EvalAltResult::ErrorReadingScriptFile(path.clone(), Position::none(), err)
|
||||||
path.clone(),
|
|
||||||
Position::none(),
|
|
||||||
err,
|
|
||||||
))
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
|
|
||||||
f.read_to_string(&mut contents).map_err(|err| {
|
f.read_to_string(&mut contents).map_err(|err| {
|
||||||
Box::new(EvalAltResult::ErrorReadingScriptFile(
|
EvalAltResult::ErrorReadingScriptFile(path.clone(), Position::none(), err)
|
||||||
path.clone(),
|
|
||||||
Position::none(),
|
|
||||||
err,
|
|
||||||
))
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(contents)
|
Ok(contents)
|
||||||
@ -1035,11 +1034,12 @@ impl Engine {
|
|||||||
let typ = self.map_type_name(result.type_name());
|
let typ = self.map_type_name(result.type_name());
|
||||||
|
|
||||||
return result.try_cast::<T>().ok_or_else(|| {
|
return result.try_cast::<T>().ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
self.map_type_name(type_name::<T>()).into(),
|
self.map_type_name(type_name::<T>()).into(),
|
||||||
typ.into(),
|
typ.into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
|
.into()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1183,11 +1183,12 @@ impl Engine {
|
|||||||
let typ = self.map_type_name(result.type_name());
|
let typ = self.map_type_name(result.type_name());
|
||||||
|
|
||||||
return result.try_cast().ok_or_else(|| {
|
return result.try_cast().ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
self.map_type_name(type_name::<T>()).into(),
|
self.map_type_name(type_name::<T>()).into(),
|
||||||
typ.into(),
|
typ.into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
|
.into()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1271,13 +1272,8 @@ impl Engine {
|
|||||||
) -> FuncReturn<Dynamic> {
|
) -> FuncReturn<Dynamic> {
|
||||||
let lib = lib.as_ref();
|
let lib = lib.as_ref();
|
||||||
let mut args: StaticVec<_> = arg_values.iter_mut().collect();
|
let mut args: StaticVec<_> = arg_values.iter_mut().collect();
|
||||||
let fn_def =
|
let fn_def = get_script_function_by_signature(lib, name, args.len(), true)
|
||||||
get_script_function_by_signature(lib, name, args.len(), true).ok_or_else(|| {
|
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?;
|
||||||
Box::new(EvalAltResult::ErrorFunctionNotFound(
|
|
||||||
name.into(),
|
|
||||||
Position::none(),
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let mut state = State::new();
|
let mut state = State::new();
|
||||||
let mut mods = Imports::new();
|
let mut mods = Imports::new();
|
||||||
|
157
src/engine.rs
157
src/engine.rs
@ -228,9 +228,7 @@ impl Target<'_> {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Self::LockGuard((r, _)) => **r = new_val,
|
Self::LockGuard((r, _)) => **r = new_val,
|
||||||
Self::Value(_) => {
|
Self::Value(_) => {
|
||||||
return Err(Box::new(EvalAltResult::ErrorAssignmentToUnknownLHS(
|
return EvalAltResult::ErrorAssignmentToUnknownLHS(Position::none()).into();
|
||||||
Position::none(),
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::StringChar(string, index, _) if string.is::<ImmutableString>() => {
|
Self::StringChar(string, index, _) if string.is::<ImmutableString>() => {
|
||||||
@ -517,12 +515,7 @@ pub fn search_imports<'s>(
|
|||||||
.rev()
|
.rev()
|
||||||
.find(|(n, _)| n == root)
|
.find(|(n, _)| n == root)
|
||||||
.map(|(_, m)| m)
|
.map(|(_, m)| m)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| EvalAltResult::ErrorModuleNotFound(root.to_string(), *root_pos))?
|
||||||
Box::new(EvalAltResult::ErrorModuleNotFound(
|
|
||||||
root.to_string(),
|
|
||||||
*root_pos,
|
|
||||||
))
|
|
||||||
})?
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,12 +543,7 @@ pub fn search_imports_mut<'s>(
|
|||||||
.rev()
|
.rev()
|
||||||
.find(|(n, _)| n == root)
|
.find(|(n, _)| n == root)
|
||||||
.map(|(_, m)| m)
|
.map(|(_, m)| m)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| EvalAltResult::ErrorModuleNotFound(root.to_string(), *root_pos))?
|
||||||
Box::new(EvalAltResult::ErrorModuleNotFound(
|
|
||||||
root.to_string(),
|
|
||||||
*root_pos,
|
|
||||||
))
|
|
||||||
})?
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,10 +565,11 @@ pub fn search_namespace<'s, 'a>(
|
|||||||
.get_qualified_var_mut(*hash_var)
|
.get_qualified_var_mut(*hash_var)
|
||||||
.map_err(|err| match *err {
|
.map_err(|err| match *err {
|
||||||
EvalAltResult::ErrorVariableNotFound(_, _) => {
|
EvalAltResult::ErrorVariableNotFound(_, _) => {
|
||||||
Box::new(EvalAltResult::ErrorVariableNotFound(
|
EvalAltResult::ErrorVariableNotFound(
|
||||||
format!("{}{}", modules, name),
|
format!("{}{}", modules, name),
|
||||||
*pos,
|
*pos,
|
||||||
))
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
_ => err.new_position(*pos),
|
_ => err.new_position(*pos),
|
||||||
})?;
|
})?;
|
||||||
@ -612,7 +601,7 @@ pub fn search_scope_only<'s, 'a>(
|
|||||||
if let Some(val) = this_ptr {
|
if let Some(val) = this_ptr {
|
||||||
return Ok(((*val).into(), KEYWORD_THIS, ScopeEntryType::Normal, *pos));
|
return Ok(((*val).into(), KEYWORD_THIS, ScopeEntryType::Normal, *pos));
|
||||||
} else {
|
} else {
|
||||||
return Err(Box::new(EvalAltResult::ErrorUnboundThis(*pos)));
|
return EvalAltResult::ErrorUnboundThis(*pos).into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -625,7 +614,7 @@ pub fn search_scope_only<'s, 'a>(
|
|||||||
// Find the variable in the scope
|
// Find the variable in the scope
|
||||||
scope
|
scope
|
||||||
.get_index(name)
|
.get_index(name)
|
||||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorVariableNotFound(name.into(), *pos)))?
|
.ok_or_else(|| EvalAltResult::ErrorVariableNotFound(name.into(), *pos))?
|
||||||
.0
|
.0
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -634,7 +623,7 @@ pub fn search_scope_only<'s, 'a>(
|
|||||||
// Check for data race - probably not necessary because the only place it should conflict is in a method call
|
// Check for data race - probably not necessary because the only place it should conflict is in a method call
|
||||||
// when the object variable is also used as a parameter.
|
// when the object variable is also used as a parameter.
|
||||||
// if cfg!(not(feature = "no_closure")) && val.is_locked() {
|
// if cfg!(not(feature = "no_closure")) && val.is_locked() {
|
||||||
// return Err(Box::new(EvalAltResult::ErrorDataRace(name.into(), *pos)));
|
// return EvalAltResult::ErrorDataRace(name.into(), *pos).into();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
Ok((val, name, typ, *pos))
|
Ok((val, name, typ, *pos))
|
||||||
@ -966,10 +955,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Syntax error
|
// Syntax error
|
||||||
_ => Err(Box::new(EvalAltResult::ErrorDotExpr(
|
_ => EvalAltResult::ErrorDotExpr("".into(), rhs.position()).into(),
|
||||||
"".into(),
|
|
||||||
rhs.position(),
|
|
||||||
))),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1016,10 +1002,8 @@ impl Engine {
|
|||||||
// Constants cannot be modified
|
// Constants cannot be modified
|
||||||
match typ {
|
match typ {
|
||||||
ScopeEntryType::Constant if new_val.is_some() => {
|
ScopeEntryType::Constant if new_val.is_some() => {
|
||||||
return Err(Box::new(EvalAltResult::ErrorAssignmentToConstant(
|
return EvalAltResult::ErrorAssignmentToConstant(var_name.to_string(), pos)
|
||||||
var_name.to_string(),
|
.into();
|
||||||
pos,
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
ScopeEntryType::Constant | ScopeEntryType::Normal => (),
|
ScopeEntryType::Constant | ScopeEntryType::Normal => (),
|
||||||
}
|
}
|
||||||
@ -1033,9 +1017,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// {expr}.??? = ??? or {expr}[???] = ???
|
// {expr}.??? = ??? or {expr}[???] = ???
|
||||||
expr if new_val.is_some() => {
|
expr if new_val.is_some() => {
|
||||||
return Err(Box::new(EvalAltResult::ErrorAssignmentToUnknownLHS(
|
return EvalAltResult::ErrorAssignmentToUnknownLHS(expr.position()).into();
|
||||||
expr.position(),
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
// {expr}.??? or {expr}[???]
|
// {expr}.??? or {expr}[???]
|
||||||
expr => {
|
expr => {
|
||||||
@ -1160,12 +1142,10 @@ impl Engine {
|
|||||||
arr.get_mut(index as usize)
|
arr.get_mut(index as usize)
|
||||||
.map(Target::from)
|
.map(Target::from)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos))
|
EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos).into()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(Box::new(EvalAltResult::ErrorArrayBounds(
|
EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos).into()
|
||||||
arr_len, index, idx_pos,
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1200,13 +1180,11 @@ impl Engine {
|
|||||||
if index >= 0 {
|
if index >= 0 {
|
||||||
let offset = index as usize;
|
let offset = index as usize;
|
||||||
let ch = s.chars().nth(offset).ok_or_else(|| {
|
let ch = s.chars().nth(offset).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorStringBounds(chars_len, index, idx_pos))
|
EvalAltResult::ErrorStringBounds(chars_len, index, idx_pos)
|
||||||
})?;
|
})?;
|
||||||
Ok(Target::StringChar(val, offset, ch.into()))
|
Ok(Target::StringChar(val, offset, ch.into()))
|
||||||
} else {
|
} else {
|
||||||
Err(Box::new(EvalAltResult::ErrorStringBounds(
|
EvalAltResult::ErrorStringBounds(chars_len, index, idx_pos).into()
|
||||||
chars_len, index, idx_pos,
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1227,10 +1205,11 @@ impl Engine {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => Err(Box::new(EvalAltResult::ErrorIndexingType(
|
_ => EvalAltResult::ErrorIndexingType(
|
||||||
self.map_type_name(val.type_name()).into(),
|
self.map_type_name(val.type_name()).into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))),
|
)
|
||||||
|
.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1284,15 +1263,15 @@ impl Engine {
|
|||||||
// Only allows String or char
|
// Only allows String or char
|
||||||
Dynamic(Union::Str(s)) => Ok(rhs_value.contains_key(&s).into()),
|
Dynamic(Union::Str(s)) => Ok(rhs_value.contains_key(&s).into()),
|
||||||
Dynamic(Union::Char(c)) => Ok(rhs_value.contains_key(&c.to_string()).into()),
|
Dynamic(Union::Char(c)) => Ok(rhs_value.contains_key(&c.to_string()).into()),
|
||||||
_ => Err(Box::new(EvalAltResult::ErrorInExpr(lhs.position()))),
|
_ => EvalAltResult::ErrorInExpr(lhs.position()).into(),
|
||||||
},
|
},
|
||||||
Dynamic(Union::Str(rhs_value)) => match lhs_value {
|
Dynamic(Union::Str(rhs_value)) => match lhs_value {
|
||||||
// Only allows String or char
|
// Only allows String or char
|
||||||
Dynamic(Union::Str(s)) => Ok(rhs_value.contains(s.as_str()).into()),
|
Dynamic(Union::Str(s)) => Ok(rhs_value.contains(s.as_str()).into()),
|
||||||
Dynamic(Union::Char(c)) => Ok(rhs_value.contains(c).into()),
|
Dynamic(Union::Char(c)) => Ok(rhs_value.contains(c).into()),
|
||||||
_ => Err(Box::new(EvalAltResult::ErrorInExpr(lhs.position()))),
|
_ => EvalAltResult::ErrorInExpr(lhs.position()).into(),
|
||||||
},
|
},
|
||||||
_ => Err(Box::new(EvalAltResult::ErrorInExpr(rhs.position()))),
|
_ => EvalAltResult::ErrorInExpr(rhs.position()).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1323,7 +1302,7 @@ impl Engine {
|
|||||||
if let Some(val) = this_ptr {
|
if let Some(val) = this_ptr {
|
||||||
Ok(val.clone())
|
Ok(val.clone())
|
||||||
} else {
|
} else {
|
||||||
Err(Box::new(EvalAltResult::ErrorUnboundThis((x.0).1)))
|
EvalAltResult::ErrorUnboundThis((x.0).1).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Variable(_) => {
|
Expr::Variable(_) => {
|
||||||
@ -1454,16 +1433,13 @@ impl Engine {
|
|||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
// Error assignment to constant
|
// Error assignment to constant
|
||||||
expr if expr.is_constant() => {
|
expr if expr.is_constant() => EvalAltResult::ErrorAssignmentToConstant(
|
||||||
Err(Box::new(EvalAltResult::ErrorAssignmentToConstant(
|
expr.get_constant_str(),
|
||||||
expr.get_constant_str(),
|
|
||||||
expr.position(),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
// Syntax error
|
|
||||||
expr => Err(Box::new(EvalAltResult::ErrorAssignmentToUnknownLHS(
|
|
||||||
expr.position(),
|
expr.position(),
|
||||||
))),
|
)
|
||||||
|
.into(),
|
||||||
|
// Syntax error
|
||||||
|
expr => EvalAltResult::ErrorAssignmentToUnknownLHS(expr.position()).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1632,7 +1608,7 @@ impl Engine {
|
|||||||
|
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
||||||
.as_bool()
|
.as_bool()
|
||||||
.map_err(|_| Box::new(EvalAltResult::ErrorLogicGuard(expr.position())))
|
.map_err(|_| EvalAltResult::ErrorLogicGuard(expr.position()).into())
|
||||||
.and_then(|guard_val| {
|
.and_then(|guard_val| {
|
||||||
if guard_val {
|
if guard_val {
|
||||||
self.eval_stmt(scope, mods, state, lib, this_ptr, if_block, level)
|
self.eval_stmt(scope, mods, state, lib, this_ptr, if_block, level)
|
||||||
@ -1665,9 +1641,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(false) => return Ok(Default::default()),
|
Ok(false) => return Ok(Default::default()),
|
||||||
Err(_) => {
|
Err(_) => return EvalAltResult::ErrorLogicGuard(expr.position()).into(),
|
||||||
return Err(Box::new(EvalAltResult::ErrorLogicGuard(expr.position())))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1727,43 +1701,45 @@ impl Engine {
|
|||||||
state.scope_level -= 1;
|
state.scope_level -= 1;
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
} else {
|
} else {
|
||||||
Err(Box::new(EvalAltResult::ErrorFor(x.1.position())))
|
EvalAltResult::ErrorFor(x.1.position()).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Continue statement
|
// Continue statement
|
||||||
Stmt::Continue(pos) => Err(Box::new(EvalAltResult::ErrorLoopBreak(false, *pos))),
|
Stmt::Continue(pos) => EvalAltResult::ErrorLoopBreak(false, *pos).into(),
|
||||||
|
|
||||||
// Break statement
|
// Break statement
|
||||||
Stmt::Break(pos) => Err(Box::new(EvalAltResult::ErrorLoopBreak(true, *pos))),
|
Stmt::Break(pos) => EvalAltResult::ErrorLoopBreak(true, *pos).into(),
|
||||||
|
|
||||||
// Return value
|
// Return value
|
||||||
Stmt::ReturnWithVal(x) if x.1.is_some() && (x.0).0 == ReturnType::Return => {
|
Stmt::ReturnWithVal(x) if x.1.is_some() && (x.0).0 == ReturnType::Return => {
|
||||||
let expr = x.1.as_ref().unwrap();
|
let expr = x.1.as_ref().unwrap();
|
||||||
Err(Box::new(EvalAltResult::Return(
|
EvalAltResult::Return(
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?,
|
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?,
|
||||||
(x.0).1,
|
(x.0).1,
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty return
|
// Empty return
|
||||||
Stmt::ReturnWithVal(x) if (x.0).0 == ReturnType::Return => {
|
Stmt::ReturnWithVal(x) if (x.0).0 == ReturnType::Return => {
|
||||||
Err(Box::new(EvalAltResult::Return(Default::default(), (x.0).1)))
|
EvalAltResult::Return(Default::default(), (x.0).1).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Throw value
|
// Throw value
|
||||||
Stmt::ReturnWithVal(x) if x.1.is_some() && (x.0).0 == ReturnType::Exception => {
|
Stmt::ReturnWithVal(x) if x.1.is_some() && (x.0).0 == ReturnType::Exception => {
|
||||||
let expr = x.1.as_ref().unwrap();
|
let expr = x.1.as_ref().unwrap();
|
||||||
let val = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
let val = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||||
Err(Box::new(EvalAltResult::ErrorRuntime(
|
EvalAltResult::ErrorRuntime(
|
||||||
val.take_string().unwrap_or_else(|_| "".into()),
|
val.take_string().unwrap_or_else(|_| "".into()),
|
||||||
(x.0).1,
|
(x.0).1,
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty throw
|
// Empty throw
|
||||||
Stmt::ReturnWithVal(x) if (x.0).0 == ReturnType::Exception => {
|
Stmt::ReturnWithVal(x) if (x.0).0 == ReturnType::Exception => {
|
||||||
Err(Box::new(EvalAltResult::ErrorRuntime("".into(), (x.0).1)))
|
EvalAltResult::ErrorRuntime("".into(), (x.0).1).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt::ReturnWithVal(_) => unreachable!(),
|
Stmt::ReturnWithVal(_) => unreachable!(),
|
||||||
@ -1806,12 +1782,12 @@ impl Engine {
|
|||||||
// Import statement
|
// Import statement
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Stmt::Import(x) => {
|
Stmt::Import(x) => {
|
||||||
let (expr, (name, _pos), _) = x.as_ref();
|
let (expr, alias, _pos) = x.as_ref();
|
||||||
|
|
||||||
// Guard against too many modules
|
// Guard against too many modules
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if state.modules >= self.limits.max_modules {
|
if state.modules >= self.limits.max_modules {
|
||||||
return Err(Box::new(EvalAltResult::ErrorTooManyModules(*_pos)));
|
return EvalAltResult::ErrorTooManyModules(*_pos).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(path) = self
|
if let Some(path) = self
|
||||||
@ -1820,20 +1796,23 @@ impl Engine {
|
|||||||
{
|
{
|
||||||
if let Some(resolver) = &self.module_resolver {
|
if let Some(resolver) = &self.module_resolver {
|
||||||
let mut module = resolver.resolve(self, &path, expr.position())?;
|
let mut module = resolver.resolve(self, &path, expr.position())?;
|
||||||
module.index_all_sub_modules();
|
|
||||||
mods.push((name.clone().into(), module));
|
if let Some((name, _)) = alias {
|
||||||
|
module.index_all_sub_modules();
|
||||||
|
mods.push((name.clone().into(), module));
|
||||||
|
}
|
||||||
|
|
||||||
state.modules += 1;
|
state.modules += 1;
|
||||||
|
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
} else {
|
} else {
|
||||||
Err(Box::new(EvalAltResult::ErrorModuleNotFound(
|
Err(
|
||||||
path.to_string(),
|
EvalAltResult::ErrorModuleNotFound(path.to_string(), expr.position())
|
||||||
expr.position(),
|
.into(),
|
||||||
)))
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(Box::new(EvalAltResult::ErrorImportExpr(expr.position())))
|
EvalAltResult::ErrorImportExpr(expr.position()).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1846,10 +1825,7 @@ impl Engine {
|
|||||||
let alias = rename.as_ref().map(|(n, _)| n).unwrap_or_else(|| id);
|
let alias = rename.as_ref().map(|(n, _)| n).unwrap_or_else(|| id);
|
||||||
scope.set_entry_alias(index, alias.clone());
|
scope.set_entry_alias(index, alias.clone());
|
||||||
} else {
|
} else {
|
||||||
return Err(Box::new(EvalAltResult::ErrorVariableNotFound(
|
return EvalAltResult::ErrorVariableNotFound(id.into(), *id_pos).into();
|
||||||
id.into(),
|
|
||||||
*id_pos,
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
@ -1973,26 +1949,29 @@ impl Engine {
|
|||||||
let (arr, map, s) = calc_size(result.as_ref().unwrap());
|
let (arr, map, s) = calc_size(result.as_ref().unwrap());
|
||||||
|
|
||||||
if s > self.limits.max_string_size {
|
if s > self.limits.max_string_size {
|
||||||
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
EvalAltResult::ErrorDataTooLarge(
|
||||||
"Length of string".to_string(),
|
"Length of string".to_string(),
|
||||||
self.limits.max_string_size,
|
self.limits.max_string_size,
|
||||||
s,
|
s,
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
} else if arr > self.limits.max_array_size {
|
} else if arr > self.limits.max_array_size {
|
||||||
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
EvalAltResult::ErrorDataTooLarge(
|
||||||
"Size of array".to_string(),
|
"Size of array".to_string(),
|
||||||
self.limits.max_array_size,
|
self.limits.max_array_size,
|
||||||
arr,
|
arr,
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
} else if map > self.limits.max_map_size {
|
} else if map > self.limits.max_map_size {
|
||||||
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
EvalAltResult::ErrorDataTooLarge(
|
||||||
"Number of properties in object map".to_string(),
|
"Number of properties in object map".to_string(),
|
||||||
self.limits.max_map_size,
|
self.limits.max_map_size,
|
||||||
map,
|
map,
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
} else {
|
} else {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -2006,16 +1985,14 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
// Guard against too many operations
|
// Guard against too many operations
|
||||||
if self.limits.max_operations > 0 && state.operations > self.limits.max_operations {
|
if self.limits.max_operations > 0 && state.operations > self.limits.max_operations {
|
||||||
return Err(Box::new(EvalAltResult::ErrorTooManyOperations(
|
return EvalAltResult::ErrorTooManyOperations(Position::none()).into();
|
||||||
Position::none(),
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report progress - only in steps
|
// Report progress - only in steps
|
||||||
if let Some(progress) = &self.progress {
|
if let Some(progress) = &self.progress {
|
||||||
if !progress(&state.operations) {
|
if !progress(&state.operations) {
|
||||||
// Terminate script if progress returns false
|
// Terminate script if progress returns false
|
||||||
return Err(Box::new(EvalAltResult::ErrorTerminated(Position::none())));
|
return EvalAltResult::ErrorTerminated(Position::none()).into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
103
src/fn_call.rs
103
src/fn_call.rs
@ -34,6 +34,7 @@ use crate::engine::{FN_IDX_GET, FN_IDX_SET};
|
|||||||
use crate::engine::{Map, Target, FN_GET, FN_SET};
|
use crate::engine::{Map, Target, FN_GET, FN_SET};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::scope::Entry as ScopeEntry;
|
use crate::scope::Entry as ScopeEntry;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
@ -48,6 +49,7 @@ use crate::stdlib::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::stdlib::{collections::HashSet, string::String};
|
use crate::stdlib::{collections::HashSet, string::String};
|
||||||
|
|
||||||
/// Extract the property name from a getter function name.
|
/// Extract the property name from a getter function name.
|
||||||
@ -140,6 +142,7 @@ impl Drop for ArgBackup<'_> {
|
|||||||
|
|
||||||
// Add captured variables into scope
|
// Add captured variables into scope
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
fn add_captured_variables_into_scope<'s>(
|
fn add_captured_variables_into_scope<'s>(
|
||||||
externals: &HashSet<String>,
|
externals: &HashSet<String>,
|
||||||
captured: Scope<'s>,
|
captured: Scope<'s>,
|
||||||
@ -175,10 +178,11 @@ pub fn ensure_no_data_race(
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, a)| a.is_locked())
|
.find(|(_, a)| a.is_locked())
|
||||||
{
|
{
|
||||||
return Err(Box::new(EvalAltResult::ErrorDataRace(
|
return EvalAltResult::ErrorDataRace(
|
||||||
format!("argument #{} of function '{}'", n + 1 + skip, fn_name),
|
format!("argument #{} of function '{}'", n + 1 + skip, fn_name),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,22 +238,22 @@ impl Engine {
|
|||||||
return Ok(match fn_name {
|
return Ok(match fn_name {
|
||||||
KEYWORD_PRINT => (
|
KEYWORD_PRINT => (
|
||||||
(self.print)(result.as_str().map_err(|typ| {
|
(self.print)(result.as_str().map_err(|typ| {
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
self.map_type_name(type_name::<ImmutableString>()).into(),
|
self.map_type_name(type_name::<ImmutableString>()).into(),
|
||||||
typ.into(),
|
typ.into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
})?)
|
})?)
|
||||||
.into(),
|
.into(),
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
KEYWORD_DEBUG => (
|
KEYWORD_DEBUG => (
|
||||||
(self.debug)(result.as_str().map_err(|typ| {
|
(self.debug)(result.as_str().map_err(|typ| {
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
self.map_type_name(type_name::<ImmutableString>()).into(),
|
self.map_type_name(type_name::<ImmutableString>()).into(),
|
||||||
typ.into(),
|
typ.into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
})?)
|
})?)
|
||||||
.into(),
|
.into(),
|
||||||
false,
|
false,
|
||||||
@ -273,56 +277,60 @@ impl Engine {
|
|||||||
|
|
||||||
// Getter function not found?
|
// Getter function not found?
|
||||||
if let Some(prop) = extract_prop_from_getter(fn_name) {
|
if let Some(prop) = extract_prop_from_getter(fn_name) {
|
||||||
return Err(Box::new(EvalAltResult::ErrorDotExpr(
|
return EvalAltResult::ErrorDotExpr(
|
||||||
format!(
|
format!(
|
||||||
"Unknown property '{}' for {}, or it is write-only",
|
"Unknown property '{}' for {}, or it is write-only",
|
||||||
prop,
|
prop,
|
||||||
self.map_type_name(args[0].type_name())
|
self.map_type_name(args[0].type_name())
|
||||||
),
|
),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setter function not found?
|
// Setter function not found?
|
||||||
if let Some(prop) = extract_prop_from_setter(fn_name) {
|
if let Some(prop) = extract_prop_from_setter(fn_name) {
|
||||||
return Err(Box::new(EvalAltResult::ErrorDotExpr(
|
return EvalAltResult::ErrorDotExpr(
|
||||||
format!(
|
format!(
|
||||||
"Unknown property '{}' for {}, or it is read-only",
|
"Unknown property '{}' for {}, or it is read-only",
|
||||||
prop,
|
prop,
|
||||||
self.map_type_name(args[0].type_name())
|
self.map_type_name(args[0].type_name())
|
||||||
),
|
),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
// index getter function not found?
|
// index getter function not found?
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
if fn_name == FN_IDX_GET && args.len() == 2 {
|
if fn_name == FN_IDX_GET && args.len() == 2 {
|
||||||
return Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
return EvalAltResult::ErrorFunctionNotFound(
|
||||||
format!(
|
format!(
|
||||||
"{} [{}]",
|
"{} [{}]",
|
||||||
self.map_type_name(args[0].type_name()),
|
self.map_type_name(args[0].type_name()),
|
||||||
self.map_type_name(args[1].type_name()),
|
self.map_type_name(args[1].type_name()),
|
||||||
),
|
),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
// index setter function not found?
|
// index setter function not found?
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
if fn_name == FN_IDX_SET {
|
if fn_name == FN_IDX_SET {
|
||||||
return Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
return EvalAltResult::ErrorFunctionNotFound(
|
||||||
format!(
|
format!(
|
||||||
"{} [{}]=",
|
"{} [{}]=",
|
||||||
self.map_type_name(args[0].type_name()),
|
self.map_type_name(args[0].type_name()),
|
||||||
self.map_type_name(args[1].type_name()),
|
self.map_type_name(args[1].type_name()),
|
||||||
),
|
),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raise error
|
// Raise error
|
||||||
Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
EvalAltResult::ErrorFunctionNotFound(
|
||||||
format!(
|
format!(
|
||||||
"{} ({})",
|
"{} ({})",
|
||||||
fn_name,
|
fn_name,
|
||||||
@ -336,7 +344,8 @@ impl Engine {
|
|||||||
.join(", ")
|
.join(", ")
|
||||||
),
|
),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call a script-defined function.
|
/// Call a script-defined function.
|
||||||
@ -397,17 +406,15 @@ impl Engine {
|
|||||||
// Convert return statement to return value
|
// Convert return statement to return value
|
||||||
EvalAltResult::Return(x, _) => Ok(x),
|
EvalAltResult::Return(x, _) => Ok(x),
|
||||||
EvalAltResult::ErrorInFunctionCall(name, err, _) => {
|
EvalAltResult::ErrorInFunctionCall(name, err, _) => {
|
||||||
Err(Box::new(EvalAltResult::ErrorInFunctionCall(
|
EvalAltResult::ErrorInFunctionCall(
|
||||||
format!("{} > {}", fn_name, name),
|
format!("{} > {}", fn_name, name),
|
||||||
err,
|
err,
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
_ => Err(Box::new(EvalAltResult::ErrorInFunctionCall(
|
_ => EvalAltResult::ErrorInFunctionCall(fn_name.to_string(), err, Position::none())
|
||||||
fn_name.to_string(),
|
.into(),
|
||||||
err,
|
|
||||||
Position::none(),
|
|
||||||
))),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove all local variables
|
// Remove all local variables
|
||||||
@ -449,11 +456,11 @@ impl Engine {
|
|||||||
hash_script: u64,
|
hash_script: u64,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
is_ref: bool,
|
is_ref: bool,
|
||||||
is_method: bool,
|
_is_method: bool,
|
||||||
pub_only: bool,
|
pub_only: bool,
|
||||||
_capture: Option<Scope>,
|
_capture: Option<Scope>,
|
||||||
def_val: Option<bool>,
|
def_val: Option<bool>,
|
||||||
level: usize,
|
_level: usize,
|
||||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||||
// Check for data race.
|
// Check for data race.
|
||||||
if cfg!(not(feature = "no_closure")) {
|
if cfg!(not(feature = "no_closure")) {
|
||||||
@ -479,20 +486,22 @@ impl Engine {
|
|||||||
KEYWORD_FN_PTR
|
KEYWORD_FN_PTR
|
||||||
if args.len() == 1 && !self.has_override(lib, hash_fn, hash_script, pub_only) =>
|
if args.len() == 1 && !self.has_override(lib, hash_fn, hash_script, pub_only) =>
|
||||||
{
|
{
|
||||||
Err(Box::new(EvalAltResult::ErrorRuntime(
|
EvalAltResult::ErrorRuntime(
|
||||||
"'Fn' should not be called in method style. Try Fn(...);".into(),
|
"'Fn' should not be called in method style. Try Fn(...);".into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
// eval - reaching this point it must be a method-style call
|
// eval - reaching this point it must be a method-style call
|
||||||
KEYWORD_EVAL
|
KEYWORD_EVAL
|
||||||
if args.len() == 1 && !self.has_override(lib, hash_fn, hash_script, pub_only) =>
|
if args.len() == 1 && !self.has_override(lib, hash_fn, hash_script, pub_only) =>
|
||||||
{
|
{
|
||||||
Err(Box::new(EvalAltResult::ErrorRuntime(
|
EvalAltResult::ErrorRuntime(
|
||||||
"'eval' should not be called in method style. Try eval(...);".into(),
|
"'eval' should not be called in method style. Try eval(...);".into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal script function call
|
// Normal script function call
|
||||||
@ -510,7 +519,7 @@ impl Engine {
|
|||||||
add_captured_variables_into_scope(&func.externals, captured, scope);
|
add_captured_variables_into_scope(&func.externals, captured, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = if is_method {
|
let result = if _is_method {
|
||||||
// Method call of script function - map first argument to `this`
|
// Method call of script function - map first argument to `this`
|
||||||
let (first, rest) = args.split_at_mut(1);
|
let (first, rest) = args.split_at_mut(1);
|
||||||
self.call_script_fn(
|
self.call_script_fn(
|
||||||
@ -522,7 +531,7 @@ impl Engine {
|
|||||||
fn_name,
|
fn_name,
|
||||||
func,
|
func,
|
||||||
rest,
|
rest,
|
||||||
level,
|
_level,
|
||||||
)?
|
)?
|
||||||
} else {
|
} else {
|
||||||
// Normal call of script function - map first argument to `this`
|
// Normal call of script function - map first argument to `this`
|
||||||
@ -531,7 +540,7 @@ impl Engine {
|
|||||||
backup.change_first_arg_to_copy(is_ref, args);
|
backup.change_first_arg_to_copy(is_ref, args);
|
||||||
|
|
||||||
let result = self.call_script_fn(
|
let result = self.call_script_fn(
|
||||||
scope, mods, state, lib, &mut None, fn_name, func, args, level,
|
scope, mods, state, lib, &mut None, fn_name, func, args, _level,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Restore the original reference
|
// Restore the original reference
|
||||||
@ -694,12 +703,12 @@ impl Engine {
|
|||||||
&& _fn_name == KEYWORD_IS_SHARED
|
&& _fn_name == KEYWORD_IS_SHARED
|
||||||
&& idx.is_empty()
|
&& idx.is_empty()
|
||||||
{
|
{
|
||||||
// take call
|
// is_shared call
|
||||||
Ok((target.is_shared().into(), false))
|
Ok((target.is_shared().into(), false))
|
||||||
} else {
|
} else {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
let redirected;
|
let redirected;
|
||||||
let mut _hash = hash_script;
|
let mut hash = hash_script;
|
||||||
|
|
||||||
// Check if it is a map method call in OOP style
|
// Check if it is a map method call in OOP style
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -719,7 +728,7 @@ impl Engine {
|
|||||||
.for_each(|(i, v)| idx.insert(i, v));
|
.for_each(|(i, v)| idx.insert(i, v));
|
||||||
}
|
}
|
||||||
// Recalculate the hash based on the new function name and new arguments
|
// Recalculate the hash based on the new function name and new arguments
|
||||||
_hash = if native {
|
hash = if native {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
calc_fn_hash(empty(), _fn_name, idx.len(), empty())
|
calc_fn_hash(empty(), _fn_name, idx.len(), empty())
|
||||||
@ -729,7 +738,7 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if native {
|
if native {
|
||||||
_hash = 0;
|
hash = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attached object pointer in front of the arguments
|
// Attached object pointer in front of the arguments
|
||||||
@ -737,7 +746,7 @@ impl Engine {
|
|||||||
let args = arg_values.as_mut();
|
let args = arg_values.as_mut();
|
||||||
|
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, _fn_name, _hash, args, is_ref, true, pub_only, None, def_val, level,
|
state, lib, _fn_name, hash, args, is_ref, true, pub_only, None, def_val, level,
|
||||||
)
|
)
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
@ -780,11 +789,12 @@ impl Engine {
|
|||||||
return arg_value
|
return arg_value
|
||||||
.take_immutable_string()
|
.take_immutable_string()
|
||||||
.map_err(|typ| {
|
.map_err(|typ| {
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
self.map_type_name(type_name::<ImmutableString>()).into(),
|
self.map_type_name(type_name::<ImmutableString>()).into(),
|
||||||
typ.into(),
|
typ.into(),
|
||||||
expr.position(),
|
expr.position(),
|
||||||
))
|
)
|
||||||
|
.into()
|
||||||
})
|
})
|
||||||
.and_then(|s| FnPtr::try_from(s))
|
.and_then(|s| FnPtr::try_from(s))
|
||||||
.map(Into::<Dynamic>::into)
|
.map(Into::<Dynamic>::into)
|
||||||
@ -798,11 +808,12 @@ impl Engine {
|
|||||||
let fn_ptr = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
let fn_ptr = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||||
|
|
||||||
if !fn_ptr.is::<FnPtr>() {
|
if !fn_ptr.is::<FnPtr>() {
|
||||||
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
return EvalAltResult::ErrorMismatchOutputType(
|
||||||
self.map_type_name(type_name::<FnPtr>()).into(),
|
self.map_type_name(type_name::<FnPtr>()).into(),
|
||||||
self.map_type_name(fn_ptr.type_name()).into(),
|
self.map_type_name(fn_ptr.type_name()).into(),
|
||||||
expr.position(),
|
expr.position(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
let (fn_name, fn_curry) = fn_ptr.cast::<FnPtr>().take_data();
|
let (fn_name, fn_curry) = fn_ptr.cast::<FnPtr>().take_data();
|
||||||
@ -852,11 +863,12 @@ impl Engine {
|
|||||||
// Recalculate hash
|
// Recalculate hash
|
||||||
hash_script = calc_fn_hash(empty(), name, curry.len() + args_expr.len(), empty());
|
hash_script = calc_fn_hash(empty(), name, curry.len() + args_expr.len(), empty());
|
||||||
} else {
|
} else {
|
||||||
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
return EvalAltResult::ErrorMismatchOutputType(
|
||||||
self.map_type_name(type_name::<FnPtr>()).into(),
|
self.map_type_name(type_name::<FnPtr>()).into(),
|
||||||
fn_name.type_name().into(),
|
fn_name.type_name().into(),
|
||||||
expr.position(),
|
expr.position(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1045,7 +1057,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
Some(f) => f.get_native_fn()(self, lib, args.as_mut()),
|
Some(f) => f.get_native_fn()(self, lib, args.as_mut()),
|
||||||
None if def_val.is_some() => Ok(def_val.unwrap().into()),
|
None if def_val.is_some() => Ok(def_val.unwrap().into()),
|
||||||
None => Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
None => EvalAltResult::ErrorFunctionNotFound(
|
||||||
format!(
|
format!(
|
||||||
"{}{} ({})",
|
"{}{} ({})",
|
||||||
modules,
|
modules,
|
||||||
@ -1060,7 +1072,8 @@ impl Engine {
|
|||||||
.join(", ")
|
.join(", ")
|
||||||
),
|
),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))),
|
)
|
||||||
|
.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
//! Module defining interfaces to native-Rust functions.
|
//! Module defining interfaces to native-Rust functions.
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::any::Dynamic;
|
||||||
use crate::calc_fn_hash;
|
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::parser::FnAccess;
|
use crate::parser::{FnAccess, ScriptFnDef};
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::{is_valid_identifier, Position};
|
use crate::token::{is_valid_identifier, Position};
|
||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::{module::FuncReturn, parser::ScriptFnDef, utils::StaticVec};
|
use crate::{calc_fn_hash, module::FuncReturn, utils::StaticVec};
|
||||||
|
|
||||||
use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, iter::empty, string::String, vec::Vec};
|
use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, string::String, vec::Vec};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::stdlib::mem;
|
use crate::stdlib::{iter::empty, mem};
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
use crate::stdlib::rc::Rc;
|
use crate::stdlib::rc::Rc;
|
||||||
@ -176,10 +175,7 @@ impl TryFrom<ImmutableString> for FnPtr {
|
|||||||
if is_valid_identifier(value.chars()) {
|
if is_valid_identifier(value.chars()) {
|
||||||
Ok(Self(value, Default::default()))
|
Ok(Self(value, Default::default()))
|
||||||
} else {
|
} else {
|
||||||
Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
EvalAltResult::ErrorFunctionNotFound(value.into(), Position::none()).into()
|
||||||
value.into(),
|
|
||||||
Position::none(),
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -293,10 +289,11 @@ impl CallableFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this a Rhai-scripted function?
|
/// Is this a Rhai-scripted function?
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
pub fn is_script(&self) -> bool {
|
pub fn is_script(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(_) => true,
|
Self::Script(_) => true,
|
||||||
|
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => false,
|
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,6 +311,8 @@ impl CallableFunction {
|
|||||||
pub fn access(&self) -> FnAccess {
|
pub fn access(&self) -> FnAccess {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => FnAccess::Public,
|
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => FnAccess::Public,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(f) => f.access,
|
Self::Script(f) => f.access,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -348,10 +347,11 @@ impl CallableFunction {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the `CallableFunction` is not `Script`.
|
/// Panics if the `CallableFunction` is not `Script`.
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
pub fn get_fn_def(&self) -> &ScriptFnDef {
|
pub fn get_fn_def(&self) -> &ScriptFnDef {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => unreachable!(),
|
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => unreachable!(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(f) => f,
|
Self::Script(f) => f,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -385,16 +385,22 @@ impl From<IteratorFn> for CallableFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
impl From<ScriptFnDef> for CallableFunction {
|
impl From<ScriptFnDef> for CallableFunction {
|
||||||
fn from(func: ScriptFnDef) -> Self {
|
fn from(_func: ScriptFnDef) -> Self {
|
||||||
Self::Script(func.into())
|
#[cfg(feature = "no_function")]
|
||||||
|
unreachable!();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
Self::Script(_func.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
impl From<Shared<ScriptFnDef>> for CallableFunction {
|
impl From<Shared<ScriptFnDef>> for CallableFunction {
|
||||||
fn from(func: Shared<ScriptFnDef>) -> Self {
|
fn from(_func: Shared<ScriptFnDef>) -> Self {
|
||||||
Self::Script(func)
|
#[cfg(feature = "no_function")]
|
||||||
|
unreachable!();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
Self::Script(_func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,13 @@ use crate::any::{Dynamic, Variant};
|
|||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::fn_native::{CallableFunction as Func, FnCallArgs, IteratorFn, SendSync};
|
use crate::fn_native::{CallableFunction as Func, FnCallArgs, IteratorFn, SendSync};
|
||||||
use crate::parser::{FnAccess, FnAccess::Public};
|
use crate::parser::{FnAccess, FnAccess::Public, ScriptFnDef};
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::{Position, Token};
|
use crate::token::{Position, Token};
|
||||||
use crate::utils::{StaticVec, StraightHasherBuilder};
|
use crate::utils::{StaticVec, StraightHasherBuilder};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::{fn_native::Shared, parser::ScriptFnDef};
|
use crate::fn_native::Shared;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -248,17 +248,13 @@ impl Module {
|
|||||||
hash_var: u64,
|
hash_var: u64,
|
||||||
) -> Result<&mut Dynamic, Box<EvalAltResult>> {
|
) -> Result<&mut Dynamic, Box<EvalAltResult>> {
|
||||||
self.all_variables.get_mut(&hash_var).ok_or_else(|| {
|
self.all_variables.get_mut(&hash_var).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorVariableNotFound(
|
EvalAltResult::ErrorVariableNotFound(String::new(), Position::none()).into()
|
||||||
String::new(),
|
|
||||||
Position::none(),
|
|
||||||
))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a script-defined function into the module.
|
/// Set a script-defined function into the 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.
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
pub(crate) fn set_script_fn(&mut self, fn_def: ScriptFnDef) -> &mut Self {
|
pub(crate) fn set_script_fn(&mut self, fn_def: ScriptFnDef) -> &mut Self {
|
||||||
// None + function name + number of arguments.
|
// None + function name + number of arguments.
|
||||||
let hash_script = 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());
|
||||||
@ -1003,7 +999,6 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get an iterator to the functions in the module.
|
/// Get an iterator to the functions in the module.
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
pub(crate) fn iter_fn(
|
pub(crate) fn iter_fn(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<Item = &(String, FnAccess, StaticVec<TypeId>, Func)> {
|
) -> impl Iterator<Item = &(String, FnAccess, StaticVec<TypeId>, Func)> {
|
||||||
@ -1519,7 +1514,7 @@ mod stat {
|
|||||||
self.0
|
self.0
|
||||||
.get(path)
|
.get(path)
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorModuleNotFound(path.into(), pos)))
|
.ok_or_else(|| EvalAltResult::ErrorModuleNotFound(path.into(), pos).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1599,10 +1594,7 @@ mod collection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(Box::new(EvalAltResult::ErrorModuleNotFound(
|
EvalAltResult::ErrorModuleNotFound(path.into(), pos).into()
|
||||||
path.into(),
|
|
||||||
pos,
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,10 @@ use crate::engine::{
|
|||||||
};
|
};
|
||||||
use crate::fn_native::FnPtr;
|
use crate::fn_native::FnPtr;
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::parser::{map_dynamic_to_expr, Expr, ScriptFnDef, Stmt, AST};
|
use crate::parser::{map_dynamic_to_expr, Expr, ReturnType, ScriptFnDef, Stmt, AST};
|
||||||
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
|
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
|
||||||
use crate::utils::StaticVec;
|
use crate::utils::StaticVec;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
use crate::parser::ReturnType;
|
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
use crate::parser::CustomExpr;
|
use crate::parser::CustomExpr;
|
||||||
|
|
||||||
@ -46,10 +43,12 @@ impl OptimizationLevel {
|
|||||||
self == Self::None
|
self == Self::None
|
||||||
}
|
}
|
||||||
/// Is the `OptimizationLevel` Simple.
|
/// Is the `OptimizationLevel` Simple.
|
||||||
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
pub fn is_simple(self) -> bool {
|
pub fn is_simple(self) -> bool {
|
||||||
self == Self::Simple
|
self == Self::Simple
|
||||||
}
|
}
|
||||||
/// Is the `OptimizationLevel` Full.
|
/// Is the `OptimizationLevel` Full.
|
||||||
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
pub fn is_full(self) -> bool {
|
pub fn is_full(self) -> bool {
|
||||||
self == Self::Full
|
self == Self::Full
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ use num_traits::{
|
|||||||
use num_traits::float::Float;
|
use num_traits::float::Float;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
boxed::Box,
|
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
format,
|
format,
|
||||||
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub},
|
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub},
|
||||||
@ -26,28 +25,31 @@ use crate::stdlib::{
|
|||||||
// Checked add
|
// Checked add
|
||||||
pub fn add<T: Display + CheckedAdd>(x: T, y: T) -> FuncReturn<T> {
|
pub fn add<T: Display + CheckedAdd>(x: T, y: T) -> FuncReturn<T> {
|
||||||
x.checked_add(&y).ok_or_else(|| {
|
x.checked_add(&y).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Addition overflow: {} + {}", x, y),
|
format!("Addition overflow: {} + {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
|
.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked subtract
|
// Checked subtract
|
||||||
pub fn sub<T: Display + CheckedSub>(x: T, y: T) -> FuncReturn<T> {
|
pub fn sub<T: Display + CheckedSub>(x: T, y: T) -> FuncReturn<T> {
|
||||||
x.checked_sub(&y).ok_or_else(|| {
|
x.checked_sub(&y).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Subtraction underflow: {} - {}", x, y),
|
format!("Subtraction underflow: {} - {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
|
.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked multiply
|
// Checked multiply
|
||||||
pub fn mul<T: Display + CheckedMul>(x: T, y: T) -> FuncReturn<T> {
|
pub fn mul<T: Display + CheckedMul>(x: T, y: T) -> FuncReturn<T> {
|
||||||
x.checked_mul(&y).ok_or_else(|| {
|
x.checked_mul(&y).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Multiplication overflow: {} * {}", x, y),
|
format!("Multiplication overflow: {} * {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
|
.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked divide
|
// Checked divide
|
||||||
@ -57,26 +59,26 @@ where
|
|||||||
{
|
{
|
||||||
// Detect division by zero
|
// Detect division by zero
|
||||||
if y == T::zero() {
|
if y == T::zero() {
|
||||||
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
return EvalAltResult::ErrorArithmetic(
|
||||||
format!("Division by zero: {} / {}", x, y),
|
format!("Division by zero: {} / {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
x.checked_div(&y).ok_or_else(|| {
|
x.checked_div(&y).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Division overflow: {} / {}", x, y),
|
format!("Division overflow: {} / {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
|
.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked negative - e.g. -(i32::MIN) will overflow i32::MAX
|
// Checked negative - e.g. -(i32::MIN) will overflow i32::MAX
|
||||||
pub fn neg<T: Display + CheckedNeg>(x: T) -> FuncReturn<T> {
|
pub fn neg<T: Display + CheckedNeg>(x: T) -> FuncReturn<T> {
|
||||||
x.checked_neg().ok_or_else(|| {
|
x.checked_neg().ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(format!("Negation overflow: -{}", x), Position::none())
|
||||||
format!("Negation overflow: -{}", x),
|
.into()
|
||||||
Position::none(),
|
|
||||||
))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked absolute
|
// Checked absolute
|
||||||
@ -87,10 +89,8 @@ pub fn abs<T: Display + CheckedNeg + PartialOrd + Zero>(x: T) -> FuncReturn<T> {
|
|||||||
Ok(x)
|
Ok(x)
|
||||||
} else {
|
} else {
|
||||||
x.checked_neg().ok_or_else(|| {
|
x.checked_neg().ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(format!("Negation overflow: -{}", x), Position::none())
|
||||||
format!("Negation overflow: -{}", x),
|
.into()
|
||||||
Position::none(),
|
|
||||||
))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,34 +140,38 @@ fn binary_xor<T: BitXor>(x: T, y: T) -> FuncReturn<<T as BitXor>::Output> {
|
|||||||
pub fn shl<T: Display + CheckedShl>(x: T, y: INT) -> FuncReturn<T> {
|
pub fn shl<T: Display + CheckedShl>(x: T, y: INT) -> FuncReturn<T> {
|
||||||
// Cannot shift by a negative number of bits
|
// Cannot shift by a negative number of bits
|
||||||
if y < 0 {
|
if y < 0 {
|
||||||
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
return EvalAltResult::ErrorArithmetic(
|
||||||
format!("Left-shift by a negative number: {} << {}", x, y),
|
format!("Left-shift by a negative number: {} << {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckedShl::checked_shl(&x, y as u32).ok_or_else(|| {
|
CheckedShl::checked_shl(&x, y as u32).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Left-shift by too many bits: {} << {}", x, y),
|
format!("Left-shift by too many bits: {} << {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
|
.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Checked right-shift
|
// Checked right-shift
|
||||||
pub fn shr<T: Display + CheckedShr>(x: T, y: INT) -> FuncReturn<T> {
|
pub fn shr<T: Display + CheckedShr>(x: T, y: INT) -> FuncReturn<T> {
|
||||||
// Cannot shift by a negative number of bits
|
// Cannot shift by a negative number of bits
|
||||||
if y < 0 {
|
if y < 0 {
|
||||||
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
return EvalAltResult::ErrorArithmetic(
|
||||||
format!("Right-shift by a negative number: {} >> {}", x, y),
|
format!("Right-shift by a negative number: {} >> {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckedShr::checked_shr(&x, y as u32).ok_or_else(|| {
|
CheckedShr::checked_shr(&x, y as u32).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Right-shift by too many bits: {} % {}", x, y),
|
format!("Right-shift by too many bits: {} % {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
|
.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Unchecked left-shift - may panic if shifting by a negative number of bits
|
// Unchecked left-shift - may panic if shifting by a negative number of bits
|
||||||
@ -181,10 +185,11 @@ pub fn shr_u<T: Shr<T>>(x: T, y: T) -> FuncReturn<<T as Shr<T>>::Output> {
|
|||||||
// Checked modulo
|
// Checked modulo
|
||||||
pub fn modulo<T: Display + CheckedRem>(x: T, y: T) -> FuncReturn<T> {
|
pub fn modulo<T: Display + CheckedRem>(x: T, y: T) -> FuncReturn<T> {
|
||||||
x.checked_rem(&y).ok_or_else(|| {
|
x.checked_rem(&y).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Modulo division by zero or overflow: {} % {}", x, y),
|
format!("Modulo division by zero or overflow: {} % {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
|
.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Unchecked modulo - may panic if dividing by zero
|
// Unchecked modulo - may panic if dividing by zero
|
||||||
@ -195,35 +200,40 @@ fn modulo_u<T: Rem>(x: T, y: T) -> FuncReturn<<T as Rem>::Output> {
|
|||||||
pub fn pow_i_i(x: INT, y: INT) -> FuncReturn<INT> {
|
pub fn pow_i_i(x: INT, y: INT) -> FuncReturn<INT> {
|
||||||
if cfg!(not(feature = "only_i32")) {
|
if cfg!(not(feature = "only_i32")) {
|
||||||
if y > (u32::MAX as INT) {
|
if y > (u32::MAX as INT) {
|
||||||
Err(Box::new(EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Integer raised to too large an index: {} ~ {}", x, y),
|
format!("Integer raised to too large an index: {} ~ {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
} else if y < 0 {
|
} else if y < 0 {
|
||||||
Err(Box::new(EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Integer raised to a negative index: {} ~ {}", x, y),
|
format!("Integer raised to a negative index: {} ~ {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
} else {
|
} else {
|
||||||
x.checked_pow(y as u32).ok_or_else(|| {
|
x.checked_pow(y as u32).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Power overflow: {} ~ {}", x, y),
|
format!("Power overflow: {} ~ {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
|
.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if y < 0 {
|
if y < 0 {
|
||||||
Err(Box::new(EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Integer raised to a negative index: {} ~ {}", x, y),
|
format!("Integer raised to a negative index: {} ~ {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
} else {
|
} else {
|
||||||
x.checked_pow(y as u32).ok_or_else(|| {
|
x.checked_pow(y as u32).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Power overflow: {} ~ {}", x, y),
|
format!("Power overflow: {} ~ {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
|
.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -242,10 +252,11 @@ pub fn pow_f_f(x: FLOAT, y: FLOAT) -> FuncReturn<FLOAT> {
|
|||||||
pub fn pow_f_i(x: FLOAT, y: INT) -> FuncReturn<FLOAT> {
|
pub fn pow_f_i(x: FLOAT, y: INT) -> FuncReturn<FLOAT> {
|
||||||
// Raise to power that is larger than an i32
|
// Raise to power that is larger than an i32
|
||||||
if y > (i32::MAX as INT) {
|
if y > (i32::MAX as INT) {
|
||||||
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
return EvalAltResult::ErrorArithmetic(
|
||||||
format!("Number raised to too large an index: {} ~ {}", x, y),
|
format!("Number raised to too large an index: {} ~ {}", x, y),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(x.powi(y as i32))
|
Ok(x.powi(y as i32))
|
||||||
|
@ -43,12 +43,13 @@ fn pad<T: Variant + Clone>(
|
|||||||
&& len > 0
|
&& len > 0
|
||||||
&& (len as usize) > _engine.limits.max_array_size
|
&& (len as usize) > _engine.limits.max_array_size
|
||||||
{
|
{
|
||||||
return Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
return EvalAltResult::ErrorDataTooLarge(
|
||||||
"Size of array".to_string(),
|
"Size of array".to_string(),
|
||||||
_engine.limits.max_array_size,
|
_engine.limits.max_array_size,
|
||||||
len as usize,
|
len as usize,
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
if len > 0 {
|
if len > 0 {
|
||||||
|
@ -12,7 +12,7 @@ use crate::{result::EvalAltResult, token::Position};
|
|||||||
use num_traits::float::Float;
|
use num_traits::float::Float;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::stdlib::{boxed::Box, format};
|
use crate::stdlib::format;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
@ -109,10 +109,10 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, {
|
|||||||
"to_int",
|
"to_int",
|
||||||
|x: f32| {
|
|x: f32| {
|
||||||
if x > (MAX_INT as f32) {
|
if x > (MAX_INT as f32) {
|
||||||
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
return EvalAltResult::ErrorArithmetic(
|
||||||
format!("Integer overflow: to_int({})", x),
|
format!("Integer overflow: to_int({})", x),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(x.trunc() as INT)
|
Ok(x.trunc() as INT)
|
||||||
@ -122,10 +122,10 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, {
|
|||||||
"to_int",
|
"to_int",
|
||||||
|x: FLOAT| {
|
|x: FLOAT| {
|
||||||
if x > (MAX_INT as FLOAT) {
|
if x > (MAX_INT as FLOAT) {
|
||||||
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
return EvalAltResult::ErrorArithmetic(
|
||||||
format!("Integer overflow: to_int({})", x),
|
format!("Integer overflow: to_int({})", x),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(x.trunc() as INT)
|
Ok(x.trunc() as INT)
|
||||||
|
@ -231,12 +231,12 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
|
|||||||
// Check if string will be over max size limit
|
// Check if string will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _engine.limits.max_string_size > 0 && len > 0 && (len as usize) > _engine.limits.max_string_size {
|
if _engine.limits.max_string_size > 0 && len > 0 && (len as usize) > _engine.limits.max_string_size {
|
||||||
return Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
return EvalAltResult::ErrorDataTooLarge(
|
||||||
"Length of string".to_string(),
|
"Length of string".to_string(),
|
||||||
_engine.limits.max_string_size,
|
_engine.limits.max_string_size,
|
||||||
len as usize,
|
len as usize,
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
if len > 0 {
|
if len > 0 {
|
||||||
@ -254,12 +254,12 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _engine.limits.max_string_size > 0 && s.len() > _engine.limits.max_string_size {
|
if _engine.limits.max_string_size > 0 && s.len() > _engine.limits.max_string_size {
|
||||||
return Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
return EvalAltResult::ErrorDataTooLarge(
|
||||||
"Length of string".to_string(),
|
"Length of string".to_string(),
|
||||||
_engine.limits.max_string_size,
|
_engine.limits.max_string_size,
|
||||||
s.len(),
|
s.len(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
).into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,13 +41,13 @@ def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, {
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if seconds > (MAX_INT as u64) {
|
if seconds > (MAX_INT as u64) {
|
||||||
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
return EvalAltResult::ErrorArithmetic(
|
||||||
format!(
|
format!(
|
||||||
"Integer overflow for timestamp duration: {}",
|
"Integer overflow for timestamp duration: {}",
|
||||||
-(seconds as i64)
|
-(seconds as i64)
|
||||||
),
|
),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(-(seconds as INT));
|
return Ok(-(seconds as INT));
|
||||||
@ -62,10 +62,10 @@ def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, {
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if seconds > (MAX_INT as u64) {
|
if seconds > (MAX_INT as u64) {
|
||||||
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
return EvalAltResult::ErrorArithmetic(
|
||||||
format!("Integer overflow for timestamp duration: {}", seconds),
|
format!("Integer overflow for timestamp duration: {}", seconds),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(seconds as INT);
|
return Ok(seconds as INT);
|
||||||
@ -92,10 +92,10 @@ def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, {
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if seconds > (MAX_INT as u64) {
|
if seconds > (MAX_INT as u64) {
|
||||||
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
return EvalAltResult::ErrorArithmetic(
|
||||||
format!("Integer overflow for timestamp.elapsed: {}", seconds),
|
format!("Integer overflow for timestamp.elapsed: {}", seconds),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(seconds as INT)
|
Ok(seconds as INT)
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
|
|
||||||
use crate::any::{Dynamic, Union};
|
use crate::any::{Dynamic, Union};
|
||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::engine::{
|
use crate::engine::{Engine, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
||||||
Engine, KEYWORD_FN_PTR_CURRY, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT,
|
|
||||||
};
|
|
||||||
use crate::error::{LexError, ParseError, ParseErrorType};
|
use crate::error::{LexError, ParseError, ParseErrorType};
|
||||||
use crate::fn_native::{FnPtr, Shared};
|
use crate::fn_native::{FnPtr, Shared};
|
||||||
use crate::module::{Module, ModuleRef};
|
use crate::module::{Module, ModuleRef};
|
||||||
@ -15,7 +13,7 @@ use crate::token::{is_keyword_function, is_valid_identifier, Position, Token, To
|
|||||||
use crate::utils::{StaticVec, StraightHasherBuilder};
|
use crate::utils::{StaticVec, StraightHasherBuilder};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::engine::FN_ANONYMOUS;
|
use crate::engine::{FN_ANONYMOUS, KEYWORD_FN_PTR_CURRY};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::engine::{make_getter, make_setter};
|
use crate::engine::{make_getter, make_setter};
|
||||||
@ -570,7 +568,7 @@ pub enum Stmt {
|
|||||||
ReturnWithVal(Box<((ReturnType, Position), Option<Expr>, Position)>),
|
ReturnWithVal(Box<((ReturnType, Position), Option<Expr>, Position)>),
|
||||||
/// import expr as module
|
/// import expr as module
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Import(Box<(Expr, (String, Position), Position)>),
|
Import(Box<(Expr, Option<(String, Position)>, Position)>),
|
||||||
/// expr id as name, ...
|
/// expr id as name, ...
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Export(
|
Export(
|
||||||
@ -2687,14 +2685,8 @@ fn parse_import(
|
|||||||
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
|
|
||||||
// import expr as ...
|
// import expr as ...
|
||||||
match input.next().unwrap() {
|
if !match_token(input, Token::As)? {
|
||||||
(Token::As, _) => (),
|
return Ok(Stmt::Import(Box::new((expr, None, token_pos))));
|
||||||
(_, pos) => {
|
|
||||||
return Err(
|
|
||||||
PERR::MissingToken(Token::As.into(), "in this import statement".into())
|
|
||||||
.into_err(pos),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// import expr as name ...
|
// import expr as name ...
|
||||||
@ -2711,7 +2703,7 @@ fn parse_import(
|
|||||||
|
|
||||||
Ok(Stmt::Import(Box::new((
|
Ok(Stmt::Import(Box::new((
|
||||||
expr,
|
expr,
|
||||||
(name, settings.pos),
|
Some((name, settings.pos)),
|
||||||
token_pos,
|
token_pos,
|
||||||
))))
|
))))
|
||||||
}
|
}
|
||||||
@ -3135,6 +3127,7 @@ fn parse_fn(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a curried expression from a list of external variables
|
/// Creates a curried expression from a list of external variables
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
fn make_curry_from_externals(
|
fn make_curry_from_externals(
|
||||||
fn_expr: Expr,
|
fn_expr: Expr,
|
||||||
externals: StaticVec<(String, Position)>,
|
externals: StaticVec<(String, Position)>,
|
||||||
|
@ -361,3 +361,9 @@ impl EvalAltResult {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> From<EvalAltResult> for Result<T, Box<EvalAltResult>> {
|
||||||
|
fn from(err: EvalAltResult) -> Self {
|
||||||
|
Err(err.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -53,11 +53,12 @@ impl<'de> DynamicDeserializer<'de> {
|
|||||||
}
|
}
|
||||||
/// Shortcut for a type conversion error.
|
/// Shortcut for a type conversion error.
|
||||||
fn type_error_str<T>(&self, error: &str) -> Result<T, Box<EvalAltResult>> {
|
fn type_error_str<T>(&self, error: &str) -> Result<T, Box<EvalAltResult>> {
|
||||||
Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
error.into(),
|
error.into(),
|
||||||
self.value.type_name().into(),
|
self.value.type_name().into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
fn deserialize_int<V: Visitor<'de>>(
|
fn deserialize_int<V: Visitor<'de>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -134,10 +135,8 @@ pub fn from_dynamic<'de, T: Deserialize<'de>>(
|
|||||||
|
|
||||||
impl Error for Box<EvalAltResult> {
|
impl Error for Box<EvalAltResult> {
|
||||||
fn custom<T: fmt::Display>(err: T) -> Self {
|
fn custom<T: fmt::Display>(err: T) -> Self {
|
||||||
Box::new(EvalAltResult::ErrorParsing(
|
EvalAltResult::ErrorParsing(ParseErrorType::BadInput(err.to_string()), Position::none())
|
||||||
ParseErrorType::BadInput(err.to_string()),
|
.into()
|
||||||
Position::none(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,9 +85,9 @@ impl DynamicSerializer {
|
|||||||
/// assert!(value.is::<Map>());
|
/// assert!(value.is::<Map>());
|
||||||
///
|
///
|
||||||
/// let map = value.cast::<Map>();
|
/// let map = value.cast::<Map>();
|
||||||
/// let point = map.get("d").unwrap().downcast_ref::<Map>().unwrap();
|
/// let point = map["d"].read_lock::<Map>().unwrap();
|
||||||
/// assert_eq!(*point.get("x").unwrap().downcast_ref::<f64>().unwrap(), 123.456);
|
/// assert_eq!(*point["x"].read_lock::<f64>().unwrap(), 123.456);
|
||||||
/// assert_eq!(*point.get("y").unwrap().downcast_ref::<f64>().unwrap(), 999.0);
|
/// assert_eq!(*point["y"].read_lock::<f64>().unwrap(), 999.0);
|
||||||
/// # }
|
/// # }
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
@ -99,10 +99,7 @@ pub fn to_dynamic<T: Serialize>(value: T) -> Result<Dynamic, Box<EvalAltResult>>
|
|||||||
|
|
||||||
impl Error for Box<EvalAltResult> {
|
impl Error for Box<EvalAltResult> {
|
||||||
fn custom<T: fmt::Display>(err: T) -> Self {
|
fn custom<T: fmt::Display>(err: T) -> Self {
|
||||||
Box::new(EvalAltResult::ErrorRuntime(
|
EvalAltResult::ErrorRuntime(err.to_string(), Position::none()).into()
|
||||||
err.to_string(),
|
|
||||||
Position::none(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,22 +295,24 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
make_variant(_variant, content)
|
make_variant(_variant, content)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
return EvalAltResult::ErrorMismatchOutputType(
|
||||||
"Dynamic".into(),
|
"Dynamic".into(),
|
||||||
"map".into(),
|
"map".into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Box<EvalAltResult>> {
|
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return Ok(DynamicSerializer::new(Array::new().into()));
|
return Ok(DynamicSerializer::new(Array::new().into()));
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
return EvalAltResult::ErrorMismatchOutputType(
|
||||||
"Dynamic".into(),
|
"Dynamic".into(),
|
||||||
"array".into(),
|
"array".into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Box<EvalAltResult>> {
|
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Box<EvalAltResult>> {
|
||||||
@ -346,11 +345,12 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
let err_type = "map";
|
let err_type = "map";
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
let err_type = "array";
|
let err_type = "array";
|
||||||
Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
"Dynamic".into(),
|
"Dynamic".into(),
|
||||||
err_type.into(),
|
err_type.into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,11 +358,12 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
return Ok(DynamicSerializer::new(Map::new().into()));
|
return Ok(DynamicSerializer::new(Map::new().into()));
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
return EvalAltResult::ErrorMismatchOutputType(
|
||||||
"Dynamic".into(),
|
"Dynamic".into(),
|
||||||
"map".into(),
|
"map".into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_struct(
|
fn serialize_struct(
|
||||||
@ -386,11 +387,12 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
map: Map::with_capacity(_len),
|
map: Map::with_capacity(_len),
|
||||||
});
|
});
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
return EvalAltResult::ErrorMismatchOutputType(
|
||||||
"Dynamic".into(),
|
"Dynamic".into(),
|
||||||
"map".into(),
|
"map".into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)));
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,11 +501,11 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
let key = mem::take(&mut self._key)
|
let key = mem::take(&mut self._key)
|
||||||
.take_immutable_string()
|
.take_immutable_string()
|
||||||
.map_err(|typ| {
|
.map_err(|typ| {
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
"string".into(),
|
"string".into(),
|
||||||
typ.into(),
|
typ.into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
})?;
|
})?;
|
||||||
let _value = _value.serialize(&mut *self)?;
|
let _value = _value.serialize(&mut *self)?;
|
||||||
let map = self._value.downcast_mut::<Map>().unwrap();
|
let map = self._value.downcast_mut::<Map>().unwrap();
|
||||||
@ -523,11 +525,11 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
{
|
{
|
||||||
let _key: Dynamic = _key.serialize(&mut *self)?;
|
let _key: Dynamic = _key.serialize(&mut *self)?;
|
||||||
let _key = _key.take_immutable_string().map_err(|typ| {
|
let _key = _key.take_immutable_string().map_err(|typ| {
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
"string".into(),
|
"string".into(),
|
||||||
typ.into(),
|
typ.into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
)
|
||||||
})?;
|
})?;
|
||||||
let _value = _value.serialize(&mut *self)?;
|
let _value = _value.serialize(&mut *self)?;
|
||||||
let map = self._value.downcast_mut::<Map>().unwrap();
|
let map = self._value.downcast_mut::<Map>().unwrap();
|
||||||
|
@ -20,11 +20,12 @@ impl<'a> ImmutableStringDeserializer<'a> {
|
|||||||
}
|
}
|
||||||
/// Shortcut for a type conversion error.
|
/// Shortcut for a type conversion error.
|
||||||
fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> {
|
fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> {
|
||||||
Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
type_name::<T>().into(),
|
type_name::<T>().into(),
|
||||||
"string".into(),
|
"string".into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
//! Configuration settings for `Engine`.
|
//! Configuration settings for `Engine`.
|
||||||
|
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::optimize::OptimizationLevel;
|
|
||||||
use crate::packages::PackageLibrary;
|
use crate::packages::PackageLibrary;
|
||||||
use crate::token::{is_valid_identifier, Token};
|
use crate::token::{is_valid_identifier, Token};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
use crate::module::ModuleResolver;
|
use crate::module::ModuleResolver;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
|
use crate::optimize::OptimizationLevel;
|
||||||
|
|
||||||
use crate::stdlib::{format, string::String};
|
use crate::stdlib::{format, string::String};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
@ -680,6 +680,7 @@ impl Token {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a token into a function name, if possible.
|
/// Convert a token into a function name, if possible.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub(crate) fn into_function_name_for_override(self) -> Result<String, Self> {
|
pub(crate) fn into_function_name_for_override(self) -> Result<String, Self> {
|
||||||
match self {
|
match self {
|
||||||
Self::Reserved(s) if can_override_keyword(&s) => Ok(s),
|
Self::Reserved(s) if can_override_keyword(&s) => Ok(s),
|
||||||
@ -1442,6 +1443,7 @@ pub fn is_keyword_function(name: &str) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Can this keyword be overridden as a function?
|
/// Can this keyword be overridden as a function?
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn can_override_keyword(name: &str) -> bool {
|
pub fn can_override_keyword(name: &str) -> bool {
|
||||||
match name {
|
match name {
|
||||||
|
@ -83,6 +83,7 @@ fn test_closures() -> Result<(), Box<EvalAltResult>> {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
#[cfg(not(feature = "sync"))]
|
||||||
fn test_closures_data_race() -> Result<(), Box<EvalAltResult>> {
|
fn test_closures_data_race() -> Result<(), Box<EvalAltResult>> {
|
||||||
let engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
|
@ -5,16 +5,16 @@ use std::sync::{Arc, Mutex, RwLock};
|
|||||||
/// Simulate a command object.
|
/// Simulate a command object.
|
||||||
struct Command {
|
struct Command {
|
||||||
/// Simulate an external state.
|
/// Simulate an external state.
|
||||||
state: i64,
|
state: INT,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command {
|
impl Command {
|
||||||
/// Do some action.
|
/// Do some action.
|
||||||
pub fn action(&mut self, val: i64) {
|
pub fn action(&mut self, val: INT) {
|
||||||
self.state = val;
|
self.state = val;
|
||||||
}
|
}
|
||||||
/// Get current value.
|
/// Get current value.
|
||||||
pub fn get(&self) -> i64 {
|
pub fn get(&self) -> INT {
|
||||||
self.state
|
self.state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,7 +39,7 @@ fn test_side_effects_command() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
// Register type.
|
// Register type.
|
||||||
engine.register_type_with_name::<API>("CommandType");
|
engine.register_type_with_name::<API>("CommandType");
|
||||||
engine.register_fn("action", |api: &mut API, x: i64| {
|
engine.register_fn("action", |api: &mut API, x: INT| {
|
||||||
let mut command = api.lock().unwrap();
|
let mut command = api.lock().unwrap();
|
||||||
let val = command.get();
|
let val = command.get();
|
||||||
command.action(val + x);
|
command.action(val + x);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#![cfg(not(feature = "unchecked"))]
|
#![cfg(not(feature = "unchecked"))]
|
||||||
use rhai::{Engine, EvalAltResult, ParseError, ParseErrorType};
|
use rhai::{Engine, EvalAltResult, ParseError, ParseErrorType, INT};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
@ -7,7 +7,7 @@ fn test_stack_overflow_fn_calls() -> Result<(), Box<EvalAltResult>> {
|
|||||||
let engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<i64>(
|
engine.eval::<INT>(
|
||||||
r"
|
r"
|
||||||
fn foo(n) { if n <= 1 { 0 } else { n + foo(n-1) } }
|
fn foo(n) { if n <= 1 { 0 } else { n + foo(n-1) } }
|
||||||
foo(8)
|
foo(8)
|
||||||
|
Loading…
Reference in New Issue
Block a user