Make Engine reentrant to prepare for parallel execution.
This commit is contained in:
parent
e204ae1a2c
commit
e795a50ae2
19
README.md
19
README.md
@ -167,7 +167,7 @@ use rhai::{Engine, EvalAltResult};
|
|||||||
|
|
||||||
fn main() -> Result<(), EvalAltResult>
|
fn main() -> Result<(), EvalAltResult>
|
||||||
{
|
{
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
let result = engine.eval::<i64>("40 + 2")?;
|
let result = engine.eval::<i64>("40 + 2")?;
|
||||||
|
|
||||||
@ -446,7 +446,7 @@ fn get_an_any() -> Dynamic {
|
|||||||
|
|
||||||
fn main() -> Result<(), EvalAltResult>
|
fn main() -> Result<(), EvalAltResult>
|
||||||
{
|
{
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
engine.register_fn("add", add);
|
engine.register_fn("add", add);
|
||||||
|
|
||||||
@ -497,7 +497,7 @@ fn show_it<T: Display>(x: &mut T) -> () {
|
|||||||
|
|
||||||
fn main()
|
fn main()
|
||||||
{
|
{
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
engine.register_fn("print", show_it as fn(x: &mut i64)->());
|
engine.register_fn("print", show_it as fn(x: &mut i64)->());
|
||||||
engine.register_fn("print", show_it as fn(x: &mut bool)->());
|
engine.register_fn("print", show_it as fn(x: &mut bool)->());
|
||||||
@ -533,7 +533,7 @@ fn safe_divide(x: i64, y: i64) -> Result<i64, EvalAltResult> {
|
|||||||
|
|
||||||
fn main()
|
fn main()
|
||||||
{
|
{
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
// Fallible functions that return Result values must use register_result_fn()
|
// Fallible functions that return Result values must use register_result_fn()
|
||||||
engine.register_result_fn("divide", safe_divide);
|
engine.register_result_fn("divide", safe_divide);
|
||||||
@ -584,7 +584,7 @@ impl TestStruct {
|
|||||||
|
|
||||||
fn main() -> Result<(), EvalAltResult>
|
fn main() -> Result<(), EvalAltResult>
|
||||||
{
|
{
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
engine.register_type::<TestStruct>();
|
engine.register_type::<TestStruct>();
|
||||||
|
|
||||||
@ -622,7 +622,7 @@ impl TestStruct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
engine.register_type::<TestStruct>();
|
engine.register_type::<TestStruct>();
|
||||||
```
|
```
|
||||||
@ -712,7 +712,7 @@ impl TestStruct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
engine.register_type::<TestStruct>();
|
engine.register_type::<TestStruct>();
|
||||||
|
|
||||||
@ -748,7 +748,7 @@ use rhai::{Engine, Scope, EvalAltResult};
|
|||||||
|
|
||||||
fn main() -> Result<(), EvalAltResult>
|
fn main() -> Result<(), EvalAltResult>
|
||||||
{
|
{
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
// First create the state
|
// First create the state
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
@ -1885,7 +1885,8 @@ print("z = " + z); // <- error: variable 'z' not found
|
|||||||
|
|
||||||
Script segments passed to `eval` execute inside the current [`Scope`], so they can access and modify _everything_,
|
Script segments passed to `eval` execute inside the current [`Scope`], so they can access and modify _everything_,
|
||||||
including all variables that are visible at that position in code! It is almost as if the script segments were
|
including all variables that are visible at that position in code! It is almost as if the script segments were
|
||||||
physically pasted in at the position of the `eval` call.
|
physically pasted in at the position of the `eval` call. But because of this, new functions cannot be defined
|
||||||
|
within an `eval` call, since functions can only be defined at the global level, not inside a function call!
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let script = "x += 32";
|
let script = "x += 32";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use rhai::{Engine, EvalAltResult, INT};
|
use rhai::{Engine, EvalAltResult, INT};
|
||||||
|
|
||||||
fn main() -> Result<(), EvalAltResult> {
|
fn main() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
let result = engine.eval::<INT>("40 + 2")?;
|
let result = engine.eval::<INT>("40 + 2")?;
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use rhai::{Engine, EvalAltResult, INT};
|
use rhai::{Engine, EvalAltResult, INT};
|
||||||
|
|
||||||
fn main() -> Result<(), EvalAltResult> {
|
fn main() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
let result = engine.eval::<INT>("40 + 2")?;
|
let result = engine.eval::<INT>("40 + 2")?;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use rhai::{Engine, EvalAltResult, Scope, INT};
|
use rhai::{Engine, EvalAltResult, Scope, INT};
|
||||||
|
|
||||||
fn main() -> Result<(), EvalAltResult> {
|
fn main() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
engine.eval_with_scope::<()>(&mut scope, "let x = 4 + 5")?;
|
engine.eval_with_scope::<()>(&mut scope, "let x = 4 + 5")?;
|
||||||
|
172
src/api.rs
172
src/api.rs
@ -334,7 +334,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// // Compile a script to an AST and store it for later evaluation
|
/// // Compile a script to an AST and store it for later evaluation
|
||||||
/// let ast = engine.compile("40 + 2")?;
|
/// let ast = engine.compile("40 + 2")?;
|
||||||
@ -413,7 +413,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// // Compile a script file to an AST and store it for later evaluation.
|
/// // Compile a script file to an AST and store it for later evaluation.
|
||||||
/// // Notice that a PathBuf is required which can easily be constructed from a string.
|
/// // Notice that a PathBuf is required which can easily be constructed from a string.
|
||||||
@ -481,7 +481,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// // Compile a script to an AST and store it for later evaluation
|
/// // Compile a script to an AST and store it for later evaluation
|
||||||
/// let ast = engine.compile_expression("40 + 2")?;
|
/// let ast = engine.compile_expression("40 + 2")?;
|
||||||
@ -552,7 +552,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// // Notice that a PathBuf is required which can easily be constructed from a string.
|
/// // Notice that a PathBuf is required which can easily be constructed from a string.
|
||||||
/// let result = engine.eval_file::<i64>("script.rhai".into())?;
|
/// let result = engine.eval_file::<i64>("script.rhai".into())?;
|
||||||
@ -560,7 +560,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
pub fn eval_file<T: Any + Clone>(&mut self, path: PathBuf) -> Result<T, EvalAltResult> {
|
pub fn eval_file<T: Any + Clone>(&self, path: PathBuf) -> Result<T, EvalAltResult> {
|
||||||
Self::read_file(path).and_then(|contents| self.eval::<T>(&contents))
|
Self::read_file(path).and_then(|contents| self.eval::<T>(&contents))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,7 +572,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::{Engine, Scope};
|
/// use rhai::{Engine, Scope};
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// // Create initialized scope
|
/// // Create initialized scope
|
||||||
/// let mut scope = Scope::new();
|
/// let mut scope = Scope::new();
|
||||||
@ -585,7 +585,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
pub fn eval_file_with_scope<T: Any + Clone>(
|
pub fn eval_file_with_scope<T: Any + Clone>(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
) -> Result<T, EvalAltResult> {
|
) -> Result<T, EvalAltResult> {
|
||||||
@ -600,13 +600,13 @@ impl<'e> Engine<'e> {
|
|||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// assert_eq!(engine.eval::<i64>("40 + 2")?, 42);
|
/// assert_eq!(engine.eval::<i64>("40 + 2")?, 42);
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn eval<T: Any + Clone>(&mut self, input: &str) -> Result<T, EvalAltResult> {
|
pub fn eval<T: Any + Clone>(&self, input: &str) -> Result<T, EvalAltResult> {
|
||||||
self.eval_with_scope(&mut Scope::new(), input)
|
self.eval_with_scope(&mut Scope::new(), input)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,7 +618,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::{Engine, Scope};
|
/// use rhai::{Engine, Scope};
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// // Create initialized scope
|
/// // Create initialized scope
|
||||||
/// let mut scope = Scope::new();
|
/// let mut scope = Scope::new();
|
||||||
@ -633,7 +633,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn eval_with_scope<T: Any + Clone>(
|
pub fn eval_with_scope<T: Any + Clone>(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
input: &str,
|
input: &str,
|
||||||
) -> Result<T, EvalAltResult> {
|
) -> Result<T, EvalAltResult> {
|
||||||
@ -649,13 +649,13 @@ impl<'e> Engine<'e> {
|
|||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// assert_eq!(engine.eval_expression::<i64>("40 + 2")?, 42);
|
/// assert_eq!(engine.eval_expression::<i64>("40 + 2")?, 42);
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn eval_expression<T: Any + Clone>(&mut self, input: &str) -> Result<T, EvalAltResult> {
|
pub fn eval_expression<T: Any + Clone>(&self, input: &str) -> Result<T, EvalAltResult> {
|
||||||
self.eval_expression_with_scope(&mut Scope::new(), input)
|
self.eval_expression_with_scope(&mut Scope::new(), input)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,7 +667,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::{Engine, Scope};
|
/// use rhai::{Engine, Scope};
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// // Create initialized scope
|
/// // Create initialized scope
|
||||||
/// let mut scope = Scope::new();
|
/// let mut scope = Scope::new();
|
||||||
@ -678,7 +678,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn eval_expression_with_scope<T: Any + Clone>(
|
pub fn eval_expression_with_scope<T: Any + Clone>(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
input: &str,
|
input: &str,
|
||||||
) -> Result<T, EvalAltResult> {
|
) -> Result<T, EvalAltResult> {
|
||||||
@ -697,7 +697,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// // Compile a script to an AST and store it for later evaluation
|
/// // Compile a script to an AST and store it for later evaluation
|
||||||
/// let ast = engine.compile("40 + 2")?;
|
/// let ast = engine.compile("40 + 2")?;
|
||||||
@ -707,7 +707,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn eval_ast<T: Any + Clone>(&mut self, ast: &AST) -> Result<T, EvalAltResult> {
|
pub fn eval_ast<T: Any + Clone>(&self, ast: &AST) -> Result<T, EvalAltResult> {
|
||||||
self.eval_ast_with_scope(&mut Scope::new(), ast)
|
self.eval_ast_with_scope(&mut Scope::new(), ast)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -719,7 +719,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::{Engine, Scope};
|
/// use rhai::{Engine, Scope};
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// // Compile a script to an AST and store it for later evaluation
|
/// // Compile a script to an AST and store it for later evaluation
|
||||||
/// let ast = engine.compile("x + 2")?;
|
/// let ast = engine.compile("x + 2")?;
|
||||||
@ -741,7 +741,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn eval_ast_with_scope<T: Any + Clone>(
|
pub fn eval_ast_with_scope<T: Any + Clone>(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
) -> Result<T, EvalAltResult> {
|
) -> Result<T, EvalAltResult> {
|
||||||
@ -756,23 +756,16 @@ impl<'e> Engine<'e> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn eval_ast_with_scope_raw(
|
pub(crate) fn eval_ast_with_scope_raw(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
) -> Result<Dynamic, EvalAltResult> {
|
) -> Result<Dynamic, EvalAltResult> {
|
||||||
let statements = {
|
ast.0
|
||||||
let AST(statements, functions) = ast;
|
|
||||||
self.fn_lib = Some(functions.clone());
|
|
||||||
statements
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = statements
|
|
||||||
.iter()
|
.iter()
|
||||||
.try_fold(().into_dynamic(), |_, stmt| self.eval_stmt(scope, stmt, 0));
|
.try_fold(().into_dynamic(), |_, stmt| {
|
||||||
|
self.eval_stmt(scope, Some(ast.1.as_ref()), stmt, 0)
|
||||||
self.fn_lib = None;
|
})
|
||||||
|
.or_else(|err| match err {
|
||||||
result.or_else(|err| match err {
|
|
||||||
EvalAltResult::Return(out, _) => Ok(out),
|
EvalAltResult::Return(out, _) => Ok(out),
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
})
|
})
|
||||||
@ -781,7 +774,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// Evaluate a file, but throw away the result and only return error (if any).
|
/// Evaluate a file, but throw away the result and only return error (if any).
|
||||||
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
pub fn consume_file(&mut self, path: PathBuf) -> Result<(), EvalAltResult> {
|
pub fn consume_file(&self, path: PathBuf) -> Result<(), EvalAltResult> {
|
||||||
Self::read_file(path).and_then(|contents| self.consume(&contents))
|
Self::read_file(path).and_then(|contents| self.consume(&contents))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -789,7 +782,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
pub fn consume_file_with_scope(
|
pub fn consume_file_with_scope(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
) -> Result<(), EvalAltResult> {
|
) -> Result<(), EvalAltResult> {
|
||||||
@ -798,17 +791,13 @@ impl<'e> Engine<'e> {
|
|||||||
|
|
||||||
/// Evaluate a string, but throw away the result and only return error (if any).
|
/// Evaluate a string, but throw away the result and only return error (if any).
|
||||||
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
||||||
pub fn consume(&mut self, input: &str) -> Result<(), EvalAltResult> {
|
pub fn consume(&self, input: &str) -> Result<(), EvalAltResult> {
|
||||||
self.consume_with_scope(&mut Scope::new(), input)
|
self.consume_with_scope(&mut Scope::new(), input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a string with own scope, but throw away the result and only return error (if any).
|
/// Evaluate a string with own scope, but throw away the result and only return error (if any).
|
||||||
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
||||||
pub fn consume_with_scope(
|
pub fn consume_with_scope(&self, scope: &mut Scope, input: &str) -> Result<(), EvalAltResult> {
|
||||||
&mut self,
|
|
||||||
scope: &mut Scope,
|
|
||||||
input: &str,
|
|
||||||
) -> Result<(), EvalAltResult> {
|
|
||||||
let tokens_stream = lex(input);
|
let tokens_stream = lex(input);
|
||||||
|
|
||||||
let ast = parse(&mut tokens_stream.peekable(), self, scope)
|
let ast = parse(&mut tokens_stream.peekable(), self, scope)
|
||||||
@ -819,30 +808,24 @@ impl<'e> Engine<'e> {
|
|||||||
|
|
||||||
/// Evaluate an AST, but throw away the result and only return error (if any).
|
/// Evaluate an AST, but throw away the result and only return error (if any).
|
||||||
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
||||||
pub fn consume_ast(&mut self, ast: &AST) -> Result<(), EvalAltResult> {
|
pub fn consume_ast(&self, ast: &AST) -> Result<(), EvalAltResult> {
|
||||||
self.consume_ast_with_scope(&mut Scope::new(), ast)
|
self.consume_ast_with_scope(&mut Scope::new(), ast)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate an `AST` with own scope, but throw away the result and only return error (if any).
|
/// Evaluate an `AST` with own scope, but throw away the result and only return error (if any).
|
||||||
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
/// Useful for when you don't need the result, but still need to keep track of possible errors.
|
||||||
pub fn consume_ast_with_scope(
|
pub fn consume_ast_with_scope(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
) -> Result<(), EvalAltResult> {
|
) -> Result<(), EvalAltResult> {
|
||||||
let statements = {
|
ast.0
|
||||||
let AST(statements, functions) = ast;
|
|
||||||
self.fn_lib = Some(functions.clone());
|
|
||||||
statements
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = statements
|
|
||||||
.iter()
|
.iter()
|
||||||
.try_fold(().into_dynamic(), |_, stmt| self.eval_stmt(scope, stmt, 0));
|
.try_fold(().into_dynamic(), |_, stmt| {
|
||||||
|
self.eval_stmt(scope, Some(ast.1.as_ref()), stmt, 0)
|
||||||
self.fn_lib = None;
|
})
|
||||||
|
.map(|_| ())
|
||||||
result.map(|_| ()).or_else(|err| match err {
|
.or_else(|err| match err {
|
||||||
EvalAltResult::Return(_, _) => Ok(()),
|
EvalAltResult::Return(_, _) => Ok(()),
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
})
|
})
|
||||||
@ -859,7 +842,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # {
|
/// # {
|
||||||
/// use rhai::{Engine, Scope};
|
/// use rhai::{Engine, Scope};
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// let ast = engine.compile("fn num() { 42 + foo }")?;
|
/// let ast = engine.compile("fn num() { 42 + foo }")?;
|
||||||
///
|
///
|
||||||
@ -876,7 +859,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub fn call_fn0<T: Any + Clone>(
|
pub fn call_fn0<T: Any + Clone>(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
name: &str,
|
name: &str,
|
||||||
@ -895,7 +878,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # {
|
/// # {
|
||||||
/// use rhai::{Engine, Scope};
|
/// use rhai::{Engine, Scope};
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// let ast = engine.compile("fn inc(x) { x + foo }")?;
|
/// let ast = engine.compile("fn inc(x) { x + foo }")?;
|
||||||
///
|
///
|
||||||
@ -912,7 +895,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub fn call_fn1<A: Any + Clone, T: Any + Clone>(
|
pub fn call_fn1<A: Any + Clone, T: Any + Clone>(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
name: &str,
|
name: &str,
|
||||||
@ -932,7 +915,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # {
|
/// # {
|
||||||
/// use rhai::{Engine, Scope};
|
/// use rhai::{Engine, Scope};
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// let ast = engine.compile("fn add(x, y) { len(x) + y + foo }")?;
|
/// let ast = engine.compile("fn add(x, y) { len(x) + y + foo }")?;
|
||||||
///
|
///
|
||||||
@ -949,7 +932,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub fn call_fn<A: FuncArgs, T: Any + Clone>(
|
pub fn call_fn<A: FuncArgs, T: Any + Clone>(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
name: &str,
|
name: &str,
|
||||||
@ -960,29 +943,24 @@ impl<'e> Engine<'e> {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
fn call_fn_internal<T: Any + Clone>(
|
fn call_fn_internal<T: Any + Clone>(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
name: &str,
|
name: &str,
|
||||||
mut arg_values: Vec<Dynamic>,
|
mut arg_values: Vec<Dynamic>,
|
||||||
) -> Result<T, EvalAltResult> {
|
) -> Result<T, EvalAltResult> {
|
||||||
let mut args: Vec<_> = arg_values.iter_mut().map(Dynamic::as_mut).collect();
|
let mut args: Vec<_> = arg_values.iter_mut().map(Dynamic::as_mut).collect();
|
||||||
|
let fn_lib = Some(ast.1.as_ref());
|
||||||
|
let pos = Position::none();
|
||||||
|
|
||||||
self.fn_lib = Some(ast.1.clone());
|
self.call_fn_raw(Some(scope), fn_lib, name, &mut args, None, pos, 0)?
|
||||||
|
|
||||||
let result = self
|
|
||||||
.call_fn_raw(Some(scope), name, &mut args, None, Position::none(), 0)?
|
|
||||||
.try_cast()
|
.try_cast()
|
||||||
.map_err(|a| {
|
.map_err(|a| {
|
||||||
EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
self.map_type_name((*a).type_name()).into(),
|
self.map_type_name((*a).type_name()).into(),
|
||||||
Position::none(),
|
pos,
|
||||||
)
|
)
|
||||||
});
|
})
|
||||||
|
|
||||||
self.fn_lib = None;
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Optimize the `AST` with constants defined in an external Scope.
|
/// Optimize the `AST` with constants defined in an external Scope.
|
||||||
@ -998,12 +976,8 @@ impl<'e> Engine<'e> {
|
|||||||
/// (i.e. with `scope.push_constant(...)`). Then, the `AST is cloned and the copy re-optimized before running.
|
/// (i.e. with `scope.push_constant(...)`). Then, the `AST is cloned and the copy re-optimized before running.
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
pub fn optimize_ast(&self, scope: &Scope, ast: AST) -> AST {
|
pub fn optimize_ast(&self, scope: &Scope, ast: AST) -> AST {
|
||||||
optimize_into_ast(
|
let fn_lib = ast.1.iter().map(|fn_def| fn_def.as_ref().clone()).collect();
|
||||||
self,
|
optimize_into_ast(self, scope, ast.0, fn_lib)
|
||||||
scope,
|
|
||||||
ast.0,
|
|
||||||
ast.1.iter().map(|fn_def| fn_def.as_ref().clone()).collect(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Override default action of `print` (print to stdout using `println!`)
|
/// Override default action of `print` (print to stdout using `println!`)
|
||||||
@ -1012,22 +986,24 @@ impl<'e> Engine<'e> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
|
/// # use std::sync::RwLock;
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let mut result = String::from("");
|
/// let result = RwLock::new(String::from(""));
|
||||||
/// {
|
/// {
|
||||||
/// let mut engine = Engine::new();
|
/// let mut engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// // Override action of 'print' function
|
/// // Override action of 'print' function
|
||||||
/// engine.on_print(|s| result.push_str(s));
|
/// engine.on_print(|s| result.write().unwrap().push_str(s));
|
||||||
|
///
|
||||||
/// engine.consume("print(40 + 2);")?;
|
/// engine.consume("print(40 + 2);")?;
|
||||||
/// }
|
/// }
|
||||||
/// assert_eq!(result, "42");
|
/// assert_eq!(*result.read().unwrap(), "42");
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
pub fn on_print(&mut self, callback: impl FnMut(&str) + Send + Sync + 'e) {
|
pub fn on_print(&mut self, callback: impl Fn(&str) + Send + Sync + 'e) {
|
||||||
self.on_print = Some(Box::new(callback));
|
self.on_print = Some(Box::new(callback));
|
||||||
}
|
}
|
||||||
/// Override default action of `print` (print to stdout using `println!`)
|
/// Override default action of `print` (print to stdout using `println!`)
|
||||||
@ -1036,22 +1012,24 @@ impl<'e> Engine<'e> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
|
/// # use std::sync::RwLock;
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let mut result = String::from("");
|
/// let result = RwLock::new(String::from(""));
|
||||||
/// {
|
/// {
|
||||||
/// let mut engine = Engine::new();
|
/// let mut engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// // Override action of 'print' function
|
/// // Override action of 'print' function
|
||||||
/// engine.on_print(|s| result.push_str(s));
|
/// engine.on_print(|s| result.write().unwrap().push_str(s));
|
||||||
|
///
|
||||||
/// engine.consume("print(40 + 2);")?;
|
/// engine.consume("print(40 + 2);")?;
|
||||||
/// }
|
/// }
|
||||||
/// assert_eq!(result, "42");
|
/// assert_eq!(*result.read().unwrap(), "42");
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
pub fn on_print(&mut self, callback: impl FnMut(&str) + 'e) {
|
pub fn on_print(&mut self, callback: impl Fn(&str) + 'e) {
|
||||||
self.on_print = Some(Box::new(callback));
|
self.on_print = Some(Box::new(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1061,22 +1039,24 @@ impl<'e> Engine<'e> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
|
/// # use std::sync::RwLock;
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let mut result = String::from("");
|
/// let result = RwLock::new(String::from(""));
|
||||||
/// {
|
/// {
|
||||||
/// let mut engine = Engine::new();
|
/// let mut engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// // Override action of 'debug' function
|
/// // Override action of 'print' function
|
||||||
/// engine.on_debug(|s| result.push_str(s));
|
/// engine.on_debug(|s| result.write().unwrap().push_str(s));
|
||||||
|
///
|
||||||
/// engine.consume(r#"debug("hello");"#)?;
|
/// engine.consume(r#"debug("hello");"#)?;
|
||||||
/// }
|
/// }
|
||||||
/// assert_eq!(result, "\"hello\"");
|
/// assert_eq!(*result.read().unwrap(), r#""hello""#);
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
pub fn on_debug(&mut self, callback: impl FnMut(&str) + Send + Sync + 'e) {
|
pub fn on_debug(&mut self, callback: impl Fn(&str) + Send + Sync + 'e) {
|
||||||
self.on_debug = Some(Box::new(callback));
|
self.on_debug = Some(Box::new(callback));
|
||||||
}
|
}
|
||||||
/// Override default action of `debug` (print to stdout using `println!`)
|
/// Override default action of `debug` (print to stdout using `println!`)
|
||||||
@ -1085,22 +1065,24 @@ impl<'e> Engine<'e> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
|
/// # use std::sync::RwLock;
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let mut result = String::from("");
|
/// let result = RwLock::new(String::from(""));
|
||||||
/// {
|
/// {
|
||||||
/// let mut engine = Engine::new();
|
/// let mut engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// // Override action of 'debug' function
|
/// // Override action of 'print' function
|
||||||
/// engine.on_debug(|s| result.push_str(s));
|
/// engine.on_debug(|s| result.write().unwrap().push_str(s));
|
||||||
|
///
|
||||||
/// engine.consume(r#"debug("hello");"#)?;
|
/// engine.consume(r#"debug("hello");"#)?;
|
||||||
/// }
|
/// }
|
||||||
/// assert_eq!(result, "\"hello\"");
|
/// assert_eq!(*result.read().unwrap(), r#""hello""#);
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
pub fn on_debug(&mut self, callback: impl FnMut(&str) + 'e) {
|
pub fn on_debug(&mut self, callback: impl Fn(&str) + 'e) {
|
||||||
self.on_debug = Some(Box::new(callback));
|
self.on_debug = Some(Box::new(callback));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
358
src/engine.rs
358
src/engine.rs
@ -1,7 +1,8 @@
|
|||||||
//! Main module defining the script evaluation `Engine`.
|
//! Main module defining the script evaluation `Engine`.
|
||||||
|
|
||||||
use crate::any::{Any, AnyExt, Dynamic, Variant};
|
use crate::any::{Any, AnyExt, Dynamic, Variant};
|
||||||
use crate::parser::{Expr, FnDef, Position, ReturnType, Stmt, AST, INT};
|
use crate::error::ParseErrorType;
|
||||||
|
use crate::parser::{Expr, FnDef, Position, ReturnType, Stmt, INT};
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{EntryRef as ScopeSource, EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryRef as ScopeSource, EntryType as ScopeEntryType, Scope};
|
||||||
|
|
||||||
@ -232,7 +233,7 @@ impl DerefMut for FunctionsLib {
|
|||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// let result = engine.eval::<i64>("40 + 2")?;
|
/// let result = engine.eval::<i64>("40 + 2")?;
|
||||||
///
|
///
|
||||||
@ -246,13 +247,6 @@ pub struct Engine<'e> {
|
|||||||
/// A hashmap containing all compiled functions known to the engine.
|
/// A hashmap containing all compiled functions known to the engine.
|
||||||
pub(crate) functions: Option<HashMap<FnSpec<'e>, Box<FnAny>>>,
|
pub(crate) functions: Option<HashMap<FnSpec<'e>, Box<FnAny>>>,
|
||||||
|
|
||||||
/// A hashmap containing all script-defined functions.
|
|
||||||
#[cfg(feature = "sync")]
|
|
||||||
pub(crate) fn_lib: Option<Arc<FunctionsLib>>,
|
|
||||||
/// A hashmap containing all script-defined functions.
|
|
||||||
#[cfg(not(feature = "sync"))]
|
|
||||||
pub(crate) fn_lib: Option<Rc<FunctionsLib>>,
|
|
||||||
|
|
||||||
/// A hashmap containing all iterators known to the engine.
|
/// A hashmap containing all iterators known to the engine.
|
||||||
pub(crate) type_iterators: Option<HashMap<TypeId, Box<IteratorFn>>>,
|
pub(crate) type_iterators: Option<HashMap<TypeId, Box<IteratorFn>>>,
|
||||||
/// A hashmap mapping type names to pretty-print names.
|
/// A hashmap mapping type names to pretty-print names.
|
||||||
@ -260,17 +254,17 @@ pub struct Engine<'e> {
|
|||||||
|
|
||||||
/// Closure for implementing the `print` command.
|
/// Closure for implementing the `print` command.
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
pub(crate) on_print: Option<Box<dyn FnMut(&str) + Send + Sync + 'e>>,
|
pub(crate) on_print: Option<Box<dyn Fn(&str) + Send + Sync + 'e>>,
|
||||||
/// Closure for implementing the `print` command.
|
/// Closure for implementing the `print` command.
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
pub(crate) on_print: Option<Box<dyn FnMut(&str) + 'e>>,
|
pub(crate) on_print: Option<Box<dyn Fn(&str) + 'e>>,
|
||||||
|
|
||||||
/// Closure for implementing the `debug` command.
|
/// Closure for implementing the `debug` command.
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
pub(crate) on_debug: Option<Box<dyn FnMut(&str) + Send + Sync + 'e>>,
|
pub(crate) on_debug: Option<Box<dyn Fn(&str) + Send + Sync + 'e>>,
|
||||||
/// Closure for implementing the `debug` command.
|
/// Closure for implementing the `debug` command.
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
pub(crate) on_debug: Option<Box<dyn FnMut(&str) + 'e>>,
|
pub(crate) on_debug: Option<Box<dyn Fn(&str) + 'e>>,
|
||||||
|
|
||||||
/// Optimize the AST after compilation.
|
/// Optimize the AST after compilation.
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
@ -299,7 +293,6 @@ impl Default for Engine<'_> {
|
|||||||
// Create the new scripting Engine
|
// Create the new scripting Engine
|
||||||
let mut engine = Engine {
|
let mut engine = Engine {
|
||||||
functions: None,
|
functions: None,
|
||||||
fn_lib: None,
|
|
||||||
type_iterators: None,
|
type_iterators: None,
|
||||||
type_names: Some(type_names),
|
type_names: Some(type_names),
|
||||||
on_print: Some(Box::new(default_print)), // default print/debug implementations
|
on_print: Some(Box::new(default_print)), // default print/debug implementations
|
||||||
@ -368,7 +361,6 @@ impl Engine<'_> {
|
|||||||
pub fn new_raw() -> Self {
|
pub fn new_raw() -> Self {
|
||||||
let mut engine = Engine {
|
let mut engine = Engine {
|
||||||
functions: None,
|
functions: None,
|
||||||
fn_lib: None,
|
|
||||||
type_iterators: None,
|
type_iterators: None,
|
||||||
type_names: None,
|
type_names: None,
|
||||||
on_print: None,
|
on_print: None,
|
||||||
@ -435,8 +427,9 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
/// Universal method for calling functions either registered with the `Engine` or written in Rhai
|
/// Universal method for calling functions either registered with the `Engine` or written in Rhai
|
||||||
pub(crate) fn call_fn_raw(
|
pub(crate) fn call_fn_raw(
|
||||||
&mut self,
|
&self,
|
||||||
scope: Option<&mut Scope>,
|
scope: Option<&mut Scope>,
|
||||||
|
fn_lib: Option<&FunctionsLib>,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
def_val: Option<&Dynamic>,
|
def_val: Option<&Dynamic>,
|
||||||
@ -444,8 +437,8 @@ impl Engine<'_> {
|
|||||||
level: usize,
|
level: usize,
|
||||||
) -> Result<Dynamic, EvalAltResult> {
|
) -> Result<Dynamic, EvalAltResult> {
|
||||||
// First search in script-defined functions (can override built-in)
|
// First search in script-defined functions (can override built-in)
|
||||||
if let Some(fn_lib_arc) = &self.fn_lib {
|
if let Some(lib) = fn_lib {
|
||||||
if let Some(fn_def) = fn_lib_arc.clone().get_function(fn_name, args.len()) {
|
if let Some(fn_def) = lib.get_function(fn_name, args.len()) {
|
||||||
match scope {
|
match scope {
|
||||||
// Extern scope passed in which is not empty
|
// Extern scope passed in which is not empty
|
||||||
Some(scope) if scope.len() > 0 => {
|
Some(scope) if scope.len() > 0 => {
|
||||||
@ -462,13 +455,13 @@ impl Engine<'_> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Evaluate the function at one higher level of call depth
|
// Evaluate the function at one higher level of call depth
|
||||||
let result = self.eval_stmt(scope, &fn_def.body, level + 1).or_else(
|
let result = self
|
||||||
|err| match err {
|
.eval_stmt(scope, fn_lib, &fn_def.body, level + 1)
|
||||||
|
.or_else(|err| match err {
|
||||||
// Convert return statement to return value
|
// Convert return statement to return value
|
||||||
EvalAltResult::Return(x, _) => Ok(x),
|
EvalAltResult::Return(x, _) => Ok(x),
|
||||||
err => Err(err.set_position(pos)),
|
err => Err(err.set_position(pos)),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
scope.rewind(scope_len);
|
scope.rewind(scope_len);
|
||||||
|
|
||||||
@ -488,13 +481,13 @@ impl Engine<'_> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Evaluate the function at one higher level of call depth
|
// Evaluate the function at one higher level of call depth
|
||||||
return self.eval_stmt(&mut scope, &fn_def.body, level + 1).or_else(
|
return self
|
||||||
|err| match err {
|
.eval_stmt(&mut scope, fn_lib, &fn_def.body, level + 1)
|
||||||
|
.or_else(|err| match err {
|
||||||
// Convert return statement to return value
|
// Convert return statement to return value
|
||||||
EvalAltResult::Return(x, _) => Ok(x),
|
EvalAltResult::Return(x, _) => Ok(x),
|
||||||
err => Err(err.set_position(pos)),
|
err => Err(err.set_position(pos)),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -521,11 +514,11 @@ impl Engine<'_> {
|
|||||||
// See if the function match print/debug (which requires special processing)
|
// See if the function match print/debug (which requires special processing)
|
||||||
return Ok(match fn_name {
|
return Ok(match fn_name {
|
||||||
KEYWORD_PRINT if self.on_print.is_some() => {
|
KEYWORD_PRINT if self.on_print.is_some() => {
|
||||||
self.on_print.as_deref_mut().unwrap()(cast_to_string(result.as_ref(), pos)?)
|
self.on_print.as_ref().unwrap()(cast_to_string(result.as_ref(), pos)?)
|
||||||
.into_dynamic()
|
.into_dynamic()
|
||||||
}
|
}
|
||||||
KEYWORD_DEBUG if self.on_debug.is_some() => {
|
KEYWORD_DEBUG if self.on_debug.is_some() => {
|
||||||
self.on_debug.as_deref_mut().unwrap()(cast_to_string(result.as_ref(), pos)?)
|
self.on_debug.as_ref().unwrap()(cast_to_string(result.as_ref(), pos)?)
|
||||||
.into_dynamic()
|
.into_dynamic()
|
||||||
}
|
}
|
||||||
KEYWORD_PRINT | KEYWORD_DEBUG => ().into_dynamic(),
|
KEYWORD_PRINT | KEYWORD_DEBUG => ().into_dynamic(),
|
||||||
@ -590,8 +583,9 @@ impl Engine<'_> {
|
|||||||
/// Chain-evaluate a dot setter.
|
/// Chain-evaluate a dot setter.
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
fn get_dot_val_helper(
|
fn get_dot_val_helper(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
fn_lib: Option<&FunctionsLib>,
|
||||||
target: Target,
|
target: Target,
|
||||||
dot_rhs: &Expr,
|
dot_rhs: &Expr,
|
||||||
level: usize,
|
level: usize,
|
||||||
@ -601,7 +595,7 @@ impl Engine<'_> {
|
|||||||
Expr::FunctionCall(fn_name, arg_expr_list, def_val, pos) => {
|
Expr::FunctionCall(fn_name, arg_expr_list, def_val, pos) => {
|
||||||
let mut values = arg_expr_list
|
let mut values = arg_expr_list
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg_expr| self.eval_expr(scope, arg_expr, level))
|
.map(|arg_expr| self.eval_expr(scope, fn_lib, arg_expr, level))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
let this_ptr = target.get_mut(scope);
|
let this_ptr = target.get_mut(scope);
|
||||||
@ -612,13 +606,13 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
let def_val = def_val.as_ref();
|
let def_val = def_val.as_ref();
|
||||||
|
|
||||||
self.call_fn_raw(None, fn_name, &mut args, def_val, *pos, 0)
|
self.call_fn_raw(None, fn_lib, fn_name, &mut args, def_val, *pos, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// xxx.id
|
// xxx.id
|
||||||
Expr::Property(id, pos) => {
|
Expr::Property(id, pos) => {
|
||||||
let mut args = [target.get_mut(scope)];
|
let mut args = [target.get_mut(scope)];
|
||||||
self.call_fn_raw(None, &make_getter(id), &mut args, None, *pos, 0)
|
self.call_fn_raw(None, fn_lib, &make_getter(id), &mut args, None, *pos, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// xxx.idx_lhs[idx_expr]
|
// xxx.idx_lhs[idx_expr]
|
||||||
@ -628,11 +622,11 @@ impl Engine<'_> {
|
|||||||
// xxx.id[idx_expr]
|
// xxx.id[idx_expr]
|
||||||
Expr::Property(id, pos) => {
|
Expr::Property(id, pos) => {
|
||||||
let mut args = [target.get_mut(scope)];
|
let mut args = [target.get_mut(scope)];
|
||||||
self.call_fn_raw(None, &make_getter(id), &mut args, None, *pos, 0)?
|
self.call_fn_raw(None, fn_lib, &make_getter(id), &mut args, None, *pos, 0)?
|
||||||
}
|
}
|
||||||
// xxx.???[???][idx_expr]
|
// xxx.???[???][idx_expr]
|
||||||
Expr::Index(_, _, _) => {
|
Expr::Index(_, _, _) => {
|
||||||
self.get_dot_val_helper(scope, target, idx_lhs, level)?
|
self.get_dot_val_helper(scope, fn_lib, target, idx_lhs, level)?
|
||||||
}
|
}
|
||||||
// Syntax error
|
// Syntax error
|
||||||
_ => {
|
_ => {
|
||||||
@ -643,7 +637,7 @@ impl Engine<'_> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.get_indexed_value(scope, &value, idx_expr, *op_pos, level)
|
self.get_indexed_value(scope, fn_lib, &value, idx_expr, *op_pos, level)
|
||||||
.map(|(val, _, _)| val)
|
.map(|(val, _, _)| val)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,9 +646,10 @@ impl Engine<'_> {
|
|||||||
// xxx.id.rhs
|
// xxx.id.rhs
|
||||||
Expr::Property(id, pos) => {
|
Expr::Property(id, pos) => {
|
||||||
let mut args = [target.get_mut(scope)];
|
let mut args = [target.get_mut(scope)];
|
||||||
self.call_fn_raw(None, &make_getter(id), &mut args, None, *pos, 0)
|
self.call_fn_raw(None, fn_lib, &make_getter(id), &mut args, None, *pos, 0)
|
||||||
.and_then(|mut val| {
|
.and_then(|mut val| {
|
||||||
self.get_dot_val_helper(scope, Target::from(val.as_mut()), rhs, level)
|
let target = Target::from(val.as_mut());
|
||||||
|
self.get_dot_val_helper(scope, fn_lib, target, rhs, level)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// xxx.idx_lhs[idx_expr].rhs
|
// xxx.idx_lhs[idx_expr].rhs
|
||||||
@ -663,12 +658,13 @@ impl Engine<'_> {
|
|||||||
let val = match idx_lhs.as_ref() {
|
let val = match idx_lhs.as_ref() {
|
||||||
// xxx.id[idx_expr].rhs
|
// xxx.id[idx_expr].rhs
|
||||||
Expr::Property(id, pos) => {
|
Expr::Property(id, pos) => {
|
||||||
|
let fn_name = make_getter(id);
|
||||||
let mut args = [target.get_mut(scope)];
|
let mut args = [target.get_mut(scope)];
|
||||||
self.call_fn_raw(None, &make_getter(id), &mut args, None, *pos, 0)?
|
self.call_fn_raw(None, fn_lib, &fn_name, &mut args, None, *pos, 0)?
|
||||||
}
|
}
|
||||||
// xxx.???[???][idx_expr].rhs
|
// xxx.???[???][idx_expr].rhs
|
||||||
Expr::Index(_, _, _) => {
|
Expr::Index(_, _, _) => {
|
||||||
self.get_dot_val_helper(scope, target, idx_lhs, level)?
|
self.get_dot_val_helper(scope, fn_lib, target, idx_lhs, level)?
|
||||||
}
|
}
|
||||||
// Syntax error
|
// Syntax error
|
||||||
_ => {
|
_ => {
|
||||||
@ -679,9 +675,10 @@ impl Engine<'_> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.get_indexed_value(scope, &val, idx_expr, *op_pos, level)
|
self.get_indexed_value(scope, fn_lib, &val, idx_expr, *op_pos, level)
|
||||||
.and_then(|(mut val, _, _)| {
|
.and_then(|(mut val, _, _)| {
|
||||||
self.get_dot_val_helper(scope, Target::from(val.as_mut()), rhs, level)
|
let target = Target::from(val.as_mut());
|
||||||
|
self.get_dot_val_helper(scope, fn_lib, target, rhs, level)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Syntax error
|
// Syntax error
|
||||||
@ -702,8 +699,9 @@ impl Engine<'_> {
|
|||||||
/// Evaluate a dot chain getter
|
/// Evaluate a dot chain getter
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
fn get_dot_val(
|
fn get_dot_val(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
fn_lib: Option<&FunctionsLib>,
|
||||||
dot_lhs: &Expr,
|
dot_lhs: &Expr,
|
||||||
dot_rhs: &Expr,
|
dot_rhs: &Expr,
|
||||||
level: usize,
|
level: usize,
|
||||||
@ -718,16 +716,16 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// This is a variable property access (potential function call).
|
// This is a variable property access (potential function call).
|
||||||
// Use a direct index into `scope` to directly mutate the variable value.
|
// Use a direct index into `scope` to directly mutate the variable value.
|
||||||
self.get_dot_val_helper(scope, Target::from_src(entry), dot_rhs, level)
|
self.get_dot_val_helper(scope, fn_lib, Target::from_src(entry), dot_rhs, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
// idx_lhs[idx_expr].???
|
// idx_lhs[idx_expr].???
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(idx_lhs, idx_expr, op_pos) => {
|
Expr::Index(idx_lhs, idx_expr, op_pos) => {
|
||||||
let (idx_src_type, src, idx, mut val) =
|
let (idx_src_type, src, idx, mut val) =
|
||||||
self.eval_index_expr(scope, idx_lhs, idx_expr, *op_pos, level)?;
|
self.eval_index_expr(scope, fn_lib, idx_lhs, idx_expr, *op_pos, level)?;
|
||||||
let value =
|
let target = Target::from(val.as_mut());
|
||||||
self.get_dot_val_helper(scope, Target::from(val.as_mut()), dot_rhs, level);
|
let value = self.get_dot_val_helper(scope, fn_lib, target, dot_rhs, level);
|
||||||
|
|
||||||
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
|
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
|
||||||
if let Some(src) = src {
|
if let Some(src) = src {
|
||||||
@ -755,8 +753,8 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// {expr}.???
|
// {expr}.???
|
||||||
expr => {
|
expr => {
|
||||||
let mut val = self.eval_expr(scope, expr, level)?;
|
let mut val = self.eval_expr(scope, fn_lib, expr, level)?;
|
||||||
self.get_dot_val_helper(scope, Target::from(val.as_mut()), dot_rhs, level)
|
self.get_dot_val_helper(scope, fn_lib, Target::from(val.as_mut()), dot_rhs, level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -775,8 +773,9 @@ impl Engine<'_> {
|
|||||||
/// Get the value at the indexed position of a base type
|
/// Get the value at the indexed position of a base type
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
fn get_indexed_value(
|
fn get_indexed_value(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
fn_lib: Option<&FunctionsLib>,
|
||||||
val: &Dynamic,
|
val: &Dynamic,
|
||||||
idx_expr: &Expr,
|
idx_expr: &Expr,
|
||||||
op_pos: Position,
|
op_pos: Position,
|
||||||
@ -787,7 +786,7 @@ impl Engine<'_> {
|
|||||||
// val_array[idx]
|
// val_array[idx]
|
||||||
if let Some(arr) = val.downcast_ref::<Array>() {
|
if let Some(arr) = val.downcast_ref::<Array>() {
|
||||||
let idx = self
|
let idx = self
|
||||||
.eval_expr(scope, idx_expr, level)?
|
.eval_expr(scope, fn_lib, idx_expr, level)?
|
||||||
.try_cast::<INT>()
|
.try_cast::<INT>()
|
||||||
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_expr.position()))?;
|
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_expr.position()))?;
|
||||||
|
|
||||||
@ -806,7 +805,7 @@ impl Engine<'_> {
|
|||||||
// val_map[idx]
|
// val_map[idx]
|
||||||
if let Some(map) = val.downcast_ref::<Map>() {
|
if let Some(map) = val.downcast_ref::<Map>() {
|
||||||
let idx = self
|
let idx = self
|
||||||
.eval_expr(scope, idx_expr, level)?
|
.eval_expr(scope, fn_lib, idx_expr, level)?
|
||||||
.try_cast::<String>()
|
.try_cast::<String>()
|
||||||
.map_err(|_| EvalAltResult::ErrorStringIndexExpr(idx_expr.position()))?;
|
.map_err(|_| EvalAltResult::ErrorStringIndexExpr(idx_expr.position()))?;
|
||||||
|
|
||||||
@ -821,7 +820,7 @@ impl Engine<'_> {
|
|||||||
// val_string[idx]
|
// val_string[idx]
|
||||||
if let Some(s) = val.downcast_ref::<String>() {
|
if let Some(s) = val.downcast_ref::<String>() {
|
||||||
let idx = self
|
let idx = self
|
||||||
.eval_expr(scope, idx_expr, level)?
|
.eval_expr(scope, fn_lib, idx_expr, level)?
|
||||||
.try_cast::<INT>()
|
.try_cast::<INT>()
|
||||||
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_expr.position()))?;
|
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_expr.position()))?;
|
||||||
|
|
||||||
@ -857,8 +856,9 @@ impl Engine<'_> {
|
|||||||
/// Evaluate an index expression
|
/// Evaluate an index expression
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
fn eval_index_expr<'a>(
|
fn eval_index_expr<'a>(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
fn_lib: Option<&FunctionsLib>,
|
||||||
lhs: &'a Expr,
|
lhs: &'a Expr,
|
||||||
idx_expr: &Expr,
|
idx_expr: &Expr,
|
||||||
op_pos: Position,
|
op_pos: Position,
|
||||||
@ -885,7 +885,7 @@ impl Engine<'_> {
|
|||||||
) = Self::search_scope(scope, &id, lhs.position())?;
|
) = Self::search_scope(scope, &id, lhs.position())?;
|
||||||
|
|
||||||
let (val, idx_src_type, idx) =
|
let (val, idx_src_type, idx) =
|
||||||
self.get_indexed_value(scope, &val, idx_expr, op_pos, level)?;
|
self.get_indexed_value(scope, fn_lib, &val, idx_expr, op_pos, level)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
idx_src_type,
|
idx_src_type,
|
||||||
@ -901,9 +901,9 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// (expr)[idx_expr]
|
// (expr)[idx_expr]
|
||||||
expr => {
|
expr => {
|
||||||
let val = self.eval_expr(scope, expr, level)?;
|
let val = self.eval_expr(scope, fn_lib, expr, level)?;
|
||||||
|
|
||||||
self.get_indexed_value(scope, &val, idx_expr, op_pos, level)
|
self.get_indexed_value(scope, fn_lib, &val, idx_expr, op_pos, level)
|
||||||
.map(|(val, _, idx)| (IndexSourceType::Expression, None, idx, val))
|
.map(|(val, _, idx)| (IndexSourceType::Expression, None, idx, val))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1002,8 +1002,9 @@ impl Engine<'_> {
|
|||||||
/// Chain-evaluate a dot setter
|
/// Chain-evaluate a dot setter
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
fn set_dot_val_helper(
|
fn set_dot_val_helper(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
fn_lib: Option<&FunctionsLib>,
|
||||||
this_ptr: &mut Variant,
|
this_ptr: &mut Variant,
|
||||||
dot_rhs: &Expr,
|
dot_rhs: &Expr,
|
||||||
new_val: (&mut Dynamic, Position),
|
new_val: (&mut Dynamic, Position),
|
||||||
@ -1013,7 +1014,7 @@ impl Engine<'_> {
|
|||||||
// xxx.id
|
// xxx.id
|
||||||
Expr::Property(id, pos) => {
|
Expr::Property(id, pos) => {
|
||||||
let mut args = [this_ptr, new_val.0.as_mut()];
|
let mut args = [this_ptr, new_val.0.as_mut()];
|
||||||
self.call_fn_raw(None, &make_setter(id), &mut args, None, *pos, 0)
|
self.call_fn_raw(None, fn_lib, &make_setter(id), &mut args, None, *pos, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// xxx.lhs[idx_expr]
|
// xxx.lhs[idx_expr]
|
||||||
@ -1021,18 +1022,21 @@ impl Engine<'_> {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(lhs, idx_expr, op_pos) => match lhs.as_ref() {
|
Expr::Index(lhs, idx_expr, op_pos) => match lhs.as_ref() {
|
||||||
// xxx.id[idx_expr]
|
// xxx.id[idx_expr]
|
||||||
Expr::Property(id, pos) => self
|
Expr::Property(id, pos) => {
|
||||||
.call_fn_raw(None, &make_getter(id), &mut [this_ptr], None, *pos, 0)
|
let fn_name = make_getter(id);
|
||||||
|
self.call_fn_raw(None, fn_lib, &fn_name, &mut [this_ptr], None, *pos, 0)
|
||||||
.and_then(|val| {
|
.and_then(|val| {
|
||||||
let (_, _, idx) =
|
let (_, _, idx) = self
|
||||||
self.get_indexed_value(scope, &val, idx_expr, *op_pos, level)?;
|
.get_indexed_value(scope, fn_lib, &val, idx_expr, *op_pos, level)?;
|
||||||
|
|
||||||
Self::update_indexed_value(val, idx, new_val.0.clone(), new_val.1)
|
Self::update_indexed_value(val, idx, new_val.0.clone(), new_val.1)
|
||||||
})
|
})
|
||||||
.and_then(|mut val| {
|
.and_then(|mut val| {
|
||||||
|
let fn_name = make_setter(id);
|
||||||
let mut args = [this_ptr, val.as_mut()];
|
let mut args = [this_ptr, val.as_mut()];
|
||||||
self.call_fn_raw(None, &make_setter(id), &mut args, None, *pos, 0)
|
self.call_fn_raw(None, fn_lib, &fn_name, &mut args, None, *pos, 0)
|
||||||
}),
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// All others - syntax error for setters chain
|
// All others - syntax error for setters chain
|
||||||
_ => Err(EvalAltResult::ErrorDotExpr(
|
_ => Err(EvalAltResult::ErrorDotExpr(
|
||||||
@ -1045,14 +1049,17 @@ impl Engine<'_> {
|
|||||||
Expr::Dot(lhs, rhs, _) => match lhs.as_ref() {
|
Expr::Dot(lhs, rhs, _) => match lhs.as_ref() {
|
||||||
// xxx.id.rhs
|
// xxx.id.rhs
|
||||||
Expr::Property(id, pos) => {
|
Expr::Property(id, pos) => {
|
||||||
self.call_fn_raw(None, &make_getter(id), &mut [this_ptr], None, *pos, 0)
|
let fn_name = make_getter(id);
|
||||||
|
self.call_fn_raw(None, fn_lib, &fn_name, &mut [this_ptr], None, *pos, 0)
|
||||||
.and_then(|mut val| {
|
.and_then(|mut val| {
|
||||||
self.set_dot_val_helper(scope, val.as_mut(), rhs, new_val, level)
|
let value = val.as_mut();
|
||||||
|
self.set_dot_val_helper(scope, fn_lib, value, rhs, new_val, level)
|
||||||
.map(|_| val) // Discard Ok return value
|
.map(|_| val) // Discard Ok return value
|
||||||
})
|
})
|
||||||
.and_then(|mut val| {
|
.and_then(|mut val| {
|
||||||
|
let fn_name = make_setter(id);
|
||||||
let mut args = [this_ptr, val.as_mut()];
|
let mut args = [this_ptr, val.as_mut()];
|
||||||
self.call_fn_raw(None, &make_setter(id), &mut args, None, *pos, 0)
|
self.call_fn_raw(None, fn_lib, &fn_name, &mut args, None, *pos, 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1062,21 +1069,26 @@ impl Engine<'_> {
|
|||||||
Expr::Index(lhs, idx_expr, op_pos) => match lhs.as_ref() {
|
Expr::Index(lhs, idx_expr, op_pos) => match lhs.as_ref() {
|
||||||
// xxx.id[idx_expr].rhs
|
// xxx.id[idx_expr].rhs
|
||||||
Expr::Property(id, pos) => {
|
Expr::Property(id, pos) => {
|
||||||
self.call_fn_raw(None, &make_getter(id), &mut [this_ptr], None, *pos, 0)
|
let fn_name = make_getter(id);
|
||||||
|
self.call_fn_raw(None, fn_lib, &fn_name, &mut [this_ptr], None, *pos, 0)
|
||||||
.and_then(|v| {
|
.and_then(|v| {
|
||||||
let (mut value, _, idx) =
|
let (mut value, _, idx) = self.get_indexed_value(
|
||||||
self.get_indexed_value(scope, &v, idx_expr, *op_pos, level)?;
|
scope, fn_lib, &v, idx_expr, *op_pos, level,
|
||||||
|
)?;
|
||||||
|
|
||||||
let val_pos = new_val.1;
|
let val_pos = new_val.1;
|
||||||
let this_ptr = value.as_mut();
|
let this_ptr = value.as_mut();
|
||||||
self.set_dot_val_helper(scope, this_ptr, rhs, new_val, level)?;
|
self.set_dot_val_helper(
|
||||||
|
scope, fn_lib, this_ptr, rhs, new_val, level,
|
||||||
|
)?;
|
||||||
|
|
||||||
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
|
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
|
||||||
Self::update_indexed_value(v, idx, value, val_pos)
|
Self::update_indexed_value(v, idx, value, val_pos)
|
||||||
})
|
})
|
||||||
.and_then(|mut v| {
|
.and_then(|mut v| {
|
||||||
|
let fn_name = make_setter(id);
|
||||||
let mut args = [this_ptr, v.as_mut()];
|
let mut args = [this_ptr, v.as_mut()];
|
||||||
self.call_fn_raw(None, &make_setter(id), &mut args, None, *pos, 0)
|
self.call_fn_raw(None, fn_lib, &fn_name, &mut args, None, *pos, 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1105,8 +1117,9 @@ impl Engine<'_> {
|
|||||||
// Evaluate a dot chain setter
|
// Evaluate a dot chain setter
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
fn set_dot_val(
|
fn set_dot_val(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
fn_lib: Option<&FunctionsLib>,
|
||||||
dot_lhs: &Expr,
|
dot_lhs: &Expr,
|
||||||
dot_rhs: &Expr,
|
dot_rhs: &Expr,
|
||||||
new_val: (&mut Dynamic, Position),
|
new_val: (&mut Dynamic, Position),
|
||||||
@ -1127,8 +1140,8 @@ impl Engine<'_> {
|
|||||||
// Avoid referencing scope which is used below as mut
|
// Avoid referencing scope which is used below as mut
|
||||||
let entry = ScopeSource { name: id, ..entry };
|
let entry = ScopeSource { name: id, ..entry };
|
||||||
let this_ptr = target.as_mut();
|
let this_ptr = target.as_mut();
|
||||||
let value =
|
let value = self
|
||||||
self.set_dot_val_helper(scope, this_ptr, dot_rhs, new_val, level);
|
.set_dot_val_helper(scope, fn_lib, this_ptr, dot_rhs, new_val, level);
|
||||||
|
|
||||||
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
|
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
|
||||||
*scope.get_mut(entry) = target;
|
*scope.get_mut(entry) = target;
|
||||||
@ -1143,10 +1156,11 @@ impl Engine<'_> {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(lhs, idx_expr, op_pos) => {
|
Expr::Index(lhs, idx_expr, op_pos) => {
|
||||||
let (idx_src_type, src, idx, mut target) =
|
let (idx_src_type, src, idx, mut target) =
|
||||||
self.eval_index_expr(scope, lhs, idx_expr, *op_pos, level)?;
|
self.eval_index_expr(scope, fn_lib, lhs, idx_expr, *op_pos, level)?;
|
||||||
let val_pos = new_val.1;
|
let val_pos = new_val.1;
|
||||||
let this_ptr = target.as_mut();
|
let this_ptr = target.as_mut();
|
||||||
let value = self.set_dot_val_helper(scope, this_ptr, dot_rhs, new_val, level);
|
let value =
|
||||||
|
self.set_dot_val_helper(scope, fn_lib, this_ptr, dot_rhs, new_val, level);
|
||||||
|
|
||||||
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
|
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
|
||||||
if let Some(src) = src {
|
if let Some(src) = src {
|
||||||
@ -1182,14 +1196,15 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// Evaluate an 'in' expression
|
// Evaluate an 'in' expression
|
||||||
fn eval_in_expr(
|
fn eval_in_expr(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
fn_lib: Option<&FunctionsLib>,
|
||||||
lhs: &Expr,
|
lhs: &Expr,
|
||||||
rhs: &Expr,
|
rhs: &Expr,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> Result<Dynamic, EvalAltResult> {
|
) -> Result<Dynamic, EvalAltResult> {
|
||||||
let mut lhs_value = self.eval_expr(scope, lhs, level)?;
|
let mut lhs_value = self.eval_expr(scope, fn_lib, lhs, level)?;
|
||||||
let rhs_value = self.eval_expr(scope, rhs, level)?;
|
let rhs_value = self.eval_expr(scope, fn_lib, rhs, level)?;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
@ -1200,15 +1215,10 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// Call the '==' operator to compare each value
|
// Call the '==' operator to compare each value
|
||||||
for value in rhs_value.iter_mut() {
|
for value in rhs_value.iter_mut() {
|
||||||
|
let args = &mut [lhs_value.as_mut(), value.as_mut()];
|
||||||
|
let def_value = Some(&def_value);
|
||||||
if self
|
if self
|
||||||
.call_fn_raw(
|
.call_fn_raw(None, fn_lib, "==", args, def_value, rhs.position(), level)?
|
||||||
None,
|
|
||||||
"==",
|
|
||||||
&mut [lhs_value.as_mut(), value.as_mut()],
|
|
||||||
Some(&def_value),
|
|
||||||
rhs.position(),
|
|
||||||
level,
|
|
||||||
)?
|
|
||||||
.try_cast::<bool>()
|
.try_cast::<bool>()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
@ -1261,8 +1271,9 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
/// Evaluate an expression
|
/// Evaluate an expression
|
||||||
fn eval_expr(
|
fn eval_expr(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
fn_lib: Option<&FunctionsLib>,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> Result<Dynamic, EvalAltResult> {
|
) -> Result<Dynamic, EvalAltResult> {
|
||||||
@ -1279,15 +1290,15 @@ impl Engine<'_> {
|
|||||||
// lhs[idx_expr]
|
// lhs[idx_expr]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(lhs, idx_expr, op_pos) => self
|
Expr::Index(lhs, idx_expr, op_pos) => self
|
||||||
.eval_index_expr(scope, lhs, idx_expr, *op_pos, level)
|
.eval_index_expr(scope, fn_lib, lhs, idx_expr, *op_pos, level)
|
||||||
.map(|(_, _, _, x)| x),
|
.map(|(_, _, _, x)| x),
|
||||||
|
|
||||||
// Statement block
|
// Statement block
|
||||||
Expr::Stmt(stmt, _) => self.eval_stmt(scope, stmt, level),
|
Expr::Stmt(stmt, _) => self.eval_stmt(scope, fn_lib, stmt, level),
|
||||||
|
|
||||||
// lhs = rhs
|
// lhs = rhs
|
||||||
Expr::Assignment(lhs, rhs, op_pos) => {
|
Expr::Assignment(lhs, rhs, op_pos) => {
|
||||||
let mut rhs_val = self.eval_expr(scope, rhs, level)?;
|
let mut rhs_val = self.eval_expr(scope, fn_lib, rhs, level)?;
|
||||||
|
|
||||||
match lhs.as_ref() {
|
match lhs.as_ref() {
|
||||||
// name = rhs
|
// name = rhs
|
||||||
@ -1324,7 +1335,7 @@ impl Engine<'_> {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(idx_lhs, idx_expr, op_pos) => {
|
Expr::Index(idx_lhs, idx_expr, op_pos) => {
|
||||||
let (idx_src_type, src, idx, _) =
|
let (idx_src_type, src, idx, _) =
|
||||||
self.eval_index_expr(scope, idx_lhs, idx_expr, *op_pos, level)?;
|
self.eval_index_expr(scope, fn_lib, idx_lhs, idx_expr, *op_pos, level)?;
|
||||||
|
|
||||||
if let Some(src) = src {
|
if let Some(src) = src {
|
||||||
match src.typ {
|
match src.typ {
|
||||||
@ -1351,14 +1362,10 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// dot_lhs.dot_rhs = rhs
|
// dot_lhs.dot_rhs = rhs
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(dot_lhs, dot_rhs, _) => self.set_dot_val(
|
Expr::Dot(dot_lhs, dot_rhs, _) => {
|
||||||
scope,
|
let new_val = (&mut rhs_val, rhs.position());
|
||||||
dot_lhs,
|
self.set_dot_val(scope, fn_lib, dot_lhs, dot_rhs, new_val, *op_pos, level)
|
||||||
dot_rhs,
|
}
|
||||||
(&mut rhs_val, rhs.position()),
|
|
||||||
*op_pos,
|
|
||||||
level,
|
|
||||||
),
|
|
||||||
|
|
||||||
// Error assignment to constant
|
// Error assignment to constant
|
||||||
expr if expr.is_constant() => Err(EvalAltResult::ErrorAssignmentToConstant(
|
expr if expr.is_constant() => Err(EvalAltResult::ErrorAssignmentToConstant(
|
||||||
@ -1372,14 +1379,15 @@ impl Engine<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(lhs, rhs, _) => self.get_dot_val(scope, lhs, rhs, level),
|
Expr::Dot(lhs, rhs, _) => self.get_dot_val(scope, fn_lib, lhs, rhs, level),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Array(contents, _) => {
|
Expr::Array(contents, _) => {
|
||||||
let mut arr = Array::new();
|
let mut arr = Array::new();
|
||||||
|
|
||||||
contents.into_iter().try_for_each(|item| {
|
contents.into_iter().try_for_each(|item| {
|
||||||
self.eval_expr(scope, item, level).map(|val| arr.push(val))
|
self.eval_expr(scope, fn_lib, item, level)
|
||||||
|
.map(|val| arr.push(val))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok((arr).into_dynamic())
|
Ok((arr).into_dynamic())
|
||||||
@ -1390,7 +1398,7 @@ impl Engine<'_> {
|
|||||||
let mut map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
contents.into_iter().try_for_each(|item| {
|
contents.into_iter().try_for_each(|item| {
|
||||||
self.eval_expr(scope, &item.1, level).map(|val| {
|
self.eval_expr(scope, fn_lib, &item.1, level).map(|val| {
|
||||||
map.insert(item.0.clone(), val);
|
map.insert(item.0.clone(), val);
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
@ -1400,14 +1408,17 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
Expr::FunctionCall(fn_name, args_expr_list, def_val, pos) => {
|
Expr::FunctionCall(fn_name, args_expr_list, def_val, pos) => {
|
||||||
// Has a system function an override?
|
// Has a system function an override?
|
||||||
fn has_override(engine: &Engine, name: &str) -> bool {
|
fn has_override(
|
||||||
(engine.functions.is_some() && {
|
engine: &Engine,
|
||||||
engine.functions.as_ref().unwrap().contains_key(&FnSpec {
|
fn_lib: Option<&FunctionsLib>,
|
||||||
|
name: &str,
|
||||||
|
) -> bool {
|
||||||
|
engine.functions.as_ref().map_or(false, |lib| {
|
||||||
|
lib.contains_key(&FnSpec {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
args: vec![TypeId::of::<String>()],
|
args: vec![TypeId::of::<String>()],
|
||||||
})
|
})
|
||||||
}) || (engine.fn_lib.is_some()
|
}) || fn_lib.map_or(false, |lib| lib.has_function(name, 1))
|
||||||
&& engine.fn_lib.as_ref().unwrap().has_function(name, 1))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match fn_name.as_ref() {
|
match fn_name.as_ref() {
|
||||||
@ -1429,14 +1440,15 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// Redirect call to `print`
|
// Redirect call to `print`
|
||||||
let mut args = [result.as_mut()];
|
let mut args = [result.as_mut()];
|
||||||
self.call_fn_raw(None, KEYWORD_PRINT, &mut args, None, pos, level)
|
self.call_fn_raw(None, fn_lib, KEYWORD_PRINT, &mut args, None, pos, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
// type_of
|
// type_of
|
||||||
KEYWORD_TYPE_OF
|
KEYWORD_TYPE_OF
|
||||||
if args_expr_list.len() == 1 && !has_override(self, KEYWORD_TYPE_OF) =>
|
if args_expr_list.len() == 1
|
||||||
|
&& !has_override(self, fn_lib, KEYWORD_TYPE_OF) =>
|
||||||
{
|
{
|
||||||
let r = self.eval_expr(scope, &args_expr_list[0], level)?;
|
let r = self.eval_expr(scope, fn_lib, &args_expr_list[0], level)?;
|
||||||
Ok(self
|
Ok(self
|
||||||
.map_type_name((*r).type_name())
|
.map_type_name((*r).type_name())
|
||||||
.to_string()
|
.to_string()
|
||||||
@ -1445,10 +1457,11 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// eval
|
// eval
|
||||||
KEYWORD_EVAL
|
KEYWORD_EVAL
|
||||||
if args_expr_list.len() == 1 && !has_override(self, KEYWORD_EVAL) =>
|
if args_expr_list.len() == 1
|
||||||
|
&& !has_override(self, fn_lib, KEYWORD_EVAL) =>
|
||||||
{
|
{
|
||||||
let pos = args_expr_list[0].position();
|
let pos = args_expr_list[0].position();
|
||||||
let r = self.eval_expr(scope, &args_expr_list[0], level)?;
|
let r = self.eval_expr(scope, fn_lib, &args_expr_list[0], level)?;
|
||||||
|
|
||||||
// Get the script text by evaluating the expression
|
// Get the script text by evaluating the expression
|
||||||
let script =
|
let script =
|
||||||
@ -1462,81 +1475,59 @@ impl Engine<'_> {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Compile the script text
|
// Compile the script text
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
let mut ast = self.compile(script).map_err(EvalAltResult::ErrorParsing)?;
|
||||||
let ast = {
|
|
||||||
let orig_optimization_level = self.optimization_level;
|
|
||||||
|
|
||||||
self.set_optimization_level(OptimizationLevel::None);
|
// If new functions are defined within the eval string, it is an error
|
||||||
let ast = self.compile(script);
|
if ast.1.len() > 0 {
|
||||||
self.set_optimization_level(orig_optimization_level);
|
return Err(EvalAltResult::ErrorParsing(
|
||||||
|
ParseErrorType::WrongFnDefinition.into_err(pos),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
ast.map_err(EvalAltResult::ErrorParsing)?
|
if let Some(lib) = fn_lib {
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "no_optimize")]
|
|
||||||
let ast = self.compile(script).map_err(EvalAltResult::ErrorParsing)?;
|
|
||||||
|
|
||||||
// If new functions are defined, merge it into the current functions library
|
|
||||||
let merged = AST(
|
|
||||||
ast.0,
|
|
||||||
if let Some(fn_lib) = &self.fn_lib {
|
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
{
|
{
|
||||||
Arc::new(fn_lib.as_ref().merge(&ast.1))
|
ast.1 = Arc::new(lib.clone());
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
{
|
{
|
||||||
Rc::new(fn_lib.as_ref().merge(&ast.1))
|
ast.1 = Rc::new(lib.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ast.1
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Evaluate the AST
|
// Evaluate the AST
|
||||||
let result = self
|
self.eval_ast_with_scope_raw(scope, &ast)
|
||||||
.eval_ast_with_scope_raw(scope, &merged)
|
.map_err(|err| err.set_position(pos))
|
||||||
.map_err(|err| err.set_position(pos));
|
|
||||||
|
|
||||||
// Update the new functions library if there are new functions
|
|
||||||
self.fn_lib = if !merged.1.is_empty() {
|
|
||||||
Some(merged.1)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(result?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal function call
|
// Normal function call
|
||||||
_ => {
|
_ => {
|
||||||
let mut values = args_expr_list
|
let mut arg_values = args_expr_list
|
||||||
.iter()
|
.iter()
|
||||||
.map(|expr| self.eval_expr(scope, expr, level))
|
.map(|expr| self.eval_expr(scope, fn_lib, expr, level))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
let mut arg_values: Vec<_> =
|
let mut args: Vec<_> = arg_values.iter_mut().map(Dynamic::as_mut).collect();
|
||||||
values.iter_mut().map(Dynamic::as_mut).collect();
|
|
||||||
|
|
||||||
let def_val = def_val.as_ref();
|
let def_val = def_val.as_ref();
|
||||||
|
self.call_fn_raw(None, fn_lib, fn_name, &mut args, def_val, *pos, level)
|
||||||
self.call_fn_raw(None, fn_name, &mut arg_values, def_val, *pos, level)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::In(lhs, rhs, _) => self.eval_in_expr(scope, lhs.as_ref(), rhs.as_ref(), level),
|
Expr::In(lhs, rhs, _) => {
|
||||||
|
self.eval_in_expr(scope, fn_lib, lhs.as_ref(), rhs.as_ref(), level)
|
||||||
|
}
|
||||||
|
|
||||||
Expr::And(lhs, rhs, _) => Ok(Box::new(
|
Expr::And(lhs, rhs, _) => Ok(Box::new(
|
||||||
self
|
self
|
||||||
.eval_expr(scope, lhs.as_ref(), level)?
|
.eval_expr(scope, fn_lib,lhs.as_ref(), level)?
|
||||||
.try_cast::<bool>()
|
.try_cast::<bool>()
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
EvalAltResult::ErrorBooleanArgMismatch("AND".into(), lhs.position())
|
EvalAltResult::ErrorBooleanArgMismatch("AND".into(), lhs.position())
|
||||||
})?
|
})?
|
||||||
&& // Short-circuit using &&
|
&& // Short-circuit using &&
|
||||||
self
|
self
|
||||||
.eval_expr(scope, rhs.as_ref(), level)?
|
.eval_expr(scope, fn_lib,rhs.as_ref(), level)?
|
||||||
.try_cast::<bool>()
|
.try_cast::<bool>()
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
EvalAltResult::ErrorBooleanArgMismatch("AND".into(), rhs.position())
|
EvalAltResult::ErrorBooleanArgMismatch("AND".into(), rhs.position())
|
||||||
@ -1545,14 +1536,14 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
Expr::Or(lhs, rhs, _) => Ok(Box::new(
|
Expr::Or(lhs, rhs, _) => Ok(Box::new(
|
||||||
self
|
self
|
||||||
.eval_expr(scope, lhs.as_ref(), level)?
|
.eval_expr(scope,fn_lib, lhs.as_ref(), level)?
|
||||||
.try_cast::<bool>()
|
.try_cast::<bool>()
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
EvalAltResult::ErrorBooleanArgMismatch("OR".into(), lhs.position())
|
EvalAltResult::ErrorBooleanArgMismatch("OR".into(), lhs.position())
|
||||||
})?
|
})?
|
||||||
|| // Short-circuit using ||
|
|| // Short-circuit using ||
|
||||||
self
|
self
|
||||||
.eval_expr(scope, rhs.as_ref(), level)?
|
.eval_expr(scope,fn_lib, rhs.as_ref(), level)?
|
||||||
.try_cast::<bool>()
|
.try_cast::<bool>()
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
EvalAltResult::ErrorBooleanArgMismatch("OR".into(), rhs.position())
|
EvalAltResult::ErrorBooleanArgMismatch("OR".into(), rhs.position())
|
||||||
@ -1567,8 +1558,9 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
/// Evaluate a statement
|
/// Evaluate a statement
|
||||||
pub(crate) fn eval_stmt(
|
pub(crate) fn eval_stmt(
|
||||||
&mut self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
fn_lib: Option<&FunctionsLib>,
|
||||||
stmt: &Stmt,
|
stmt: &Stmt,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> Result<Dynamic, EvalAltResult> {
|
) -> Result<Dynamic, EvalAltResult> {
|
||||||
@ -1578,7 +1570,7 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// Expression as statement
|
// Expression as statement
|
||||||
Stmt::Expr(expr) => {
|
Stmt::Expr(expr) => {
|
||||||
let result = self.eval_expr(scope, expr, level)?;
|
let result = self.eval_expr(scope, fn_lib, expr, level)?;
|
||||||
|
|
||||||
Ok(if !matches!(expr.as_ref(), Expr::Assignment(_, _, _)) {
|
Ok(if !matches!(expr.as_ref(), Expr::Assignment(_, _, _)) {
|
||||||
result
|
result
|
||||||
@ -1593,7 +1585,7 @@ impl Engine<'_> {
|
|||||||
let prev_len = scope.len();
|
let prev_len = scope.len();
|
||||||
|
|
||||||
let result = block.iter().try_fold(().into_dynamic(), |_, stmt| {
|
let result = block.iter().try_fold(().into_dynamic(), |_, stmt| {
|
||||||
self.eval_stmt(scope, stmt, level)
|
self.eval_stmt(scope, fn_lib, stmt, level)
|
||||||
});
|
});
|
||||||
|
|
||||||
scope.rewind(prev_len);
|
scope.rewind(prev_len);
|
||||||
@ -1603,14 +1595,14 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// If-else statement
|
// If-else statement
|
||||||
Stmt::IfThenElse(guard, if_body, else_body) => self
|
Stmt::IfThenElse(guard, if_body, else_body) => self
|
||||||
.eval_expr(scope, guard, level)?
|
.eval_expr(scope, fn_lib, guard, level)?
|
||||||
.try_cast::<bool>()
|
.try_cast::<bool>()
|
||||||
.map_err(|_| EvalAltResult::ErrorLogicGuard(guard.position()))
|
.map_err(|_| EvalAltResult::ErrorLogicGuard(guard.position()))
|
||||||
.and_then(|guard_val| {
|
.and_then(|guard_val| {
|
||||||
if guard_val {
|
if guard_val {
|
||||||
self.eval_stmt(scope, if_body, level)
|
self.eval_stmt(scope, fn_lib, if_body, level)
|
||||||
} else if let Some(stmt) = else_body {
|
} else if let Some(stmt) = else_body {
|
||||||
self.eval_stmt(scope, stmt.as_ref(), level)
|
self.eval_stmt(scope, fn_lib, stmt.as_ref(), level)
|
||||||
} else {
|
} else {
|
||||||
Ok(().into_dynamic())
|
Ok(().into_dynamic())
|
||||||
}
|
}
|
||||||
@ -1618,12 +1610,19 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// While loop
|
// While loop
|
||||||
Stmt::While(guard, body) => loop {
|
Stmt::While(guard, body) => loop {
|
||||||
match self.eval_expr(scope, guard, level)?.try_cast::<bool>() {
|
match self
|
||||||
Ok(guard_val) if guard_val => match self.eval_stmt(scope, body, level) {
|
.eval_expr(scope, fn_lib, guard, level)?
|
||||||
|
.try_cast::<bool>()
|
||||||
|
{
|
||||||
|
Ok(guard_val) if guard_val => {
|
||||||
|
match self.eval_stmt(scope, fn_lib, body, level) {
|
||||||
Ok(_) | Err(EvalAltResult::ErrorLoopBreak(false, _)) => (),
|
Ok(_) | Err(EvalAltResult::ErrorLoopBreak(false, _)) => (),
|
||||||
Err(EvalAltResult::ErrorLoopBreak(true, _)) => return Ok(().into_dynamic()),
|
Err(EvalAltResult::ErrorLoopBreak(true, _)) => {
|
||||||
|
return Ok(().into_dynamic())
|
||||||
|
}
|
||||||
Err(x) => return Err(x),
|
Err(x) => return Err(x),
|
||||||
},
|
}
|
||||||
|
}
|
||||||
Ok(_) => return Ok(().into_dynamic()),
|
Ok(_) => return Ok(().into_dynamic()),
|
||||||
Err(_) => return Err(EvalAltResult::ErrorLogicGuard(guard.position())),
|
Err(_) => return Err(EvalAltResult::ErrorLogicGuard(guard.position())),
|
||||||
}
|
}
|
||||||
@ -1631,7 +1630,7 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// Loop statement
|
// Loop statement
|
||||||
Stmt::Loop(body) => loop {
|
Stmt::Loop(body) => loop {
|
||||||
match self.eval_stmt(scope, body, level) {
|
match self.eval_stmt(scope, fn_lib, body, level) {
|
||||||
Ok(_) | Err(EvalAltResult::ErrorLoopBreak(false, _)) => (),
|
Ok(_) | Err(EvalAltResult::ErrorLoopBreak(false, _)) => (),
|
||||||
Err(EvalAltResult::ErrorLoopBreak(true, _)) => return Ok(().into_dynamic()),
|
Err(EvalAltResult::ErrorLoopBreak(true, _)) => return Ok(().into_dynamic()),
|
||||||
Err(x) => return Err(x),
|
Err(x) => return Err(x),
|
||||||
@ -1640,7 +1639,7 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// For loop
|
// For loop
|
||||||
Stmt::For(name, expr, body) => {
|
Stmt::For(name, expr, body) => {
|
||||||
let arr = self.eval_expr(scope, expr, level)?;
|
let arr = self.eval_expr(scope, fn_lib, expr, level)?;
|
||||||
let tid = Any::type_id(arr.as_ref());
|
let tid = Any::type_id(arr.as_ref());
|
||||||
|
|
||||||
if let Some(type_iterators) = &self.type_iterators {
|
if let Some(type_iterators) = &self.type_iterators {
|
||||||
@ -1658,7 +1657,7 @@ impl Engine<'_> {
|
|||||||
for a in iter_fn(&arr) {
|
for a in iter_fn(&arr) {
|
||||||
*scope.get_mut(entry) = a;
|
*scope.get_mut(entry) = a;
|
||||||
|
|
||||||
match self.eval_stmt(scope, body, level) {
|
match self.eval_stmt(scope, fn_lib, body, level) {
|
||||||
Ok(_) | Err(EvalAltResult::ErrorLoopBreak(false, _)) => (),
|
Ok(_) | Err(EvalAltResult::ErrorLoopBreak(false, _)) => (),
|
||||||
Err(EvalAltResult::ErrorLoopBreak(true, _)) => break,
|
Err(EvalAltResult::ErrorLoopBreak(true, _)) => break,
|
||||||
Err(x) => return Err(x),
|
Err(x) => return Err(x),
|
||||||
@ -1688,7 +1687,7 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// Return value
|
// Return value
|
||||||
Stmt::ReturnWithVal(Some(a), ReturnType::Return, pos) => Err(EvalAltResult::Return(
|
Stmt::ReturnWithVal(Some(a), ReturnType::Return, pos) => Err(EvalAltResult::Return(
|
||||||
self.eval_expr(scope, a, level)?,
|
self.eval_expr(scope, fn_lib, a, level)?,
|
||||||
*pos,
|
*pos,
|
||||||
)),
|
)),
|
||||||
|
|
||||||
@ -1699,7 +1698,7 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// Throw value
|
// Throw value
|
||||||
Stmt::ReturnWithVal(Some(a), ReturnType::Exception, pos) => {
|
Stmt::ReturnWithVal(Some(a), ReturnType::Exception, pos) => {
|
||||||
let val = self.eval_expr(scope, a, level)?;
|
let val = self.eval_expr(scope, fn_lib, a, level)?;
|
||||||
Err(EvalAltResult::ErrorRuntime(
|
Err(EvalAltResult::ErrorRuntime(
|
||||||
val.try_cast::<String>().unwrap_or_else(|_| "".to_string()),
|
val.try_cast::<String>().unwrap_or_else(|_| "".to_string()),
|
||||||
*pos,
|
*pos,
|
||||||
@ -1708,7 +1707,7 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// Let statement
|
// Let statement
|
||||||
Stmt::Let(name, Some(expr), _) => {
|
Stmt::Let(name, Some(expr), _) => {
|
||||||
let val = self.eval_expr(scope, expr, level)?;
|
let val = self.eval_expr(scope, fn_lib, expr, level)?;
|
||||||
// TODO - avoid copying variable name in inner block?
|
// TODO - avoid copying variable name in inner block?
|
||||||
scope.push_dynamic_value(name.clone(), ScopeEntryType::Normal, val, false);
|
scope.push_dynamic_value(name.clone(), ScopeEntryType::Normal, val, false);
|
||||||
Ok(().into_dynamic())
|
Ok(().into_dynamic())
|
||||||
@ -1722,7 +1721,7 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// Const statement
|
// Const statement
|
||||||
Stmt::Const(name, expr, _) if expr.is_constant() => {
|
Stmt::Const(name, expr, _) if expr.is_constant() => {
|
||||||
let val = self.eval_expr(scope, expr, level)?;
|
let val = self.eval_expr(scope, fn_lib, expr, level)?;
|
||||||
// TODO - avoid copying variable name in inner block?
|
// TODO - avoid copying variable name in inner block?
|
||||||
scope.push_dynamic_value(name.clone(), ScopeEntryType::Constant, val, true);
|
scope.push_dynamic_value(name.clone(), ScopeEntryType::Constant, val, true);
|
||||||
Ok(().into_dynamic())
|
Ok(().into_dynamic())
|
||||||
@ -1745,11 +1744,6 @@ impl Engine<'_> {
|
|||||||
.unwrap_or(name)
|
.unwrap_or(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clean up all script-defined functions within the `Engine`.
|
|
||||||
pub fn clear_functions(&mut self) {
|
|
||||||
self.fn_lib = None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print/debug to stdout
|
/// Print/debug to stdout
|
||||||
|
@ -39,15 +39,18 @@ struct State<'a> {
|
|||||||
constants: Vec<(String, Expr)>,
|
constants: Vec<(String, Expr)>,
|
||||||
/// An `Engine` instance for eager function evaluation.
|
/// An `Engine` instance for eager function evaluation.
|
||||||
engine: &'a Engine<'a>,
|
engine: &'a Engine<'a>,
|
||||||
|
/// Library of script-defined functions.
|
||||||
|
fn_lib: &'a [(&'a str, usize)],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> State<'a> {
|
impl<'a> State<'a> {
|
||||||
/// Create a new State.
|
/// Create a new State.
|
||||||
pub fn new(engine: &'a Engine<'a>) -> Self {
|
pub fn new(engine: &'a Engine<'a>, fn_lib: &'a [(&'a str, usize)]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
changed: false,
|
changed: false,
|
||||||
constants: vec![],
|
constants: vec![],
|
||||||
engine,
|
engine,
|
||||||
|
fn_lib,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Reset the state from dirty to clean.
|
/// Reset the state from dirty to clean.
|
||||||
@ -502,12 +505,10 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
&& args.iter().all(|expr| expr.is_constant()) // all arguments are constants
|
&& args.iter().all(|expr| expr.is_constant()) // all arguments are constants
|
||||||
=> {
|
=> {
|
||||||
// First search in script-defined functions (can override built-in)
|
// First search in script-defined functions (can override built-in)
|
||||||
if let Some(fn_lib_arc) = &state.engine.fn_lib {
|
if state.fn_lib.iter().find(|(name, len)| name == &id && *len == args.len()).is_some() {
|
||||||
if fn_lib_arc.has_function(&id, args.len()) {
|
|
||||||
// A script-defined function overrides the built-in function - do not make the call
|
// A script-defined function overrides the built-in function - do not make the call
|
||||||
return Expr::FunctionCall(id, args.into_iter().map(|a| optimize_expr(a, state)).collect(), def_value, pos);
|
return Expr::FunctionCall(id, args.into_iter().map(|a| optimize_expr(a, state)).collect(), def_value, pos);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let mut arg_values: Vec<_> = args.iter().map(Expr::get_constant_value).collect();
|
let mut arg_values: Vec<_> = args.iter().map(Expr::get_constant_value).collect();
|
||||||
let mut call_args: Vec<_> = arg_values.iter_mut().map(Dynamic::as_mut).collect();
|
let mut call_args: Vec<_> = arg_values.iter_mut().map(Dynamic::as_mut).collect();
|
||||||
@ -554,14 +555,19 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn optimize<'a>(statements: Vec<Stmt>, engine: &Engine<'a>, scope: &Scope) -> Vec<Stmt> {
|
pub(crate) fn optimize<'a>(
|
||||||
|
statements: Vec<Stmt>,
|
||||||
|
engine: &Engine<'a>,
|
||||||
|
scope: &Scope,
|
||||||
|
fn_lib: &'a [(&'a str, usize)],
|
||||||
|
) -> Vec<Stmt> {
|
||||||
// If optimization level is None then skip optimizing
|
// If optimization level is None then skip optimizing
|
||||||
if engine.optimization_level == OptimizationLevel::None {
|
if engine.optimization_level == OptimizationLevel::None {
|
||||||
return statements;
|
return statements;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up the state
|
// Set up the state
|
||||||
let mut state = State::new(engine);
|
let mut state = State::new(engine, fn_lib);
|
||||||
|
|
||||||
// Add constants from the scope into the state
|
// Add constants from the scope into the state
|
||||||
scope
|
scope
|
||||||
@ -635,7 +641,12 @@ pub fn optimize_into_ast(
|
|||||||
statements: Vec<Stmt>,
|
statements: Vec<Stmt>,
|
||||||
functions: Vec<FnDef>,
|
functions: Vec<FnDef>,
|
||||||
) -> AST {
|
) -> AST {
|
||||||
let fn_lib = FunctionsLib::from_vec(
|
let fn_lib: Vec<_> = functions
|
||||||
|
.iter()
|
||||||
|
.map(|fn_def| (fn_def.name.as_str(), fn_def.params.len()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let lib = FunctionsLib::from_vec(
|
||||||
functions
|
functions
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -644,7 +655,7 @@ pub fn optimize_into_ast(
|
|||||||
let pos = fn_def.body.position();
|
let pos = fn_def.body.position();
|
||||||
|
|
||||||
// Optimize the function body
|
// Optimize the function body
|
||||||
let mut body = optimize(vec![fn_def.body], engine, &Scope::new());
|
let mut body = optimize(vec![fn_def.body], engine, &Scope::new(), &fn_lib);
|
||||||
|
|
||||||
// {} -> Noop
|
// {} -> Noop
|
||||||
fn_def.body = match body.pop().unwrap_or_else(|| Stmt::Noop(pos)) {
|
fn_def.body = match body.pop().unwrap_or_else(|| Stmt::Noop(pos)) {
|
||||||
@ -667,12 +678,12 @@ pub fn optimize_into_ast(
|
|||||||
match engine.optimization_level {
|
match engine.optimization_level {
|
||||||
OptimizationLevel::None => statements,
|
OptimizationLevel::None => statements,
|
||||||
OptimizationLevel::Simple | OptimizationLevel::Full => {
|
OptimizationLevel::Simple | OptimizationLevel::Full => {
|
||||||
optimize(statements, engine, &scope)
|
optimize(statements, engine, &scope, &fn_lib)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
Arc::new(fn_lib),
|
Arc::new(lib),
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
Rc::new(fn_lib),
|
Rc::new(lib),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -199,7 +199,7 @@ impl AST {
|
|||||||
/// # {
|
/// # {
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
/// let ast1 = engine.compile(r#"fn foo(x) { 42 + x } foo(1)"#)?;
|
/// let ast1 = engine.compile(r#"fn foo(x) { 42 + x } foo(1)"#)?;
|
||||||
/// let ast2 = engine.compile(r#"fn foo(n) { "hello" + n } foo("!")"#)?;
|
/// let ast2 = engine.compile(r#"fn foo(n) { "hello" + n } foo("!")"#)?;
|
||||||
|
@ -16,6 +16,8 @@ use crate::stdlib::path::PathBuf;
|
|||||||
/// Evaluation result.
|
/// Evaluation result.
|
||||||
///
|
///
|
||||||
/// All wrapped `Position` values represent the location in the script where the error occurs.
|
/// All wrapped `Position` values represent the location in the script where the error occurs.
|
||||||
|
///
|
||||||
|
/// Currently, `EvalAltResult` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum EvalAltResult {
|
pub enum EvalAltResult {
|
||||||
/// Syntax error.
|
/// Syntax error.
|
||||||
|
@ -49,7 +49,7 @@ pub(crate) struct EntryRef<'a> {
|
|||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::{Engine, Scope};
|
/// use rhai::{Engine, Scope};
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
/// let mut my_scope = Scope::new();
|
/// let mut my_scope = Scope::new();
|
||||||
///
|
///
|
||||||
/// my_scope.push("z", 40_i64);
|
/// my_scope.push("z", 40_i64);
|
||||||
|
@ -3,7 +3,7 @@ use rhai::{Array, Engine, EvalAltResult, RegisterFn, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_arrays() -> Result<(), EvalAltResult> {
|
fn test_arrays() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("let x = [1, 2, 3]; x[1]")?, 2);
|
assert_eq!(engine.eval::<INT>("let x = [1, 2, 3]; x[1]")?, 2);
|
||||||
assert_eq!(engine.eval::<INT>("let y = [1, 2, 3]; y[1] = 5; y[1]")?, 5);
|
assert_eq!(engine.eval::<INT>("let y = [1, 2, 3]; y[1] = 5; y[1]")?, 5);
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_binary_ops() -> Result<(), EvalAltResult> {
|
fn test_binary_ops() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("10 % 4")?, 2);
|
assert_eq!(engine.eval::<INT>("10 % 4")?, 2);
|
||||||
assert_eq!(engine.eval::<INT>("10 << 4")?, 160);
|
assert_eq!(engine.eval::<INT>("10 << 4")?, 160);
|
||||||
|
@ -2,14 +2,14 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_left_shift() -> Result<(), EvalAltResult> {
|
fn test_left_shift() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
assert_eq!(engine.eval::<INT>("4 << 2")?, 16);
|
assert_eq!(engine.eval::<INT>("4 << 2")?, 16);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_right_shift() -> Result<(), EvalAltResult> {
|
fn test_right_shift() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
assert_eq!(engine.eval::<INT>("9 >> 1")?, 4);
|
assert_eq!(engine.eval::<INT>("9 >> 1")?, 4);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bool_op1() -> Result<(), EvalAltResult> {
|
fn test_bool_op1() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<bool>("true && (false || true)")?, true);
|
assert_eq!(engine.eval::<bool>("true && (false || true)")?, true);
|
||||||
assert_eq!(engine.eval::<bool>("true & (false | true)")?, true);
|
assert_eq!(engine.eval::<bool>("true & (false | true)")?, true);
|
||||||
@ -12,7 +12,7 @@ fn test_bool_op1() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bool_op2() -> Result<(), EvalAltResult> {
|
fn test_bool_op2() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<bool>("false && (false || true)")?, false);
|
assert_eq!(engine.eval::<bool>("false && (false || true)")?, false);
|
||||||
assert_eq!(engine.eval::<bool>("false & (false | true)")?, false);
|
assert_eq!(engine.eval::<bool>("false & (false | true)")?, false);
|
||||||
@ -22,7 +22,7 @@ fn test_bool_op2() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bool_op3() -> Result<(), EvalAltResult> {
|
fn test_bool_op3() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert!(engine.eval::<bool>("true && (false || 123)").is_err());
|
assert!(engine.eval::<bool>("true && (false || 123)").is_err());
|
||||||
assert_eq!(engine.eval::<bool>("true && (true || 123)")?, true);
|
assert_eq!(engine.eval::<bool>("true && (true || 123)")?, true);
|
||||||
@ -34,7 +34,7 @@ fn test_bool_op3() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bool_op_short_circuit() -> Result<(), EvalAltResult> {
|
fn test_bool_op_short_circuit() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<bool>(
|
engine.eval::<bool>(
|
||||||
@ -63,7 +63,7 @@ fn test_bool_op_short_circuit() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bool_op_no_short_circuit1() {
|
fn test_bool_op_no_short_circuit1() {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert!(engine
|
assert!(engine
|
||||||
.eval::<bool>(
|
.eval::<bool>(
|
||||||
@ -78,7 +78,7 @@ fn test_bool_op_no_short_circuit1() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bool_op_no_short_circuit2() {
|
fn test_bool_op_no_short_circuit2() {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert!(engine
|
assert!(engine
|
||||||
.eval::<bool>(
|
.eval::<bool>(
|
||||||
|
@ -20,7 +20,7 @@ fn test_fn() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_call_fn() -> Result<(), EvalAltResult> {
|
fn test_call_fn() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
scope.push("foo", 42 as INT);
|
scope.push("foo", 42 as INT);
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_chars() -> Result<(), EvalAltResult> {
|
fn test_chars() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<char>("'y'")?, 'y');
|
assert_eq!(engine.eval::<char>("'y'")?, 'y');
|
||||||
assert_eq!(engine.eval::<char>("'\\u2764'")?, '❤');
|
assert_eq!(engine.eval::<char>("'\\u2764'")?, '❤');
|
||||||
|
@ -2,13 +2,13 @@ use rhai::{Engine, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_comments() {
|
fn test_comments() {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert!(engine
|
assert!(engine
|
||||||
.eval::<INT>("let x = 5; x // I am a single line comment, yay!")
|
.eval::<INT>("let x = 5; x // I am a single line comment, yay!")
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
|
||||||
assert!(engine
|
assert!(engine
|
||||||
.eval::<INT>("let /* I am a multiline comment, yay! */ x = 5; x")
|
.eval::<INT>("let /* I am a multi-line comment, yay! */ x = 5; x")
|
||||||
.is_ok());
|
.is_ok());
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_or_equals() -> Result<(), EvalAltResult> {
|
fn test_or_equals() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("let x = 16; x |= 74; x")?, 90);
|
assert_eq!(engine.eval::<INT>("let x = 16; x |= 74; x")?, 90);
|
||||||
assert_eq!(engine.eval::<bool>("let x = true; x |= false; x")?, true);
|
assert_eq!(engine.eval::<bool>("let x = true; x |= false; x")?, true);
|
||||||
@ -13,7 +13,7 @@ fn test_or_equals() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_and_equals() -> Result<(), EvalAltResult> {
|
fn test_and_equals() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("let x = 16; x &= 31; x")?, 16);
|
assert_eq!(engine.eval::<INT>("let x = 16; x &= 31; x")?, 16);
|
||||||
assert_eq!(engine.eval::<bool>("let x = true; x &= false; x")?, false);
|
assert_eq!(engine.eval::<bool>("let x = true; x &= false; x")?, false);
|
||||||
@ -25,42 +25,42 @@ fn test_and_equals() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_xor_equals() -> Result<(), EvalAltResult> {
|
fn test_xor_equals() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
assert_eq!(engine.eval::<INT>("let x = 90; x ^= 12; x")?, 86);
|
assert_eq!(engine.eval::<INT>("let x = 90; x ^= 12; x")?, 86);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_multiply_equals() -> Result<(), EvalAltResult> {
|
fn test_multiply_equals() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
assert_eq!(engine.eval::<INT>("let x = 2; x *= 3; x")?, 6);
|
assert_eq!(engine.eval::<INT>("let x = 2; x *= 3; x")?, 6);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_divide_equals() -> Result<(), EvalAltResult> {
|
fn test_divide_equals() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
assert_eq!(engine.eval::<INT>("let x = 6; x /= 2; x")?, 3);
|
assert_eq!(engine.eval::<INT>("let x = 6; x /= 2; x")?, 3);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_left_shift_equals() -> Result<(), EvalAltResult> {
|
fn test_left_shift_equals() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
assert_eq!(engine.eval::<INT>("let x = 9; x >>=1; x")?, 4);
|
assert_eq!(engine.eval::<INT>("let x = 9; x >>=1; x")?, 4);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_right_shift_equals() -> Result<(), EvalAltResult> {
|
fn test_right_shift_equals() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
assert_eq!(engine.eval::<INT>("let x = 4; x<<= 2; x")?, 16);
|
assert_eq!(engine.eval::<INT>("let x = 4; x<<= 2; x")?, 16);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_modulo_equals() -> Result<(), EvalAltResult> {
|
fn test_modulo_equals() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
assert_eq!(engine.eval::<INT>("let x = 10; x %= 4; x")?, 2);
|
assert_eq!(engine.eval::<INT>("let x = 10; x %= 4; x")?, 2);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_constant() -> Result<(), EvalAltResult> {
|
fn test_constant() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("const x = 123; x")?, 123);
|
assert_eq!(engine.eval::<INT>("const x = 123; x")?, 123);
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_decrement() -> Result<(), EvalAltResult> {
|
fn test_decrement() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("let x = 10; x -= 7; x")?, 3);
|
assert_eq!(engine.eval::<INT>("let x = 10; x -= 7; x")?, 3);
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, Scope, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_eval() -> Result<(), EvalAltResult> {
|
fn test_eval() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<INT>(
|
engine.eval::<INT>(
|
||||||
@ -19,7 +19,7 @@ fn test_eval() -> Result<(), EvalAltResult> {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
fn test_eval_function() -> Result<(), EvalAltResult> {
|
fn test_eval_function() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -62,7 +62,7 @@ fn test_eval_function() -> Result<(), EvalAltResult> {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
fn test_eval_override() -> Result<(), EvalAltResult> {
|
fn test_eval_override() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<String>(
|
engine.eval::<String>(
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, Scope, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_expressions() -> Result<(), EvalAltResult> {
|
fn test_expressions() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
scope.push("x", 10 as INT);
|
scope.push("x", 10 as INT);
|
||||||
|
@ -5,7 +5,7 @@ const EPSILON: FLOAT = 0.000_000_000_1;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_float() -> Result<(), EvalAltResult> {
|
fn test_float() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<bool>("let x = 0.0; let y = 1.0; x < y")?,
|
engine.eval::<bool>("let x = 0.0; let y = 1.0; x < y")?,
|
||||||
|
@ -3,7 +3,7 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_for_array() -> Result<(), EvalAltResult> {
|
fn test_for_array() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
let script = r"
|
let script = r"
|
||||||
let sum1 = 0;
|
let sum1 = 0;
|
||||||
@ -33,7 +33,7 @@ fn test_for_array() -> Result<(), EvalAltResult> {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_for_object() -> Result<(), EvalAltResult> {
|
fn test_for_object() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
let script = r#"
|
let script = r#"
|
||||||
let sum = 0;
|
let sum = 0;
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_if() -> Result<(), EvalAltResult> {
|
fn test_if() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("if true { 55 }")?, 55);
|
assert_eq!(engine.eval::<INT>("if true { 55 }")?, 55);
|
||||||
assert_eq!(engine.eval::<INT>("if false { 55 } else { 44 }")?, 44);
|
assert_eq!(engine.eval::<INT>("if false { 55 } else { 44 }")?, 44);
|
||||||
@ -30,7 +30,7 @@ fn test_if() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_if_expr() -> Result<(), EvalAltResult> {
|
fn test_if_expr() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<INT>(
|
engine.eval::<INT>(
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_increment() -> Result<(), EvalAltResult> {
|
fn test_increment() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("let x = 1; x += 2; x")?, 3);
|
assert_eq!(engine.eval::<INT>("let x = 1; x += 2; x")?, 3);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -4,9 +4,12 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_internal_fn() -> Result<(), EvalAltResult> {
|
fn test_internal_fn() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("fn addme(a, b) { a+b } addme(3, 4)")?, 7);
|
assert_eq!(
|
||||||
|
engine.eval::<INT>("fn add_me(a, b) { a+b } add_me(3, 4)")?,
|
||||||
|
7
|
||||||
|
);
|
||||||
assert_eq!(engine.eval::<INT>("fn bob() { return 4; 5 } bob()")?, 4);
|
assert_eq!(engine.eval::<INT>("fn bob() { return 4; 5 } bob()")?, 4);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -14,15 +17,15 @@ fn test_internal_fn() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_big_internal_fn() -> Result<(), EvalAltResult> {
|
fn test_big_internal_fn() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<INT>(
|
engine.eval::<INT>(
|
||||||
r"
|
r"
|
||||||
fn mathme(a, b, c, d, e, f) {
|
fn math_me(a, b, c, d, e, f) {
|
||||||
a - b * c + d * e - f
|
a - b * c + d * e - f
|
||||||
}
|
}
|
||||||
mathme(100, 5, 2, 9, 6, 32)
|
math_me(100, 5, 2, 9, 6, 32)
|
||||||
",
|
",
|
||||||
)?,
|
)?,
|
||||||
112
|
112
|
||||||
@ -33,7 +36,7 @@ fn test_big_internal_fn() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_internal_fn_overloading() -> Result<(), EvalAltResult> {
|
fn test_internal_fn_overloading() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<INT>(
|
engine.eval::<INT>(
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_loop() -> Result<(), EvalAltResult> {
|
fn test_loop() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<INT>(
|
engine.eval::<INT>(
|
||||||
|
@ -4,7 +4,7 @@ use rhai::{AnyExt, Engine, EvalAltResult, Map, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_map_indexing() -> Result<(), EvalAltResult> {
|
fn test_map_indexing() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
@ -75,7 +75,7 @@ fn test_map_indexing() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_map_assign() -> Result<(), EvalAltResult> {
|
fn test_map_assign() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
let x = engine.eval::<Map>(r#"let x = #{a: 1, b: true, "c$": "hello"}; x"#)?;
|
let x = engine.eval::<Map>(r#"let x = #{a: 1, b: true, "c$": "hello"}; x"#)?;
|
||||||
let a = x.get("a").cloned().expect("should have property a");
|
let a = x.get("a").cloned().expect("should have property a");
|
||||||
@ -91,7 +91,7 @@ fn test_map_assign() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_map_return() -> Result<(), EvalAltResult> {
|
fn test_map_return() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
let x = engine.eval::<Map>(r#"#{a: 1, b: true, "c$": "hello"}"#)?;
|
let x = engine.eval::<Map>(r#"#{a: 1, b: true, "c$": "hello"}"#)?;
|
||||||
let a = x.get("a").cloned().expect("should have property a");
|
let a = x.get("a").cloned().expect("should have property a");
|
||||||
@ -107,7 +107,7 @@ fn test_map_return() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_map_for() -> Result<(), EvalAltResult> {
|
fn test_map_for() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<INT>(
|
engine.eval::<INT>(
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_math() -> Result<(), EvalAltResult> {
|
fn test_math() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("1 + 2")?, 3);
|
assert_eq!(engine.eval::<INT>("1 + 2")?, 3);
|
||||||
assert_eq!(engine.eval::<INT>("1 - 2")?, -1);
|
assert_eq!(engine.eval::<INT>("1 - 2")?, -1);
|
||||||
|
@ -3,7 +3,7 @@ use rhai::{Engine, EvalAltResult, RegisterFn, INT};
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(feature = "no_stdlib"))]
|
#[cfg(not(feature = "no_stdlib"))]
|
||||||
fn test_mismatched_op() {
|
fn test_mismatched_op() {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
matches!(engine.eval::<INT>(r#"60 + "hello""#).expect_err("expects error"),
|
matches!(engine.eval::<INT>(r#"60 + "hello""#).expect_err("expects error"),
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_not() -> Result<(), EvalAltResult> {
|
fn test_not() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<bool>("let not_true = !true; not_true")?,
|
engine.eval::<bool>("let not_true = !true; not_true")?,
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_number_literal() -> Result<(), EvalAltResult> {
|
fn test_number_literal() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("65")?, 65);
|
assert_eq!(engine.eval::<INT>("65")?, 65);
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ fn test_number_literal() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hex_literal() -> Result<(), EvalAltResult> {
|
fn test_hex_literal() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("let x = 0xf; x")?, 15);
|
assert_eq!(engine.eval::<INT>("let x = 0xf; x")?, 15);
|
||||||
assert_eq!(engine.eval::<INT>("let x = 0xff; x")?, 255);
|
assert_eq!(engine.eval::<INT>("let x = 0xff; x")?, 255);
|
||||||
@ -21,7 +21,7 @@ fn test_hex_literal() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_octal_literal() -> Result<(), EvalAltResult> {
|
fn test_octal_literal() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("let x = 0o77; x")?, 63);
|
assert_eq!(engine.eval::<INT>("let x = 0o77; x")?, 63);
|
||||||
assert_eq!(engine.eval::<INT>("let x = 0o1234; x")?, 668);
|
assert_eq!(engine.eval::<INT>("let x = 0o1234; x")?, 668);
|
||||||
@ -31,7 +31,7 @@ fn test_octal_literal() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_binary_literal() -> Result<(), EvalAltResult> {
|
fn test_binary_literal() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("let x = 0b1111; x")?, 15);
|
assert_eq!(engine.eval::<INT>("let x = 0b1111; x")?, 15);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ops() -> Result<(), EvalAltResult> {
|
fn test_ops() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("60 + 5")?, 65);
|
assert_eq!(engine.eval::<INT>("60 + 5")?, 65);
|
||||||
assert_eq!(engine.eval::<INT>("(1 + 2) * (6 - 4) / 2")?, 3);
|
assert_eq!(engine.eval::<INT>("(1 + 2) * (6 - 4) / 2")?, 3);
|
||||||
@ -11,8 +11,8 @@ fn test_ops() -> Result<(), EvalAltResult> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_op_prec() -> Result<(), EvalAltResult> {
|
fn test_op_precedence() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<INT>("let x = 0; if x == 10 || true { x = 1} x")?,
|
engine.eval::<INT>("let x = 0; if x == 10 || true { x = 1} x")?,
|
||||||
|
@ -8,7 +8,7 @@ const EPSILON: FLOAT = 0.000_000_000_1;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_power_of() -> Result<(), EvalAltResult> {
|
fn test_power_of() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("2 ~ 3")?, 8);
|
assert_eq!(engine.eval::<INT>("2 ~ 3")?, 8);
|
||||||
assert_eq!(engine.eval::<INT>("(-2 ~ 3)")?, -8);
|
assert_eq!(engine.eval::<INT>("(-2 ~ 3)")?, -8);
|
||||||
@ -29,7 +29,7 @@ fn test_power_of() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_power_of_equals() -> Result<(), EvalAltResult> {
|
fn test_power_of_equals() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("let x = 2; x ~= 3; x")?, 8);
|
assert_eq!(engine.eval::<INT>("let x = 2; x ~= 3; x")?, 8);
|
||||||
assert_eq!(engine.eval::<INT>("let x = -2; x ~= 3; x")?, -8);
|
assert_eq!(engine.eval::<INT>("let x = -2; x ~= 3; x")?, -8);
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![cfg(not(feature = "no_object"))]
|
|
||||||
|
|
||||||
///! This test simulates an external command object that is driven by a script.
|
///! This test simulates an external command object that is driven by a script.
|
||||||
use rhai::{Engine, EvalAltResult, RegisterFn, Scope, INT};
|
use rhai::{Engine, EvalAltResult, RegisterFn, Scope, INT};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
@ -40,8 +38,9 @@ impl CommandWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_side_effects() -> Result<(), EvalAltResult> {
|
fn test_side_effects_command() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
@ -79,3 +78,22 @@ fn test_side_effects() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_side_effects_print() -> Result<(), EvalAltResult> {
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
|
let result = RwLock::new(String::from(""));
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
// Override action of 'print' function
|
||||||
|
engine.on_print(|s| result.write().unwrap().push_str(s));
|
||||||
|
|
||||||
|
engine.consume("print(40 + 2);")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(*result.read().unwrap(), "42");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_string() -> Result<(), EvalAltResult> {
|
fn test_string() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<String>(r#""Test string: \u2764""#)?,
|
engine.eval::<String>(r#""Test string: \u2764""#)?,
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_throw() {
|
fn test_throw() {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
engine.eval::<()>(r#"if true { throw "hello" }"#).expect_err("expects error"),
|
engine.eval::<()>(r#"if true { throw "hello" }"#).expect_err("expects error"),
|
||||||
|
@ -4,7 +4,7 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
// TODO also add test case for unary after compound
|
// TODO also add test case for unary after compound
|
||||||
// Hah, turns out unary + has a good use after all!
|
// Hah, turns out unary + has a good use after all!
|
||||||
fn test_unary_after_binary() -> Result<(), EvalAltResult> {
|
fn test_unary_after_binary() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("10 % +4")?, 2);
|
assert_eq!(engine.eval::<INT>("10 % +4")?, 2);
|
||||||
assert_eq!(engine.eval::<INT>("10 << +4")?, 160);
|
assert_eq!(engine.eval::<INT>("10 << +4")?, 160);
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unary_minus() -> Result<(), EvalAltResult> {
|
fn test_unary_minus() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("let x = -5; x")?, -5);
|
assert_eq!(engine.eval::<INT>("let x = -5; x")?, -5);
|
||||||
|
|
||||||
|
@ -2,21 +2,21 @@ use rhai::{Engine, EvalAltResult};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unit() -> Result<(), EvalAltResult> {
|
fn test_unit() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
engine.eval::<()>("let x = (); x")?;
|
engine.eval::<()>("let x = (); x")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unit_eq() -> Result<(), EvalAltResult> {
|
fn test_unit_eq() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
assert_eq!(engine.eval::<bool>("let x = (); let y = (); x == y")?, true);
|
assert_eq!(engine.eval::<bool>("let x = (); let y = (); x == y")?, true);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unit_with_spaces() -> Result<(), EvalAltResult> {
|
fn test_unit_with_spaces() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
engine.eval::<()>("let x = ( ); x")?;
|
engine.eval::<()>("let x = ( ); x")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, Scope, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_var_scope() -> Result<(), EvalAltResult> {
|
fn test_var_scope() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
engine.eval_with_scope::<()>(&mut scope, "let x = 4 + 5")?;
|
engine.eval_with_scope::<()>(&mut scope, "let x = 4 + 5")?;
|
||||||
@ -21,7 +21,7 @@ fn test_var_scope() -> Result<(), EvalAltResult> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_scope_eval() -> Result<(), EvalAltResult> {
|
fn test_scope_eval() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
// First create the state
|
// First create the state
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
|
@ -2,7 +2,7 @@ use rhai::{Engine, EvalAltResult, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_while() -> Result<(), EvalAltResult> {
|
fn test_while() -> Result<(), EvalAltResult> {
|
||||||
let mut engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<INT>(
|
engine.eval::<INT>(
|
||||||
|
Loading…
Reference in New Issue
Block a user