Merge pull request #281 from schungx/master
Allow functions to use global imports.
This commit is contained in:
commit
6937f596fd
@ -6,7 +6,7 @@ members = [
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "rhai"
|
name = "rhai"
|
||||||
version = "0.19.4"
|
version = "0.19.5"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"]
|
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"]
|
||||||
description = "Embedded scripting for Rust"
|
description = "Embedded scripting for Rust"
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
Rhai Release Notes
|
Rhai Release Notes
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
Version 0.19.5
|
||||||
|
==============
|
||||||
|
|
||||||
|
Breaking changes
|
||||||
|
----------------
|
||||||
|
|
||||||
|
* Modules imported at global level can now be accessed in functions.
|
||||||
|
|
||||||
|
|
||||||
Version 0.19.4
|
Version 0.19.4
|
||||||
==============
|
==============
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "0.19.4",
|
"version": "0.19.5",
|
||||||
"repoHome": "https://github.com/jonathandturner/rhai/blob/master",
|
"repoHome": "https://github.com/jonathandturner/rhai/blob/master",
|
||||||
"repoTree": "https://github.com/jonathandturner/rhai/tree/master",
|
"repoTree": "https://github.com/jonathandturner/rhai/tree/master",
|
||||||
"rootUrl": "",
|
"rootUrl": "",
|
||||||
|
@ -82,8 +82,9 @@ fn get_message() { "Hello!" }
|
|||||||
| script.rhai |
|
| script.rhai |
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
import "message" as msg;
|
||||||
|
|
||||||
fn say_hello() {
|
fn say_hello() {
|
||||||
import "message" as msg;
|
|
||||||
print(msg::get_message());
|
print(msg::get_message());
|
||||||
}
|
}
|
||||||
say_hello();
|
say_hello();
|
||||||
|
@ -77,7 +77,6 @@ f::do_work(); // works!
|
|||||||
let p = Fn("f::do_work"); // error: invalid function name
|
let p = Fn("f::do_work"); // error: invalid function name
|
||||||
|
|
||||||
fn do_work_now() { // call it from a local function
|
fn do_work_now() { // call it from a local function
|
||||||
import "foo" as f;
|
|
||||||
f::do_work();
|
f::do_work();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
63
src/ast.rs
63
src/ast.rs
@ -4,7 +4,7 @@ use crate::dynamic::{Dynamic, Union};
|
|||||||
use crate::fn_native::{FnPtr, Shared};
|
use crate::fn_native::{FnPtr, Shared};
|
||||||
use crate::module::{Module, ModuleRef};
|
use crate::module::{Module, ModuleRef};
|
||||||
use crate::syntax::FnCustomSyntaxEval;
|
use crate::syntax::FnCustomSyntaxEval;
|
||||||
use crate::token::{Position, Token};
|
use crate::token::{Position, Token, NO_POS};
|
||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
use crate::StaticVec;
|
use crate::StaticVec;
|
||||||
use crate::INT;
|
use crate::INT;
|
||||||
@ -93,9 +93,9 @@ pub struct ScriptFnDef {
|
|||||||
pub access: FnAccess,
|
pub access: FnAccess,
|
||||||
/// Names of function parameters.
|
/// Names of function parameters.
|
||||||
pub params: StaticVec<String>,
|
pub params: StaticVec<String>,
|
||||||
/// Access to external variables.
|
/// Access to external variables. Boxed because it occurs rarely.
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
pub externals: HashSet<String>,
|
pub externals: Option<Box<HashSet<String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ScriptFnDef {
|
impl fmt::Display for ScriptFnDef {
|
||||||
@ -590,11 +590,12 @@ pub enum ReturnType {
|
|||||||
Exception,
|
Exception,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// _[INTERNALS]_ A Rhai statement.
|
/// _[INTERNALS]_ A statement.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
/// Each variant is at most one pointer in size (for speed),
|
/// ## WARNING
|
||||||
/// with everything being allocated together in one single tuple.
|
///
|
||||||
|
/// This type is volatile and may change.
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub enum Stmt {
|
pub enum Stmt {
|
||||||
/// No-op.
|
/// No-op.
|
||||||
@ -616,7 +617,7 @@ pub enum Stmt {
|
|||||||
/// { stmt; ... }
|
/// { stmt; ... }
|
||||||
Block(Vec<Stmt>, Position),
|
Block(Vec<Stmt>, Position),
|
||||||
/// try { stmt; ... } catch ( var ) { stmt; ... }
|
/// try { stmt; ... } catch ( var ) { stmt; ... }
|
||||||
TryCatch(Box<(Stmt, Option<Ident>, Stmt, (Position, Position))>),
|
TryCatch(Box<(Stmt, Option<Ident>, Stmt)>, Position, Position),
|
||||||
/// expr
|
/// expr
|
||||||
Expr(Expr),
|
Expr(Expr),
|
||||||
/// continue
|
/// continue
|
||||||
@ -639,7 +640,7 @@ pub enum Stmt {
|
|||||||
impl Default for Stmt {
|
impl Default for Stmt {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Noop(Default::default())
|
Self::Noop(NO_POS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,7 +668,7 @@ impl Stmt {
|
|||||||
| Self::ReturnWithVal((_, pos), _, _) => *pos,
|
| Self::ReturnWithVal((_, pos), _, _) => *pos,
|
||||||
|
|
||||||
Self::Let(x, _, _) | Self::Const(x, _, _) => x.pos,
|
Self::Let(x, _, _) | Self::Const(x, _, _) => x.pos,
|
||||||
Self::TryCatch(x) => (x.3).0,
|
Self::TryCatch(_, pos, _) => *pos,
|
||||||
|
|
||||||
Self::Expr(x) => x.position(),
|
Self::Expr(x) => x.position(),
|
||||||
|
|
||||||
@ -696,7 +697,7 @@ impl Stmt {
|
|||||||
| Self::ReturnWithVal((_, pos), _, _) => *pos = new_pos,
|
| Self::ReturnWithVal((_, pos), _, _) => *pos = new_pos,
|
||||||
|
|
||||||
Self::Let(x, _, _) | Self::Const(x, _, _) => x.pos = new_pos,
|
Self::Let(x, _, _) | Self::Const(x, _, _) => x.pos = new_pos,
|
||||||
Self::TryCatch(x) => (x.3).0 = new_pos,
|
Self::TryCatch(_, pos, _) => *pos = new_pos,
|
||||||
|
|
||||||
Self::Expr(x) => {
|
Self::Expr(x) => {
|
||||||
x.set_position(new_pos);
|
x.set_position(new_pos);
|
||||||
@ -722,7 +723,7 @@ impl Stmt {
|
|||||||
| Self::Loop(_, _)
|
| Self::Loop(_, _)
|
||||||
| Self::For(_, _, _)
|
| Self::For(_, _, _)
|
||||||
| Self::Block(_, _)
|
| Self::Block(_, _)
|
||||||
| Self::TryCatch(_) => true,
|
| Self::TryCatch(_, _, _) => true,
|
||||||
|
|
||||||
// A No-op requires a semicolon in order to know it is an empty statement!
|
// A No-op requires a semicolon in order to know it is an empty statement!
|
||||||
Self::Noop(_) => false,
|
Self::Noop(_) => false,
|
||||||
@ -758,7 +759,7 @@ impl Stmt {
|
|||||||
Self::Let(_, _, _) | Self::Const(_, _, _) | Self::Assignment(_, _) => false,
|
Self::Let(_, _, _) | Self::Const(_, _, _) | Self::Assignment(_, _) => false,
|
||||||
Self::Block(block, _) => block.iter().all(|stmt| stmt.is_pure()),
|
Self::Block(block, _) => block.iter().all(|stmt| stmt.is_pure()),
|
||||||
Self::Continue(_) | Self::Break(_) | Self::ReturnWithVal(_, _, _) => false,
|
Self::Continue(_) | Self::Break(_) | Self::ReturnWithVal(_, _, _) => false,
|
||||||
Self::TryCatch(x) => x.0.is_pure() && x.2.is_pure(),
|
Self::TryCatch(x, _, _) => x.0.is_pure() && x.2.is_pure(),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Import(_, _, _) => false,
|
Self::Import(_, _, _) => false,
|
||||||
@ -779,7 +780,9 @@ impl Stmt {
|
|||||||
/// This type is volatile and may change.
|
/// This type is volatile and may change.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CustomExpr {
|
pub struct CustomExpr {
|
||||||
|
/// List of keywords.
|
||||||
pub(crate) keywords: StaticVec<Expr>,
|
pub(crate) keywords: StaticVec<Expr>,
|
||||||
|
/// Implementation function.
|
||||||
pub(crate) func: Shared<FnCustomSyntaxEval>,
|
pub(crate) func: Shared<FnCustomSyntaxEval>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,6 +851,11 @@ impl From<INT> for FloatWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A binary expression structure.
|
/// A binary expression structure.
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
///
|
||||||
|
/// ## WARNING
|
||||||
|
///
|
||||||
|
/// This type is volatile and may change.
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub struct BinaryExpr {
|
pub struct BinaryExpr {
|
||||||
/// LHS expression.
|
/// LHS expression.
|
||||||
@ -856,7 +864,12 @@ pub struct BinaryExpr {
|
|||||||
pub rhs: Expr,
|
pub rhs: Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A function call.
|
/// _[INTERNALS]_ A function call.
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
///
|
||||||
|
/// ## WARNING
|
||||||
|
///
|
||||||
|
/// This type is volatile and may change.
|
||||||
#[derive(Debug, Clone, Hash, Default)]
|
#[derive(Debug, Clone, Hash, Default)]
|
||||||
pub struct FnCallInfo {
|
pub struct FnCallInfo {
|
||||||
/// Pre-calculated hash for a script-defined function of the same name and number of parameters.
|
/// Pre-calculated hash for a script-defined function of the same name and number of parameters.
|
||||||
@ -869,7 +882,7 @@ pub struct FnCallInfo {
|
|||||||
/// Default value when the function is not found, mostly used to provide a default for comparison functions.
|
/// Default value when the function is not found, mostly used to provide a default for comparison functions.
|
||||||
/// Type is `bool` in order for `FnCallInfo` to be `Hash`
|
/// Type is `bool` in order for `FnCallInfo` to be `Hash`
|
||||||
pub def_value: Option<bool>,
|
pub def_value: Option<bool>,
|
||||||
/// Namespace of the function, if any.
|
/// Namespace of the function, if any. Boxed because it occurs rarely.
|
||||||
pub namespace: Option<Box<ModuleRef>>,
|
pub namespace: Option<Box<ModuleRef>>,
|
||||||
/// Function name.
|
/// Function name.
|
||||||
/// Use `Cow<'static, str>` because a lot of operators (e.g. `==`, `>=`) are implemented as function calls
|
/// Use `Cow<'static, str>` because a lot of operators (e.g. `==`, `>=`) are implemented as function calls
|
||||||
@ -882,9 +895,6 @@ pub struct FnCallInfo {
|
|||||||
/// _[INTERNALS]_ An expression sub-tree.
|
/// _[INTERNALS]_ An expression sub-tree.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
/// Each variant is at most one pointer in size (for speed),
|
|
||||||
/// with everything being allocated together in one single tuple.
|
|
||||||
///
|
|
||||||
/// ## WARNING
|
/// ## WARNING
|
||||||
///
|
///
|
||||||
/// This type is volatile and may change.
|
/// This type is volatile and may change.
|
||||||
@ -938,7 +948,7 @@ pub enum Expr {
|
|||||||
impl Default for Expr {
|
impl Default for Expr {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Unit(Default::default())
|
Self::Unit(NO_POS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1241,16 +1251,21 @@ impl Expr {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// This test is to make sure no code changes increase the sizes of critical data structures.
|
/// This test is to make sure no code changes increase the sizes of critical data structures.
|
||||||
#[test]
|
#[test]
|
||||||
fn check_struct_sizes() {
|
fn check_struct_sizes() {
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
|
|
||||||
assert_eq!(size_of::<Dynamic>(), 16);
|
assert_eq!(size_of::<crate::Dynamic>(), 16);
|
||||||
assert_eq!(size_of::<Option<Dynamic>>(), 16);
|
assert_eq!(size_of::<Option<crate::Dynamic>>(), 16);
|
||||||
assert_eq!(size_of::<Expr>(), 16);
|
assert_eq!(size_of::<crate::Position>(), 4);
|
||||||
assert_eq!(size_of::<Stmt>(), 32);
|
assert_eq!(size_of::<crate::ast::Expr>(), 16);
|
||||||
|
assert_eq!(size_of::<Option<crate::ast::Expr>>(), 16);
|
||||||
|
assert_eq!(size_of::<crate::ast::Stmt>(), 32);
|
||||||
|
assert_eq!(size_of::<Option<crate::ast::Stmt>>(), 32);
|
||||||
|
assert_eq!(size_of::<crate::Scope>(), 72);
|
||||||
|
assert_eq!(size_of::<crate::LexError>(), 32);
|
||||||
|
assert_eq!(size_of::<crate::ParseError>(), 16);
|
||||||
|
assert_eq!(size_of::<crate::EvalAltResult>(), 64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -619,7 +619,6 @@ impl Dynamic {
|
|||||||
|
|
||||||
Self(Union::Variant(Box::new(boxed)))
|
Self(Union::Variant(Box::new(boxed)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Turn the `Dynamic` value into a shared `Dynamic` value backed by an `Rc<RefCell<Dynamic>>`
|
/// Turn the `Dynamic` value into a shared `Dynamic` value backed by an `Rc<RefCell<Dynamic>>`
|
||||||
/// or `Arc<RwLock<Dynamic>>` depending on the `sync` feature.
|
/// or `Arc<RwLock<Dynamic>>` depending on the `sync` feature.
|
||||||
///
|
///
|
||||||
@ -644,7 +643,6 @@ impl Dynamic {
|
|||||||
#[cfg(feature = "no_closure")]
|
#[cfg(feature = "no_closure")]
|
||||||
panic!("converting into a shared value is not supported under 'no_closure'");
|
panic!("converting into a shared value is not supported under 'no_closure'");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the `Dynamic` value into specific type.
|
/// Convert the `Dynamic` value into specific type.
|
||||||
///
|
///
|
||||||
/// Casting to a `Dynamic` just returns as is, but if it contains a shared value,
|
/// Casting to a `Dynamic` just returns as is, but if it contains a shared value,
|
||||||
@ -775,7 +773,6 @@ impl Dynamic {
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the `Dynamic` value into a specific type.
|
/// Convert the `Dynamic` value into a specific type.
|
||||||
///
|
///
|
||||||
/// Casting to a `Dynamic` just returns as is, but if it contains a shared value,
|
/// Casting to a `Dynamic` just returns as is, but if it contains a shared value,
|
||||||
@ -819,7 +816,6 @@ impl Dynamic {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flatten the `Dynamic` and clone it.
|
/// Flatten the `Dynamic` and clone it.
|
||||||
///
|
///
|
||||||
/// If the `Dynamic` is not a shared value, it returns a cloned copy.
|
/// If the `Dynamic` is not a shared value, it returns a cloned copy.
|
||||||
@ -839,7 +835,6 @@ impl Dynamic {
|
|||||||
_ => self.clone(),
|
_ => self.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flatten the `Dynamic`.
|
/// Flatten the `Dynamic`.
|
||||||
///
|
///
|
||||||
/// If the `Dynamic` is not a shared value, it returns itself.
|
/// If the `Dynamic` is not a shared value, it returns itself.
|
||||||
@ -867,7 +862,6 @@ impl Dynamic {
|
|||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is the `Dynamic` a shared value that is locked?
|
/// Is the `Dynamic` a shared value that is locked?
|
||||||
///
|
///
|
||||||
/// ## Note
|
/// ## Note
|
||||||
@ -889,7 +883,6 @@ impl Dynamic {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference of a specific type to the `Dynamic`.
|
/// Get a reference of a specific type to the `Dynamic`.
|
||||||
/// Casting to `Dynamic` just returns a reference to it.
|
/// Casting to `Dynamic` just returns a reference to it.
|
||||||
///
|
///
|
||||||
@ -922,7 +915,6 @@ impl Dynamic {
|
|||||||
.map(|r| DynamicReadLock(DynamicReadLockInner::Reference(r))),
|
.map(|r| DynamicReadLock(DynamicReadLockInner::Reference(r))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a mutable reference of a specific type to the `Dynamic`.
|
/// Get a mutable reference of a specific type to the `Dynamic`.
|
||||||
/// Casting to `Dynamic` just returns a mutable reference to it.
|
/// Casting to `Dynamic` just returns a mutable reference to it.
|
||||||
///
|
///
|
||||||
@ -955,7 +947,6 @@ impl Dynamic {
|
|||||||
.map(|r| DynamicWriteLock(DynamicWriteLockInner::Reference(r))),
|
.map(|r| DynamicWriteLock(DynamicWriteLockInner::Reference(r))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference of a specific type to the `Dynamic`.
|
/// Get a reference of a specific type to the `Dynamic`.
|
||||||
/// Casting to `Dynamic` just returns a reference to it.
|
/// Casting to `Dynamic` just returns a reference to it.
|
||||||
///
|
///
|
||||||
@ -1045,7 +1036,6 @@ impl Dynamic {
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a mutable reference of a specific type to the `Dynamic`.
|
/// Get a mutable reference of a specific type to the `Dynamic`.
|
||||||
/// Casting to `Dynamic` just returns a mutable reference to it.
|
/// Casting to `Dynamic` just returns a mutable reference to it.
|
||||||
///
|
///
|
||||||
@ -1129,7 +1119,6 @@ impl Dynamic {
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cast the `Dynamic` as the system integer type `INT` and return it.
|
/// Cast the `Dynamic` as the system integer type `INT` and return it.
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -1141,7 +1130,6 @@ impl Dynamic {
|
|||||||
_ => Err(self.type_name()),
|
_ => Err(self.type_name()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cast the `Dynamic` as the system floating-point type `FLOAT` and return it.
|
/// Cast the `Dynamic` as the system floating-point type `FLOAT` and return it.
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
@ -1154,7 +1142,6 @@ impl Dynamic {
|
|||||||
_ => Err(self.type_name()),
|
_ => Err(self.type_name()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cast the `Dynamic` as a `bool` and return it.
|
/// Cast the `Dynamic` as a `bool` and return it.
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -1166,7 +1153,6 @@ impl Dynamic {
|
|||||||
_ => Err(self.type_name()),
|
_ => Err(self.type_name()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cast the `Dynamic` as a `char` and return it.
|
/// Cast the `Dynamic` as a `char` and return it.
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -1178,7 +1164,6 @@ impl Dynamic {
|
|||||||
_ => Err(self.type_name()),
|
_ => Err(self.type_name()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cast the `Dynamic` as a string and return the string slice.
|
/// Cast the `Dynamic` as a string and return the string slice.
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
///
|
///
|
||||||
@ -1191,7 +1176,6 @@ impl Dynamic {
|
|||||||
_ => Err(self.type_name()),
|
_ => Err(self.type_name()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the `Dynamic` into `String` and return it.
|
/// Convert the `Dynamic` into `String` and return it.
|
||||||
/// If there are other references to the same string, a cloned copy is returned.
|
/// If there are other references to the same string, a cloned copy is returned.
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
@ -1200,7 +1184,6 @@ impl Dynamic {
|
|||||||
self.take_immutable_string()
|
self.take_immutable_string()
|
||||||
.map(ImmutableString::into_owned)
|
.map(ImmutableString::into_owned)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the `Dynamic` into `ImmutableString` and return it.
|
/// Convert the `Dynamic` into `ImmutableString` and return it.
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
127
src/engine.rs
127
src/engine.rs
@ -88,10 +88,6 @@ impl Imports {
|
|||||||
pub fn get(&self, index: usize) -> Option<&Module> {
|
pub fn get(&self, index: usize) -> Option<&Module> {
|
||||||
self.0.get(index)
|
self.0.get(index)
|
||||||
}
|
}
|
||||||
/// Get a mutable reference to the imported module at a particular index.
|
|
||||||
pub fn get_mut(&mut self, index: usize) -> Option<&mut Module> {
|
|
||||||
self.0.get_mut(index)
|
|
||||||
}
|
|
||||||
/// Get the index of an imported module by name.
|
/// Get the index of an imported module by name.
|
||||||
pub fn find(&self, name: &str) -> Option<usize> {
|
pub fn find(&self, name: &str) -> Option<usize> {
|
||||||
self.1
|
self.1
|
||||||
@ -658,35 +654,6 @@ pub fn search_imports<'s>(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Search for a module within an imports stack.
|
|
||||||
/// Position in `EvalAltResult` is `None` and must be set afterwards.
|
|
||||||
pub fn search_imports_mut<'s>(
|
|
||||||
mods: &'s mut Imports,
|
|
||||||
state: &mut State,
|
|
||||||
modules: &ModuleRef,
|
|
||||||
) -> Result<&'s mut Module, Box<EvalAltResult>> {
|
|
||||||
let Ident { name: root, pos } = &modules[0];
|
|
||||||
|
|
||||||
// Qualified - check if the root module is directly indexed
|
|
||||||
let index = if state.always_search {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
modules.index().map_or(0, NonZeroUsize::get)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(if index > 0 {
|
|
||||||
let offset = mods.len() - index;
|
|
||||||
mods.get_mut(offset).expect("invalid index in Imports")
|
|
||||||
} else {
|
|
||||||
if let Some(n) = mods.find(root) {
|
|
||||||
mods.get_mut(n)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
.ok_or_else(|| EvalAltResult::ErrorModuleNotFound(root.to_string(), *pos))?
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
/// Create a new `Engine`
|
/// Create a new `Engine`
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -803,7 +770,7 @@ impl Engine {
|
|||||||
pub(crate) fn search_namespace<'s, 'a>(
|
pub(crate) fn search_namespace<'s, 'a>(
|
||||||
&self,
|
&self,
|
||||||
scope: &'s mut Scope,
|
scope: &'s mut Scope,
|
||||||
mods: &'s mut Imports,
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
this_ptr: &'s mut Option<&mut Dynamic>,
|
this_ptr: &'s mut Option<&mut Dynamic>,
|
||||||
@ -813,8 +780,8 @@ impl Engine {
|
|||||||
Expr::Variable(v) => match v.as_ref() {
|
Expr::Variable(v) => match v.as_ref() {
|
||||||
// Qualified variable
|
// Qualified variable
|
||||||
(_, Some(modules), hash_var, Ident { name, pos }) => {
|
(_, Some(modules), hash_var, Ident { name, pos }) => {
|
||||||
let module = search_imports_mut(mods, state, modules)?;
|
let module = search_imports(mods, state, modules)?;
|
||||||
let target = module.get_qualified_var_mut(*hash_var).map_err(|mut err| {
|
let target = module.get_qualified_var(*hash_var).map_err(|mut err| {
|
||||||
match *err {
|
match *err {
|
||||||
EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => {
|
EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => {
|
||||||
*err_name = format!("{}{}", modules, name);
|
*err_name = format!("{}{}", modules, name);
|
||||||
@ -825,7 +792,7 @@ impl Engine {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Module variables are constant
|
// Module variables are constant
|
||||||
Ok((target.into(), name, ScopeEntryType::Constant, *pos))
|
Ok((target.clone().into(), name, ScopeEntryType::Constant, *pos))
|
||||||
}
|
}
|
||||||
// Normal variable access
|
// Normal variable access
|
||||||
_ => self.search_scope_only(scope, mods, state, lib, this_ptr, expr),
|
_ => self.search_scope_only(scope, mods, state, lib, this_ptr, expr),
|
||||||
@ -909,6 +876,7 @@ impl Engine {
|
|||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
fn eval_dot_index_chain_helper(
|
fn eval_dot_index_chain_helper(
|
||||||
&self,
|
&self,
|
||||||
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
@ -945,12 +913,12 @@ impl Engine {
|
|||||||
let idx_pos = x.lhs.position();
|
let idx_pos = x.lhs.position();
|
||||||
let idx_val = idx_val.as_value();
|
let idx_val = idx_val.as_value();
|
||||||
let obj_ptr = &mut self.get_indexed_mut(
|
let obj_ptr = &mut self.get_indexed_mut(
|
||||||
state, lib, target, idx_val, idx_pos, false, true, level,
|
mods, state, lib, target, idx_val, idx_pos, false, true, level,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, obj_ptr, &x.rhs, idx_values, next_chain, level,
|
mods, state, lib, this_ptr, obj_ptr, &x.rhs, idx_values, next_chain,
|
||||||
new_val,
|
level, new_val,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*x_pos))
|
.map_err(|err| err.fill_position(*x_pos))
|
||||||
}
|
}
|
||||||
@ -960,9 +928,9 @@ impl Engine {
|
|||||||
let mut idx_val2 = idx_val.clone();
|
let mut idx_val2 = idx_val.clone();
|
||||||
|
|
||||||
// `call_setter` is introduced to bypass double mutable borrowing of target
|
// `call_setter` is introduced to bypass double mutable borrowing of target
|
||||||
let _call_setter = match self
|
let _call_setter = match self.get_indexed_mut(
|
||||||
.get_indexed_mut(state, lib, target, idx_val, pos, true, false, level)
|
mods, state, lib, target, idx_val, pos, true, false, level,
|
||||||
{
|
) {
|
||||||
// Indexed value is a reference - update directly
|
// Indexed value is a reference - update directly
|
||||||
Ok(ref mut obj_ptr) => {
|
Ok(ref mut obj_ptr) => {
|
||||||
obj_ptr.set_value(new_val.unwrap())?;
|
obj_ptr.set_value(new_val.unwrap())?;
|
||||||
@ -984,8 +952,8 @@ impl Engine {
|
|||||||
let args = &mut [val, &mut idx_val2, &mut new_val.0];
|
let args = &mut [val, &mut idx_val2, &mut new_val.0];
|
||||||
|
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, FN_IDX_SET, 0, args, is_ref, true, false, None, None,
|
mods, state, lib, FN_IDX_SET, 0, args, is_ref, true, false, None,
|
||||||
level,
|
None, level,
|
||||||
)
|
)
|
||||||
.map_err(|err| match *err {
|
.map_err(|err| match *err {
|
||||||
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
|
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
|
||||||
@ -1005,7 +973,9 @@ impl Engine {
|
|||||||
// xxx[rhs]
|
// xxx[rhs]
|
||||||
_ => {
|
_ => {
|
||||||
let idx_val = idx_val.as_value();
|
let idx_val = idx_val.as_value();
|
||||||
self.get_indexed_mut(state, lib, target, idx_val, pos, false, true, level)
|
self.get_indexed_mut(
|
||||||
|
mods, state, lib, target, idx_val, pos, false, true, level,
|
||||||
|
)
|
||||||
.map(|v| (v.take_or_clone(), false))
|
.map(|v| (v.take_or_clone(), false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1026,7 +996,8 @@ impl Engine {
|
|||||||
let def_value = def_value.map(Into::<Dynamic>::into);
|
let def_value = def_value.map(Into::<Dynamic>::into);
|
||||||
let args = idx_val.as_fn_call_args();
|
let args = idx_val.as_fn_call_args();
|
||||||
self.make_method_call(
|
self.make_method_call(
|
||||||
state, lib, name, *hash, target, args, def_value, *native, false, level,
|
mods, state, lib, name, *hash, target, args, def_value, *native, false,
|
||||||
|
level,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*pos))
|
.map_err(|err| err.fill_position(*pos))
|
||||||
}
|
}
|
||||||
@ -1036,8 +1007,9 @@ impl Engine {
|
|||||||
Expr::Property(x) if target.is::<Map>() && new_val.is_some() => {
|
Expr::Property(x) if target.is::<Map>() && new_val.is_some() => {
|
||||||
let IdentX { name, pos } = &x.1;
|
let IdentX { name, pos } = &x.1;
|
||||||
let index = name.clone().into();
|
let index = name.clone().into();
|
||||||
let mut val = self
|
let mut val = self.get_indexed_mut(
|
||||||
.get_indexed_mut(state, lib, target, index, *pos, true, false, level)?;
|
mods, state, lib, target, index, *pos, true, false, level,
|
||||||
|
)?;
|
||||||
|
|
||||||
val.set_value(new_val.unwrap())?;
|
val.set_value(new_val.unwrap())?;
|
||||||
Ok((Default::default(), true))
|
Ok((Default::default(), true))
|
||||||
@ -1047,7 +1019,7 @@ impl Engine {
|
|||||||
let IdentX { name, pos } = &x.1;
|
let IdentX { name, pos } = &x.1;
|
||||||
let index = name.clone().into();
|
let index = name.clone().into();
|
||||||
let val = self.get_indexed_mut(
|
let val = self.get_indexed_mut(
|
||||||
state, lib, target, index, *pos, false, false, level,
|
mods, state, lib, target, index, *pos, false, false, level,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok((val.take_or_clone(), false))
|
Ok((val.take_or_clone(), false))
|
||||||
@ -1058,8 +1030,8 @@ impl Engine {
|
|||||||
let mut new_val = new_val;
|
let mut new_val = new_val;
|
||||||
let mut args = [target.as_mut(), &mut new_val.as_mut().unwrap().0];
|
let mut args = [target.as_mut(), &mut new_val.as_mut().unwrap().0];
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, setter, 0, &mut args, is_ref, true, false, None, None,
|
mods, state, lib, setter, 0, &mut args, is_ref, true, false, None,
|
||||||
level,
|
None, level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| (v, true))
|
.map(|(v, _)| (v, true))
|
||||||
.map_err(|err| err.fill_position(*pos))
|
.map_err(|err| err.fill_position(*pos))
|
||||||
@ -1069,8 +1041,8 @@ impl Engine {
|
|||||||
let ((getter, _), IdentX { pos, .. }) = x.as_ref();
|
let ((getter, _), IdentX { pos, .. }) = x.as_ref();
|
||||||
let mut args = [target.as_mut()];
|
let mut args = [target.as_mut()];
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, getter, 0, &mut args, is_ref, true, false, None, None,
|
mods, state, lib, getter, 0, &mut args, is_ref, true, false, None,
|
||||||
level,
|
None, level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| (v, false))
|
.map(|(v, _)| (v, false))
|
||||||
.map_err(|err| err.fill_position(*pos))
|
.map_err(|err| err.fill_position(*pos))
|
||||||
@ -1082,7 +1054,7 @@ impl Engine {
|
|||||||
let IdentX { name, pos } = &p.1;
|
let IdentX { name, pos } = &p.1;
|
||||||
let index = name.clone().into();
|
let index = name.clone().into();
|
||||||
self.get_indexed_mut(
|
self.get_indexed_mut(
|
||||||
state, lib, target, index, *pos, false, true, level,
|
mods, state, lib, target, index, *pos, false, true, level,
|
||||||
)?
|
)?
|
||||||
}
|
}
|
||||||
// {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr
|
// {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr
|
||||||
@ -1098,8 +1070,8 @@ impl Engine {
|
|||||||
let args = idx_val.as_fn_call_args();
|
let args = idx_val.as_fn_call_args();
|
||||||
let (val, _) = self
|
let (val, _) = self
|
||||||
.make_method_call(
|
.make_method_call(
|
||||||
state, lib, name, *hash, target, args, def_value, *native,
|
mods, state, lib, name, *hash, target, args, def_value,
|
||||||
false, level,
|
*native, false, level,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*pos))?;
|
.map_err(|err| err.fill_position(*pos))?;
|
||||||
val.into()
|
val.into()
|
||||||
@ -1111,8 +1083,8 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, &mut val, &x.rhs, idx_values, next_chain, level,
|
mods, state, lib, this_ptr, &mut val, &x.rhs, idx_values, next_chain,
|
||||||
new_val,
|
level, new_val,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*x_pos))
|
.map_err(|err| err.fill_position(*x_pos))
|
||||||
}
|
}
|
||||||
@ -1126,8 +1098,8 @@ impl Engine {
|
|||||||
let args = &mut arg_values[..1];
|
let args = &mut arg_values[..1];
|
||||||
let (mut val, updated) = self
|
let (mut val, updated) = self
|
||||||
.exec_fn_call(
|
.exec_fn_call(
|
||||||
state, lib, getter, 0, args, is_ref, true, false, None,
|
mods, state, lib, getter, 0, args, is_ref, true, false,
|
||||||
None, level,
|
None, None, level,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*pos))?;
|
.map_err(|err| err.fill_position(*pos))?;
|
||||||
|
|
||||||
@ -1135,6 +1107,7 @@ impl Engine {
|
|||||||
|
|
||||||
let (result, may_be_changed) = self
|
let (result, may_be_changed) = self
|
||||||
.eval_dot_index_chain_helper(
|
.eval_dot_index_chain_helper(
|
||||||
|
mods,
|
||||||
state,
|
state,
|
||||||
lib,
|
lib,
|
||||||
this_ptr,
|
this_ptr,
|
||||||
@ -1152,8 +1125,8 @@ impl Engine {
|
|||||||
// Re-use args because the first &mut parameter will not be consumed
|
// Re-use args because the first &mut parameter will not be consumed
|
||||||
arg_values[1] = val;
|
arg_values[1] = val;
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, setter, 0, arg_values, is_ref, true, false,
|
mods, state, lib, setter, 0, arg_values, is_ref, true,
|
||||||
None, None, level,
|
false, None, None, level,
|
||||||
)
|
)
|
||||||
.or_else(
|
.or_else(
|
||||||
|err| match *err {
|
|err| match *err {
|
||||||
@ -1181,16 +1154,16 @@ impl Engine {
|
|||||||
let args = idx_val.as_fn_call_args();
|
let args = idx_val.as_fn_call_args();
|
||||||
let (mut val, _) = self
|
let (mut val, _) = self
|
||||||
.make_method_call(
|
.make_method_call(
|
||||||
state, lib, name, *hash, target, args, def_value, *native,
|
mods, state, lib, name, *hash, target, args, def_value,
|
||||||
false, level,
|
*native, false, level,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*pos))?;
|
.map_err(|err| err.fill_position(*pos))?;
|
||||||
let val = &mut val;
|
let val = &mut val;
|
||||||
let target = &mut val.into();
|
let target = &mut val.into();
|
||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, target, &x.rhs, idx_values, next_chain,
|
mods, state, lib, this_ptr, target, &x.rhs, idx_values,
|
||||||
level, new_val,
|
next_chain, level, new_val,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*pos))
|
.map_err(|err| err.fill_position(*pos))
|
||||||
}
|
}
|
||||||
@ -1275,7 +1248,8 @@ impl Engine {
|
|||||||
|
|
||||||
let obj_ptr = &mut target.into();
|
let obj_ptr = &mut target.into();
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, &mut None, obj_ptr, dot_rhs, idx_values, chain_type, level, new_val,
|
mods, state, lib, &mut None, obj_ptr, dot_rhs, idx_values, chain_type, level,
|
||||||
|
new_val,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v)
|
.map(|(v, _)| v)
|
||||||
.map_err(|err| err.fill_position(op_pos))
|
.map_err(|err| err.fill_position(op_pos))
|
||||||
@ -1287,7 +1261,8 @@ impl Engine {
|
|||||||
let val = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
let val = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||||
let obj_ptr = &mut val.into();
|
let obj_ptr = &mut val.into();
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, obj_ptr, dot_rhs, idx_values, chain_type, level, new_val,
|
mods, state, lib, this_ptr, obj_ptr, dot_rhs, idx_values, chain_type, level,
|
||||||
|
new_val,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v)
|
.map(|(v, _)| v)
|
||||||
.map_err(|err| err.fill_position(op_pos))
|
.map_err(|err| err.fill_position(op_pos))
|
||||||
@ -1375,6 +1350,7 @@ impl Engine {
|
|||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
fn get_indexed_mut<'a>(
|
fn get_indexed_mut<'a>(
|
||||||
&self,
|
&self,
|
||||||
|
_mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
_lib: &[&Module],
|
_lib: &[&Module],
|
||||||
target: &'a mut Target,
|
target: &'a mut Target,
|
||||||
@ -1457,7 +1433,8 @@ impl Engine {
|
|||||||
let mut idx = idx;
|
let mut idx = idx;
|
||||||
let args = &mut [val, &mut idx];
|
let args = &mut [val, &mut idx];
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, _lib, FN_IDX_GET, 0, args, is_ref, true, false, None, None, _level,
|
_mods, state, _lib, FN_IDX_GET, 0, args, is_ref, true, false, None, None,
|
||||||
|
_level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v.into())
|
.map(|(v, _)| v.into())
|
||||||
.map_err(|err| match *err {
|
.map_err(|err| match *err {
|
||||||
@ -1846,8 +1823,8 @@ impl Engine {
|
|||||||
// Run function
|
// Run function
|
||||||
let (value, _) = self
|
let (value, _) = self
|
||||||
.exec_fn_call(
|
.exec_fn_call(
|
||||||
state, lib, op, 0, args, false, false, false, None, None,
|
mods, state, lib, op, 0, args, false, false, false, None,
|
||||||
level,
|
None, level,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*op_pos))?;
|
.map_err(|err| err.fill_position(*op_pos))?;
|
||||||
|
|
||||||
@ -1884,7 +1861,7 @@ impl Engine {
|
|||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
.exec_fn_call(
|
.exec_fn_call(
|
||||||
state, lib, op, 0, args, false, false, false, None, None, level,
|
mods, state, lib, op, 0, args, false, false, false, None, None, level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v)
|
.map(|(v, _)| v)
|
||||||
.map_err(|err| err.fill_position(*op_pos))?;
|
.map_err(|err| err.fill_position(*op_pos))?;
|
||||||
@ -2034,8 +2011,8 @@ impl Engine {
|
|||||||
Stmt::Break(pos) => EvalAltResult::LoopBreak(true, *pos).into(),
|
Stmt::Break(pos) => EvalAltResult::LoopBreak(true, *pos).into(),
|
||||||
|
|
||||||
// Try/Catch statement
|
// Try/Catch statement
|
||||||
Stmt::TryCatch(x) => {
|
Stmt::TryCatch(x, _, _) => {
|
||||||
let (try_body, var_def, catch_body, _) = x.as_ref();
|
let (try_body, var_def, catch_body) = x.as_ref();
|
||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
.eval_stmt(scope, mods, state, lib, this_ptr, try_body, level)
|
.eval_stmt(scope, mods, state, lib, this_ptr, try_body, level)
|
||||||
|
@ -118,7 +118,6 @@ impl<'a> ArgBackup<'a> {
|
|||||||
mem::transmute(&mut self.value_copy)
|
mem::transmute(&mut self.value_copy)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function restores the first argument that was replaced by `change_first_arg_to_copy`.
|
/// This function restores the first argument that was replaced by `change_first_arg_to_copy`.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -470,6 +469,7 @@ impl Engine {
|
|||||||
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
||||||
pub(crate) fn exec_fn_call(
|
pub(crate) fn exec_fn_call(
|
||||||
&self,
|
&self,
|
||||||
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
@ -536,22 +536,25 @@ impl Engine {
|
|||||||
let func = func.get_fn_def();
|
let func = func.get_fn_def();
|
||||||
|
|
||||||
let scope: &mut Scope = &mut Default::default();
|
let scope: &mut Scope = &mut Default::default();
|
||||||
let mods = &mut Default::default();
|
|
||||||
|
|
||||||
// Move captured variables into scope
|
// Move captured variables into scope
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
if let Some(captured) = _capture_scope {
|
if let Some(captured) = _capture_scope {
|
||||||
|
if let Some(ref externals) = func.externals {
|
||||||
captured
|
captured
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(name, _, _, _)| func.externals.contains(name.as_ref()))
|
.filter(|(name, _, _, _)| externals.contains(name.as_ref()))
|
||||||
.for_each(|(name, typ, value, _)| {
|
.for_each(|(name, typ, value, _)| {
|
||||||
// Consume the scope values.
|
// Consume the scope values.
|
||||||
match typ {
|
match typ {
|
||||||
ScopeEntryType::Normal => scope.push(name, value),
|
ScopeEntryType::Normal => scope.push(name, value),
|
||||||
ScopeEntryType::Constant => scope.push_constant(name, value),
|
ScopeEntryType::Constant => {
|
||||||
|
scope.push_constant(name, value)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let result = if _is_method {
|
let result = if _is_method {
|
||||||
// Method call of script function - map first argument to `this`
|
// Method call of script function - map first argument to `this`
|
||||||
@ -681,6 +684,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub(crate) fn make_method_call(
|
pub(crate) fn make_method_call(
|
||||||
&self,
|
&self,
|
||||||
|
mods: &mut Imports,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
name: &str,
|
name: &str,
|
||||||
@ -720,7 +724,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Map it to name(args) in function-call style
|
// Map it to name(args) in function-call style
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, fn_name, hash, args, false, false, pub_only, None, def_val, level,
|
mods, state, lib, fn_name, hash, args, false, false, pub_only, None, def_val, level,
|
||||||
)
|
)
|
||||||
} else if _fn_name == KEYWORD_FN_PTR_CALL
|
} else if _fn_name == KEYWORD_FN_PTR_CALL
|
||||||
&& call_args.len() > 0
|
&& call_args.len() > 0
|
||||||
@ -747,7 +751,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Map it to name(args) in function-call style
|
// Map it to name(args) in function-call style
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, fn_name, hash, args, is_ref, true, pub_only, None, def_val, level,
|
mods, state, lib, fn_name, hash, args, is_ref, true, pub_only, None, def_val, level,
|
||||||
)
|
)
|
||||||
} else if _fn_name == KEYWORD_FN_PTR_CURRY && obj.is::<FnPtr>() {
|
} else if _fn_name == KEYWORD_FN_PTR_CURRY && obj.is::<FnPtr>() {
|
||||||
// Curry call
|
// Curry call
|
||||||
@ -815,7 +819,8 @@ impl Engine {
|
|||||||
let args = arg_values.as_mut();
|
let args = arg_values.as_mut();
|
||||||
|
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, _fn_name, hash, args, is_ref, true, pub_only, None, def_val, level,
|
mods, state, lib, _fn_name, hash, args, is_ref, true, pub_only, None, def_val,
|
||||||
|
level,
|
||||||
)
|
)
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
@ -1061,7 +1066,7 @@ impl Engine {
|
|||||||
let args = args.as_mut();
|
let args = args.as_mut();
|
||||||
|
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, name, hash, args, is_ref, false, pub_only, capture, def_val, level,
|
mods, state, lib, name, hash, args, is_ref, false, pub_only, capture, def_val, level,
|
||||||
)
|
)
|
||||||
.map(|(v, _)| v)
|
.map(|(v, _)| v)
|
||||||
}
|
}
|
||||||
@ -1173,12 +1178,11 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let args = args.as_mut();
|
let args = args.as_mut();
|
||||||
let fn_def = f.get_fn_def();
|
let fn_def = f.get_shared_fn_def().clone();
|
||||||
|
|
||||||
let new_scope = &mut Default::default();
|
let new_scope = &mut Default::default();
|
||||||
let mods = &mut Default::default();
|
|
||||||
|
|
||||||
self.call_script_fn(new_scope, mods, state, lib, &mut None, fn_def, args, level)
|
self.call_script_fn(new_scope, mods, state, lib, &mut None, &fn_def, args, level)
|
||||||
}
|
}
|
||||||
Some(f) if f.is_plugin_fn() => {
|
Some(f) if f.is_plugin_fn() => {
|
||||||
f.get_plugin_fn().call((self, lib).into(), args.as_mut())
|
f.get_plugin_fn().call((self, lib).into(), args.as_mut())
|
||||||
|
@ -183,6 +183,7 @@ impl FnPtr {
|
|||||||
|
|
||||||
ctx.engine()
|
ctx.engine()
|
||||||
.exec_fn_call(
|
.exec_fn_call(
|
||||||
|
&mut Default::default(),
|
||||||
&mut Default::default(),
|
&mut Default::default(),
|
||||||
ctx.lib,
|
ctx.lib,
|
||||||
fn_name,
|
fn_name,
|
||||||
|
@ -161,11 +161,6 @@ pub mod serde {
|
|||||||
pub use optimize::OptimizationLevel;
|
pub use optimize::OptimizationLevel;
|
||||||
|
|
||||||
// Expose internal data structures.
|
// Expose internal data structures.
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
|
||||||
#[deprecated(note = "this type is volatile and may change")]
|
|
||||||
pub use parse_error::LexError;
|
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[deprecated(note = "this type is volatile and may change")]
|
#[deprecated(note = "this type is volatile and may change")]
|
||||||
pub use token::{get_next_token, parse_string_literal, InputStream, Token, TokenizeState};
|
pub use token::{get_next_token, parse_string_literal, InputStream, Token, TokenizeState};
|
||||||
|
@ -268,20 +268,17 @@ impl Module {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a mutable reference to a modules-qualified variable.
|
/// Get a reference to a modules-qualified variable.
|
||||||
/// Name and Position in `EvalAltResult` are None and must be set afterwards.
|
/// Name and Position in `EvalAltResult` are None and must be set afterwards.
|
||||||
///
|
///
|
||||||
/// The `u64` hash is calculated by the function `crate::calc_native_fn_hash`.
|
/// The `u64` hash is calculated by the function `crate::calc_native_fn_hash`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn get_qualified_var_mut(
|
pub(crate) fn get_qualified_var(&self, hash_var: u64) -> Result<&Dynamic, Box<EvalAltResult>> {
|
||||||
&mut self,
|
|
||||||
hash_var: u64,
|
|
||||||
) -> Result<&mut Dynamic, Box<EvalAltResult>> {
|
|
||||||
if hash_var == 0 {
|
if hash_var == 0 {
|
||||||
Err(EvalAltResult::ErrorVariableNotFound(String::new(), NO_POS).into())
|
Err(EvalAltResult::ErrorVariableNotFound(String::new(), NO_POS).into())
|
||||||
} else {
|
} else {
|
||||||
self.all_variables
|
self.all_variables
|
||||||
.get_mut(&hash_var)
|
.get(&hash_var)
|
||||||
.ok_or_else(|| EvalAltResult::ErrorVariableNotFound(String::new(), NO_POS).into())
|
.ok_or_else(|| EvalAltResult::ErrorVariableNotFound(String::new(), NO_POS).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -387,7 +387,7 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// try { block } catch ( var ) { block }
|
// try { block } catch ( var ) { block }
|
||||||
Stmt::TryCatch(x) if x.0.is_pure() => {
|
Stmt::TryCatch(x, _, _) if x.0.is_pure() => {
|
||||||
// If try block is pure, there will never be any exceptions
|
// If try block is pure, there will never be any exceptions
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
let pos = x.0.position();
|
let pos = x.0.position();
|
||||||
@ -399,14 +399,17 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
|
|||||||
Stmt::Block(statements, pos)
|
Stmt::Block(statements, pos)
|
||||||
}
|
}
|
||||||
// try { block } catch ( var ) { block }
|
// try { block } catch ( var ) { block }
|
||||||
Stmt::TryCatch(x) => {
|
Stmt::TryCatch(x, try_pos, catch_pos) => {
|
||||||
let (try_block, var_name, catch_block, pos) = *x;
|
let (try_block, var_name, catch_block) = *x;
|
||||||
Stmt::TryCatch(Box::new((
|
Stmt::TryCatch(
|
||||||
|
Box::new((
|
||||||
optimize_stmt(try_block, state, false),
|
optimize_stmt(try_block, state, false),
|
||||||
var_name,
|
var_name,
|
||||||
optimize_stmt(catch_block, state, false),
|
optimize_stmt(catch_block, state, false),
|
||||||
pos,
|
)),
|
||||||
)))
|
try_pos,
|
||||||
|
catch_pos,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// {}
|
// {}
|
||||||
Stmt::Expr(Expr::Stmt(x, pos)) if x.is_empty() => {
|
Stmt::Expr(Expr::Stmt(x, pos)) if x.is_empty() => {
|
||||||
|
@ -32,7 +32,7 @@ use crate::{
|
|||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
collections::HashMap,
|
collections::{HashMap, HashSet},
|
||||||
format,
|
format,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
iter::empty,
|
iter::empty,
|
||||||
@ -2376,12 +2376,11 @@ fn parse_try_catch(
|
|||||||
// try { body } catch ( var ) { catch_block }
|
// try { body } catch ( var ) { catch_block }
|
||||||
let catch_body = parse_block(input, state, lib, settings.level_up())?;
|
let catch_body = parse_block(input, state, lib, settings.level_up())?;
|
||||||
|
|
||||||
Ok(Stmt::TryCatch(Box::new((
|
Ok(Stmt::TryCatch(
|
||||||
body,
|
Box::new((body, var_def, catch_body)),
|
||||||
var_def,
|
token_pos,
|
||||||
catch_body,
|
catch_pos,
|
||||||
(token_pos, catch_pos),
|
))
|
||||||
))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a function definition.
|
/// Parse a function definition.
|
||||||
@ -2470,7 +2469,7 @@ fn parse_fn(
|
|||||||
let params: StaticVec<_> = params.into_iter().map(|(p, _)| p).collect();
|
let params: StaticVec<_> = params.into_iter().map(|(p, _)| p).collect();
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
let externals = state
|
let externals: HashSet<_> = state
|
||||||
.externals
|
.externals
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(name, _)| name)
|
.map(|(name, _)| name)
|
||||||
@ -2483,7 +2482,11 @@ fn parse_fn(
|
|||||||
access,
|
access,
|
||||||
params,
|
params,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
externals,
|
externals: if externals.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Box::new(externals))
|
||||||
|
},
|
||||||
body,
|
body,
|
||||||
lib: None,
|
lib: None,
|
||||||
})
|
})
|
||||||
|
29
src/scope.rs
29
src/scope.rs
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::dynamic::{Dynamic, Variant};
|
use crate::dynamic::{Dynamic, Variant};
|
||||||
|
|
||||||
use crate::stdlib::{borrow::Cow, iter, string::String, vec::Vec};
|
use crate::stdlib::{borrow::Cow, boxed::Box, iter, string::String, vec::Vec};
|
||||||
|
|
||||||
/// Type of an entry in the Scope.
|
/// Type of an entry in the Scope.
|
||||||
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
|
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
|
||||||
@ -70,8 +70,8 @@ pub struct Scope<'a> {
|
|||||||
values: Vec<Dynamic>,
|
values: Vec<Dynamic>,
|
||||||
/// Type of the entry.
|
/// Type of the entry.
|
||||||
types: Vec<EntryType>,
|
types: Vec<EntryType>,
|
||||||
/// (Name, alias) of the entry.
|
/// (Name, alias) of the entry. The alias is Boxed because it occurs rarely.
|
||||||
names: Vec<(Cow<'a, str>, Option<String>)>,
|
names: Vec<(Cow<'a, str>, Option<Box<String>>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Scope<'a> {
|
impl<'a> Scope<'a> {
|
||||||
@ -91,7 +91,6 @@ impl<'a> Scope<'a> {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Empty the Scope.
|
/// Empty the Scope.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -118,7 +117,6 @@ impl<'a> Scope<'a> {
|
|||||||
self.values.clear();
|
self.values.clear();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the number of entries inside the Scope.
|
/// Get the number of entries inside the Scope.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -136,7 +134,6 @@ impl<'a> Scope<'a> {
|
|||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.values.len()
|
self.values.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is the Scope empty?
|
/// Is the Scope empty?
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -154,7 +151,6 @@ impl<'a> Scope<'a> {
|
|||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.values.len() == 0
|
self.values.len() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add (push) a new entry to the Scope.
|
/// Add (push) a new entry to the Scope.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -175,7 +171,6 @@ impl<'a> Scope<'a> {
|
|||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.push_dynamic_value(name, EntryType::Normal, Dynamic::from(value))
|
self.push_dynamic_value(name, EntryType::Normal, Dynamic::from(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add (push) a new `Dynamic` entry to the Scope.
|
/// Add (push) a new `Dynamic` entry to the Scope.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -192,7 +187,6 @@ impl<'a> Scope<'a> {
|
|||||||
pub fn push_dynamic(&mut self, name: impl Into<Cow<'a, str>>, value: Dynamic) -> &mut Self {
|
pub fn push_dynamic(&mut self, name: impl Into<Cow<'a, str>>, value: Dynamic) -> &mut Self {
|
||||||
self.push_dynamic_value(name, EntryType::Normal, value)
|
self.push_dynamic_value(name, EntryType::Normal, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add (push) a new constant to the Scope.
|
/// Add (push) a new constant to the Scope.
|
||||||
///
|
///
|
||||||
/// Constants are immutable and cannot be assigned to. Their values never change.
|
/// Constants are immutable and cannot be assigned to. Their values never change.
|
||||||
@ -219,7 +213,6 @@ impl<'a> Scope<'a> {
|
|||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.push_dynamic_value(name, EntryType::Constant, Dynamic::from(value))
|
self.push_dynamic_value(name, EntryType::Constant, Dynamic::from(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add (push) a new constant with a `Dynamic` value to the Scope.
|
/// Add (push) a new constant with a `Dynamic` value to the Scope.
|
||||||
///
|
///
|
||||||
/// Constants are immutable and cannot be assigned to. Their values never change.
|
/// Constants are immutable and cannot be assigned to. Their values never change.
|
||||||
@ -247,7 +240,6 @@ impl<'a> Scope<'a> {
|
|||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.push_dynamic_value(name, EntryType::Constant, value)
|
self.push_dynamic_value(name, EntryType::Constant, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add (push) a new entry with a `Dynamic` value to the Scope.
|
/// Add (push) a new entry with a `Dynamic` value to the Scope.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn push_dynamic_value(
|
pub(crate) fn push_dynamic_value(
|
||||||
@ -261,7 +253,6 @@ impl<'a> Scope<'a> {
|
|||||||
self.values.push(value.into());
|
self.values.push(value.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Truncate (rewind) the Scope to a previous size.
|
/// Truncate (rewind) the Scope to a previous size.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -295,7 +286,6 @@ impl<'a> Scope<'a> {
|
|||||||
self.values.truncate(size);
|
self.values.truncate(size);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does the scope contain the entry?
|
/// Does the scope contain the entry?
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -316,7 +306,6 @@ impl<'a> Scope<'a> {
|
|||||||
.rev() // Always search a Scope in reverse order
|
.rev() // Always search a Scope in reverse order
|
||||||
.any(|(key, _)| name == key.as_ref())
|
.any(|(key, _)| name == key.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find an entry in the Scope, starting from the last.
|
/// Find an entry in the Scope, starting from the last.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn get_index(&self, name: &str) -> Option<(usize, EntryType)> {
|
pub(crate) fn get_index(&self, name: &str) -> Option<(usize, EntryType)> {
|
||||||
@ -332,7 +321,6 @@ impl<'a> Scope<'a> {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the value of an entry in the Scope, starting from the last.
|
/// Get the value of an entry in the Scope, starting from the last.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -354,7 +342,6 @@ impl<'a> Scope<'a> {
|
|||||||
.find(|(_, (key, _))| name == key.as_ref())
|
.find(|(_, (key, _))| name == key.as_ref())
|
||||||
.and_then(|(index, _)| self.values[index].flatten_clone().try_cast())
|
.and_then(|(index, _)| self.values[index].flatten_clone().try_cast())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the value of the named entry.
|
/// Update the value of the named entry.
|
||||||
/// Search starts backwards from the last, and only the first entry matching the specified name is updated.
|
/// Search starts backwards from the last, and only the first entry matching the specified name is updated.
|
||||||
/// If no entry matching the specified name is found, a new one is added.
|
/// If no entry matching the specified name is found, a new one is added.
|
||||||
@ -389,7 +376,6 @@ impl<'a> Scope<'a> {
|
|||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a mutable reference to an entry in the Scope.
|
/// Get a mutable reference to an entry in the Scope.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn get_mut(&mut self, index: usize) -> (&mut Dynamic, EntryType) {
|
pub(crate) fn get_mut(&mut self, index: usize) -> (&mut Dynamic, EntryType) {
|
||||||
@ -398,16 +384,14 @@ impl<'a> Scope<'a> {
|
|||||||
self.types[index],
|
self.types[index],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the access type of an entry in the Scope.
|
/// Update the access type of an entry in the Scope.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn set_entry_alias(&mut self, index: usize, alias: String) -> &mut Self {
|
pub(crate) fn set_entry_alias(&mut self, index: usize, alias: String) -> &mut Self {
|
||||||
let entry = self.names.get_mut(index).expect("invalid index in Scope");
|
let entry = self.names.get_mut(index).expect("invalid index in Scope");
|
||||||
entry.1 = Some(alias);
|
entry.1 = Some(Box::new(alias));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clone the Scope, keeping only the last instances of each variable name.
|
/// Clone the Scope, keeping only the last instances of each variable name.
|
||||||
/// Shadowed variables are omitted in the copy.
|
/// Shadowed variables are omitted in the copy.
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -428,7 +412,6 @@ impl<'a> Scope<'a> {
|
|||||||
|
|
||||||
entries
|
entries
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an iterator to entries in the Scope.
|
/// Get an iterator to entries in the Scope.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn into_iter(
|
pub(crate) fn into_iter(
|
||||||
@ -437,9 +420,8 @@ impl<'a> Scope<'a> {
|
|||||||
self.names
|
self.names
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(self.types.into_iter().zip(self.values.into_iter()))
|
.zip(self.types.into_iter().zip(self.values.into_iter()))
|
||||||
.map(|((name, alias), (typ, value))| (name, typ, value, alias))
|
.map(|((name, alias), (typ, value))| (name, typ, value, alias.map(|v| *v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an iterator to entries in the Scope.
|
/// Get an iterator to entries in the Scope.
|
||||||
/// Shared values are flatten-cloned.
|
/// Shared values are flatten-cloned.
|
||||||
///
|
///
|
||||||
@ -470,7 +452,6 @@ impl<'a> Scope<'a> {
|
|||||||
self.iter_raw()
|
self.iter_raw()
|
||||||
.map(|(name, constant, value)| (name, constant, value.flatten_clone()))
|
.map(|(name, constant, value)| (name, constant, value.flatten_clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an iterator to entries in the Scope.
|
/// Get an iterator to entries in the Scope.
|
||||||
/// Shared values are not expanded.
|
/// Shared values are not expanded.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -85,9 +85,14 @@ impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_, '_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Definition of a custom syntax definition.
|
||||||
pub struct CustomSyntax {
|
pub struct CustomSyntax {
|
||||||
|
/// A parsing function to return the next keyword in a custom syntax based on the
|
||||||
|
/// keywords parsed so far.
|
||||||
pub parse: Box<FnCustomSyntaxParse>,
|
pub parse: Box<FnCustomSyntaxParse>,
|
||||||
|
/// Custom syntax implementation function.
|
||||||
pub func: Shared<FnCustomSyntaxEval>,
|
pub func: Shared<FnCustomSyntaxEval>,
|
||||||
|
/// Delta number of variables in the scope.
|
||||||
pub scope_delta: isize,
|
pub scope_delta: isize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,10 @@ fn test_call_fn() -> Result<(), Box<EvalAltResult>> {
|
|||||||
fn hello() {
|
fn hello() {
|
||||||
41 + foo
|
41 + foo
|
||||||
}
|
}
|
||||||
|
fn define_var() {
|
||||||
|
let bar = 21;
|
||||||
|
bar * 2
|
||||||
|
}
|
||||||
",
|
",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -50,6 +54,11 @@ fn test_call_fn() -> Result<(), Box<EvalAltResult>> {
|
|||||||
let r: INT = engine.call_fn(&mut scope, &ast, "hello", ())?;
|
let r: INT = engine.call_fn(&mut scope, &ast, "hello", ())?;
|
||||||
assert_eq!(r, 42);
|
assert_eq!(r, 42);
|
||||||
|
|
||||||
|
let r: INT = engine.call_fn(&mut scope, &ast, "define_var", ())?;
|
||||||
|
assert_eq!(r, 42);
|
||||||
|
|
||||||
|
assert!(!scope.contains("bar"));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
scope
|
scope
|
||||||
.get_value::<INT>("foo")
|
.get_value::<INT>("foo")
|
||||||
|
Loading…
Reference in New Issue
Block a user