Rename sub-scope/SubScope to module.
This commit is contained in:
parent
64036f69ca
commit
143861747d
@ -28,7 +28,7 @@ no_float = [] # no floating-point
|
|||||||
no_function = [] # no script-defined functions
|
no_function = [] # no script-defined functions
|
||||||
no_object = [] # no custom objects
|
no_object = [] # no custom objects
|
||||||
no_optimize = [] # no script optimizer
|
no_optimize = [] # no script optimizer
|
||||||
no_import = [] # no modules
|
no_module = [] # no modules
|
||||||
only_i32 = [] # set INT=i32 (useful for 32-bit systems)
|
only_i32 = [] # set INT=i32 (useful for 32-bit systems)
|
||||||
only_i64 = [] # set INT=i64 (default) and disable support for all other integer types
|
only_i64 = [] # set INT=i64 (default) and disable support for all other integer types
|
||||||
sync = [] # restrict to only types that implement Send + Sync
|
sync = [] # restrict to only types that implement Send + Sync
|
||||||
|
@ -70,7 +70,7 @@ Optional features
|
|||||||
| `no_object` | Disable support for custom types and objects. |
|
| `no_object` | Disable support for custom types and objects. |
|
||||||
| `no_float` | Disable floating-point numbers and math if not needed. |
|
| `no_float` | Disable floating-point numbers and math if not needed. |
|
||||||
| `no_optimize` | Disable the script optimizer. |
|
| `no_optimize` | Disable the script optimizer. |
|
||||||
| `no_import` | Disable modules. |
|
| `no_module` | Disable modules. |
|
||||||
| `only_i32` | Set the system integer type to `i32` and disable all other integer types. `INT` is set to `i32`. |
|
| `only_i32` | Set the system integer type to `i32` and disable all other integer types. `INT` is set to `i32`. |
|
||||||
| `only_i64` | Set the system integer type to `i64` and disable all other integer types. `INT` is set to `i64`. |
|
| `only_i64` | Set the system integer type to `i64` and disable all other integer types. `INT` is set to `i64`. |
|
||||||
| `no_std` | Build for `no-std`. Notice that additional dependencies will be pulled in to replace `std` features. |
|
| `no_std` | Build for `no-std`. Notice that additional dependencies will be pulled in to replace `std` features. |
|
||||||
@ -86,7 +86,7 @@ Excluding unneeded functionalities can result in smaller, faster builds as well
|
|||||||
[`no_function`]: #optional-features
|
[`no_function`]: #optional-features
|
||||||
[`no_object`]: #optional-features
|
[`no_object`]: #optional-features
|
||||||
[`no_optimize`]: #optional-features
|
[`no_optimize`]: #optional-features
|
||||||
[`no_import`]: #optional-features
|
[`no_module`]: #optional-features
|
||||||
[`only_i32`]: #optional-features
|
[`only_i32`]: #optional-features
|
||||||
[`only_i64`]: #optional-features
|
[`only_i64`]: #optional-features
|
||||||
[`no_std`]: #optional-features
|
[`no_std`]: #optional-features
|
||||||
|
22
src/any.rs
22
src/any.rs
@ -1,6 +1,6 @@
|
|||||||
//! Helper module which defines the `Any` trait to to allow dynamic value handling.
|
//! Helper module which defines the `Any` trait to to allow dynamic value handling.
|
||||||
|
|
||||||
use crate::engine::{Array, Map, SubScope};
|
use crate::engine::{Array, Map, Module};
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
@ -135,7 +135,7 @@ pub enum Union {
|
|||||||
Float(FLOAT),
|
Float(FLOAT),
|
||||||
Array(Box<Array>),
|
Array(Box<Array>),
|
||||||
Map(Box<Map>),
|
Map(Box<Map>),
|
||||||
SubScope(Box<SubScope>),
|
Module(Box<Module>),
|
||||||
Variant(Box<Box<dyn Variant>>),
|
Variant(Box<Box<dyn Variant>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +166,7 @@ impl Dynamic {
|
|||||||
Union::Float(_) => TypeId::of::<FLOAT>(),
|
Union::Float(_) => TypeId::of::<FLOAT>(),
|
||||||
Union::Array(_) => TypeId::of::<Array>(),
|
Union::Array(_) => TypeId::of::<Array>(),
|
||||||
Union::Map(_) => TypeId::of::<Map>(),
|
Union::Map(_) => TypeId::of::<Map>(),
|
||||||
Union::SubScope(_) => TypeId::of::<SubScope>(),
|
Union::Module(_) => TypeId::of::<Module>(),
|
||||||
Union::Variant(value) => (***value).type_id(),
|
Union::Variant(value) => (***value).type_id(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,7 +183,7 @@ impl Dynamic {
|
|||||||
Union::Float(_) => type_name::<FLOAT>(),
|
Union::Float(_) => type_name::<FLOAT>(),
|
||||||
Union::Array(_) => "array",
|
Union::Array(_) => "array",
|
||||||
Union::Map(_) => "map",
|
Union::Map(_) => "map",
|
||||||
Union::SubScope(_) => "sub-scope",
|
Union::Module(_) => "sub-scope",
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
Union::Variant(value) if value.is::<Instant>() => "timestamp",
|
Union::Variant(value) if value.is::<Instant>() => "timestamp",
|
||||||
@ -204,7 +204,7 @@ impl fmt::Display for Dynamic {
|
|||||||
Union::Float(value) => write!(f, "{}", value),
|
Union::Float(value) => write!(f, "{}", value),
|
||||||
Union::Array(value) => write!(f, "{:?}", value),
|
Union::Array(value) => write!(f, "{:?}", value),
|
||||||
Union::Map(value) => write!(f, "#{:?}", value),
|
Union::Map(value) => write!(f, "#{:?}", value),
|
||||||
Union::SubScope(value) => write!(f, "#{:?}", value),
|
Union::Module(value) => write!(f, "#{:?}", value),
|
||||||
Union::Variant(_) => write!(f, "?"),
|
Union::Variant(_) => write!(f, "?"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,7 +222,7 @@ impl fmt::Debug for Dynamic {
|
|||||||
Union::Float(value) => write!(f, "{:?}", value),
|
Union::Float(value) => write!(f, "{:?}", value),
|
||||||
Union::Array(value) => write!(f, "{:?}", value),
|
Union::Array(value) => write!(f, "{:?}", value),
|
||||||
Union::Map(value) => write!(f, "#{:?}", value),
|
Union::Map(value) => write!(f, "#{:?}", value),
|
||||||
Union::SubScope(value) => write!(f, "#{:?}", value),
|
Union::Module(value) => write!(f, "#{:?}", value),
|
||||||
Union::Variant(_) => write!(f, "<dynamic>"),
|
Union::Variant(_) => write!(f, "<dynamic>"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,7 +240,7 @@ impl Clone for Dynamic {
|
|||||||
Union::Float(value) => Self(Union::Float(value)),
|
Union::Float(value) => Self(Union::Float(value)),
|
||||||
Union::Array(ref value) => Self(Union::Array(value.clone())),
|
Union::Array(ref value) => Self(Union::Array(value.clone())),
|
||||||
Union::Map(ref value) => Self(Union::Map(value.clone())),
|
Union::Map(ref value) => Self(Union::Map(value.clone())),
|
||||||
Union::SubScope(ref value) => Self(Union::SubScope(value.clone())),
|
Union::Module(ref value) => Self(Union::Module(value.clone())),
|
||||||
Union::Variant(ref value) => (***value).clone_into_dynamic(),
|
Union::Variant(ref value) => (***value).clone_into_dynamic(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,7 +369,7 @@ impl Dynamic {
|
|||||||
Union::Float(ref value) => (value as &dyn Any).downcast_ref::<T>().cloned(),
|
Union::Float(ref value) => (value as &dyn Any).downcast_ref::<T>().cloned(),
|
||||||
Union::Array(value) => cast_box::<_, T>(value).ok(),
|
Union::Array(value) => cast_box::<_, T>(value).ok(),
|
||||||
Union::Map(value) => cast_box::<_, T>(value).ok(),
|
Union::Map(value) => cast_box::<_, T>(value).ok(),
|
||||||
Union::SubScope(value) => cast_box::<_, T>(value).ok(),
|
Union::Module(value) => cast_box::<_, T>(value).ok(),
|
||||||
Union::Variant(value) => value.as_any().downcast_ref::<T>().cloned(),
|
Union::Variant(value) => value.as_any().downcast_ref::<T>().cloned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -407,7 +407,7 @@ impl Dynamic {
|
|||||||
Union::Float(ref value) => (value as &dyn Any).downcast_ref::<T>().unwrap().clone(),
|
Union::Float(ref value) => (value as &dyn Any).downcast_ref::<T>().unwrap().clone(),
|
||||||
Union::Array(value) => cast_box::<_, T>(value).unwrap(),
|
Union::Array(value) => cast_box::<_, T>(value).unwrap(),
|
||||||
Union::Map(value) => cast_box::<_, T>(value).unwrap(),
|
Union::Map(value) => cast_box::<_, T>(value).unwrap(),
|
||||||
Union::SubScope(value) => cast_box::<_, T>(value).unwrap(),
|
Union::Module(value) => cast_box::<_, T>(value).unwrap(),
|
||||||
Union::Variant(value) => value.as_any().downcast_ref::<T>().unwrap().clone(),
|
Union::Variant(value) => value.as_any().downcast_ref::<T>().unwrap().clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -430,7 +430,7 @@ impl Dynamic {
|
|||||||
Union::Float(value) => (value as &dyn Any).downcast_ref::<T>(),
|
Union::Float(value) => (value as &dyn Any).downcast_ref::<T>(),
|
||||||
Union::Array(value) => (value.as_ref() as &dyn Any).downcast_ref::<T>(),
|
Union::Array(value) => (value.as_ref() as &dyn Any).downcast_ref::<T>(),
|
||||||
Union::Map(value) => (value.as_ref() as &dyn Any).downcast_ref::<T>(),
|
Union::Map(value) => (value.as_ref() as &dyn Any).downcast_ref::<T>(),
|
||||||
Union::SubScope(value) => (value.as_ref() as &dyn Any).downcast_ref::<T>(),
|
Union::Module(value) => (value.as_ref() as &dyn Any).downcast_ref::<T>(),
|
||||||
Union::Variant(value) => value.as_ref().as_ref().as_any().downcast_ref::<T>(),
|
Union::Variant(value) => value.as_ref().as_ref().as_any().downcast_ref::<T>(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -453,7 +453,7 @@ impl Dynamic {
|
|||||||
Union::Float(value) => (value as &mut dyn Any).downcast_mut::<T>(),
|
Union::Float(value) => (value as &mut dyn Any).downcast_mut::<T>(),
|
||||||
Union::Array(value) => (value.as_mut() as &mut dyn Any).downcast_mut::<T>(),
|
Union::Array(value) => (value.as_mut() as &mut dyn Any).downcast_mut::<T>(),
|
||||||
Union::Map(value) => (value.as_mut() as &mut dyn Any).downcast_mut::<T>(),
|
Union::Map(value) => (value.as_mut() as &mut dyn Any).downcast_mut::<T>(),
|
||||||
Union::SubScope(value) => (value.as_mut() as &mut dyn Any).downcast_mut::<T>(),
|
Union::Module(value) => (value.as_mut() as &mut dyn Any).downcast_mut::<T>(),
|
||||||
Union::Variant(value) => value.as_mut().as_mut_any().downcast_mut::<T>(),
|
Union::Variant(value) => value.as_mut().as_mut_any().downcast_mut::<T>(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
170
src/engine.rs
170
src/engine.rs
@ -5,7 +5,7 @@ use crate::calc_fn_hash;
|
|||||||
use crate::error::ParseErrorType;
|
use crate::error::ParseErrorType;
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::packages::{CorePackage, Package, PackageLibrary, StandardPackage};
|
use crate::packages::{CorePackage, Package, PackageLibrary, StandardPackage};
|
||||||
use crate::parser::{Expr, FnDef, ReturnType, Stmt};
|
use crate::parser::{Expr, FnDef, ModuleRef, ReturnType, Stmt};
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
@ -42,27 +42,27 @@ pub type Array = Vec<Dynamic>;
|
|||||||
/// Not available under the `no_object` feature.
|
/// Not available under the `no_object` feature.
|
||||||
pub type Map = HashMap<String, Dynamic>;
|
pub type Map = HashMap<String, Dynamic>;
|
||||||
|
|
||||||
/// A sub-scope - basically an imported module namespace.
|
/// An imported module.
|
||||||
///
|
///
|
||||||
/// Not available under the `no_import` feature.
|
/// Not available under the `no_module` feature.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SubScope(HashMap<String, Dynamic>);
|
pub struct Module(HashMap<String, Dynamic>);
|
||||||
|
|
||||||
impl SubScope {
|
impl Module {
|
||||||
/// Create a new sub-scope.
|
/// Create a new module.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self(HashMap::new())
|
Self(HashMap::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for SubScope {
|
impl Deref for Module {
|
||||||
type Target = HashMap<String, Dynamic>;
|
type Target = HashMap<String, Dynamic>;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for SubScope {
|
impl DerefMut for Module {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
&mut self.0
|
&mut self.0
|
||||||
}
|
}
|
||||||
@ -500,12 +500,51 @@ fn default_print(s: &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Search for a variable within the scope
|
/// Search for a variable within the scope
|
||||||
fn search_scope_variables<'a>(
|
fn search_scope<'a>(
|
||||||
scope: &'a mut Scope,
|
scope: &'a mut Scope,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
modules: &Option<Box<StaticVec<(String, Position)>>>,
|
||||||
index: Option<NonZeroUsize>,
|
index: Option<NonZeroUsize>,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> Result<(&'a mut Dynamic, ScopeEntryType), Box<EvalAltResult>> {
|
) -> Result<(&'a mut Dynamic, ScopeEntryType), Box<EvalAltResult>> {
|
||||||
|
if let Some(modules) = modules {
|
||||||
|
let (id, root_pos) = modules.get(0); // First module
|
||||||
|
|
||||||
|
let mut module = if let Some(index) = index {
|
||||||
|
scope
|
||||||
|
.get_mut(scope.len() - index.get())
|
||||||
|
.0
|
||||||
|
.downcast_mut::<Module>()
|
||||||
|
.unwrap()
|
||||||
|
} else {
|
||||||
|
scope
|
||||||
|
.find_module(id)
|
||||||
|
.ok_or_else(|| Box::new(EvalAltResult::ErrorModuleNotFound(id.into(), *root_pos)))?
|
||||||
|
};
|
||||||
|
|
||||||
|
for x in 1..modules.len() {
|
||||||
|
let (id, id_pos) = modules.get(x);
|
||||||
|
|
||||||
|
module = module
|
||||||
|
.get_mut(id)
|
||||||
|
.and_then(|v| v.downcast_mut::<Module>())
|
||||||
|
.ok_or_else(|| Box::new(EvalAltResult::ErrorModuleNotFound(id.into(), *id_pos)))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = module
|
||||||
|
.get_mut(name)
|
||||||
|
.map(|v| (v, ScopeEntryType::Constant))
|
||||||
|
.ok_or_else(|| Box::new(EvalAltResult::ErrorVariableNotFound(name.into(), pos)))?;
|
||||||
|
|
||||||
|
if result.0.is::<Module>() {
|
||||||
|
Err(Box::new(EvalAltResult::ErrorVariableNotFound(
|
||||||
|
name.into(),
|
||||||
|
pos,
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
let index = if let Some(index) = index {
|
let index = if let Some(index) = index {
|
||||||
scope.len() - index.get()
|
scope.len() - index.get()
|
||||||
} else {
|
} else {
|
||||||
@ -516,51 +555,6 @@ fn search_scope_variables<'a>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(scope.get_mut(index))
|
Ok(scope.get_mut(index))
|
||||||
}
|
|
||||||
|
|
||||||
/// Search for a sub-scope within the scope
|
|
||||||
fn search_scope_modules<'a>(
|
|
||||||
scope: &'a mut Scope,
|
|
||||||
name: &str,
|
|
||||||
modules: &Box<StaticVec<(String, Position)>>,
|
|
||||||
index: Option<NonZeroUsize>,
|
|
||||||
pos: Position,
|
|
||||||
) -> Result<(&'a mut Dynamic, ScopeEntryType), Box<EvalAltResult>> {
|
|
||||||
let (id, root_pos) = modules.get(0); // First module
|
|
||||||
|
|
||||||
let mut sub_scope = if let Some(index) = index {
|
|
||||||
scope
|
|
||||||
.get_mut(scope.len() - index.get())
|
|
||||||
.0
|
|
||||||
.downcast_mut::<SubScope>()
|
|
||||||
.unwrap()
|
|
||||||
} else {
|
|
||||||
scope
|
|
||||||
.find_sub_scope(id)
|
|
||||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorModuleNotFound(id.into(), *root_pos)))?
|
|
||||||
};
|
|
||||||
|
|
||||||
for x in 1..modules.len() {
|
|
||||||
let (id, id_pos) = modules.get(x);
|
|
||||||
|
|
||||||
sub_scope = sub_scope
|
|
||||||
.get_mut(id)
|
|
||||||
.and_then(|v| v.downcast_mut::<SubScope>())
|
|
||||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorModuleNotFound(id.into(), *id_pos)))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = sub_scope
|
|
||||||
.get_mut(name)
|
|
||||||
.map(|v| (v, ScopeEntryType::Constant))
|
|
||||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorVariableNotFound(name.into(), pos)))?;
|
|
||||||
|
|
||||||
if result.0.is::<SubScope>() {
|
|
||||||
Err(Box::new(EvalAltResult::ErrorVariableNotFound(
|
|
||||||
name.into(),
|
|
||||||
pos,
|
|
||||||
)))
|
|
||||||
} else {
|
|
||||||
Ok(result)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -620,11 +614,13 @@ 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
|
||||||
|
// TODO - handle moduled function call
|
||||||
pub(crate) fn call_fn_raw(
|
pub(crate) fn call_fn_raw(
|
||||||
&self,
|
&self,
|
||||||
scope: Option<&mut Scope>,
|
scope: Option<&mut Scope>,
|
||||||
fn_lib: &FunctionsLib,
|
fn_lib: &FunctionsLib,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
|
modules: &ModuleRef,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
def_val: Option<&Dynamic>,
|
def_val: Option<&Dynamic>,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
@ -794,6 +790,7 @@ impl Engine {
|
|||||||
&self,
|
&self,
|
||||||
fn_lib: &FunctionsLib,
|
fn_lib: &FunctionsLib,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
|
modules: &ModuleRef,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
def_val: Option<&Dynamic>,
|
def_val: Option<&Dynamic>,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
@ -801,12 +798,20 @@ impl Engine {
|
|||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
match fn_name {
|
match fn_name {
|
||||||
// type_of
|
// type_of
|
||||||
KEYWORD_TYPE_OF if args.len() == 1 && !self.has_override(fn_lib, KEYWORD_TYPE_OF) => {
|
KEYWORD_TYPE_OF
|
||||||
|
if modules.is_none()
|
||||||
|
&& args.len() == 1
|
||||||
|
&& !self.has_override(fn_lib, KEYWORD_TYPE_OF) =>
|
||||||
|
{
|
||||||
Ok(self.map_type_name(args[0].type_name()).to_string().into())
|
Ok(self.map_type_name(args[0].type_name()).to_string().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// eval - reaching this point it must be a method-style call
|
// eval - reaching this point it must be a method-style call
|
||||||
KEYWORD_EVAL if args.len() == 1 && !self.has_override(fn_lib, KEYWORD_EVAL) => {
|
KEYWORD_EVAL
|
||||||
|
if modules.is_none()
|
||||||
|
&& args.len() == 1
|
||||||
|
&& !self.has_override(fn_lib, KEYWORD_EVAL) =>
|
||||||
|
{
|
||||||
Err(Box::new(EvalAltResult::ErrorRuntime(
|
Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||||
"'eval' should not be called in method style. Try eval(...);".into(),
|
"'eval' should not be called in method style. Try eval(...);".into(),
|
||||||
pos,
|
pos,
|
||||||
@ -814,7 +819,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Normal method call
|
// Normal method call
|
||||||
_ => self.call_fn_raw(None, fn_lib, fn_name, args, def_val, pos, level),
|
_ => self.call_fn_raw(None, fn_lib, fn_name, modules, args, def_val, pos, level),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -915,7 +920,7 @@ impl Engine {
|
|||||||
let def_val = def_val.as_deref();
|
let def_val = def_val.as_deref();
|
||||||
// A function call is assumed to have side effects, so the value is changed
|
// A function call is assumed to have side effects, so the value is changed
|
||||||
// TODO - Remove assumption of side effects by checking whether the first parameter is &mut
|
// TODO - Remove assumption of side effects by checking whether the first parameter is &mut
|
||||||
self.exec_fn_call(fn_lib, fn_name, &mut args, def_val, *pos, 0).map(|v| (v, true))
|
self.exec_fn_call(fn_lib, fn_name, &None, &mut args, def_val, *pos, 0).map(|v| (v, true))
|
||||||
}
|
}
|
||||||
// xxx.module::fn_name(...) - syntax error
|
// xxx.module::fn_name(...) - syntax error
|
||||||
Expr::FnCall(_,_,_,_,_) => unreachable!(),
|
Expr::FnCall(_,_,_,_,_) => unreachable!(),
|
||||||
@ -936,13 +941,13 @@ impl Engine {
|
|||||||
Expr::Property(id, pos) if new_val.is_some() => {
|
Expr::Property(id, pos) if new_val.is_some() => {
|
||||||
let fn_name = make_setter(id);
|
let fn_name = make_setter(id);
|
||||||
let mut args = [obj, new_val.as_mut().unwrap()];
|
let mut args = [obj, new_val.as_mut().unwrap()];
|
||||||
self.exec_fn_call(fn_lib, &fn_name, &mut args, None, *pos, 0).map(|v| (v, true))
|
self.exec_fn_call(fn_lib, &fn_name, &None, &mut args, None, *pos, 0).map(|v| (v, true))
|
||||||
}
|
}
|
||||||
// xxx.id
|
// xxx.id
|
||||||
Expr::Property(id, pos) => {
|
Expr::Property(id, pos) => {
|
||||||
let fn_name = make_getter(id);
|
let fn_name = make_getter(id);
|
||||||
let mut args = [obj];
|
let mut args = [obj];
|
||||||
self.exec_fn_call(fn_lib, &fn_name, &mut args, None, *pos, 0).map(|v| (v, false))
|
self.exec_fn_call(fn_lib, &fn_name, &None, &mut args, None, *pos, 0).map(|v| (v, false))
|
||||||
}
|
}
|
||||||
// {xxx:map}.idx_lhs[idx_expr]
|
// {xxx:map}.idx_lhs[idx_expr]
|
||||||
Expr::Index(dot_lhs, dot_rhs, pos) |
|
Expr::Index(dot_lhs, dot_rhs, pos) |
|
||||||
@ -972,7 +977,7 @@ impl Engine {
|
|||||||
|
|
||||||
let indexed_val = &mut (if let Expr::Property(id, pos) = dot_lhs.as_ref() {
|
let indexed_val = &mut (if let Expr::Property(id, pos) = dot_lhs.as_ref() {
|
||||||
let fn_name = make_getter(id);
|
let fn_name = make_getter(id);
|
||||||
self.exec_fn_call(fn_lib, &fn_name, &mut args[..1], None, *pos, 0)?
|
self.exec_fn_call(fn_lib, &fn_name, &None, &mut args[..1], None, *pos, 0)?
|
||||||
} else {
|
} else {
|
||||||
// Syntax error
|
// Syntax error
|
||||||
return Err(Box::new(EvalAltResult::ErrorDotExpr(
|
return Err(Box::new(EvalAltResult::ErrorDotExpr(
|
||||||
@ -990,7 +995,7 @@ impl Engine {
|
|||||||
let fn_name = make_setter(id);
|
let fn_name = make_setter(id);
|
||||||
// Re-use args because the first &mut parameter will not be consumed
|
// Re-use args because the first &mut parameter will not be consumed
|
||||||
args[1] = indexed_val;
|
args[1] = indexed_val;
|
||||||
self.exec_fn_call(fn_lib, &fn_name, &mut args, None, *pos, 0).or_else(|err| match *err {
|
self.exec_fn_call(fn_lib, &fn_name, &None, &mut args, None, *pos, 0).or_else(|err| match *err {
|
||||||
// If there is no setter, no need to feed it back because the property is read-only
|
// If there is no setter, no need to feed it back because the property is read-only
|
||||||
EvalAltResult::ErrorDotExpr(_,_) => Ok(Default::default()),
|
EvalAltResult::ErrorDotExpr(_,_) => Ok(Default::default()),
|
||||||
err => Err(Box::new(err))
|
err => Err(Box::new(err))
|
||||||
@ -1030,16 +1035,11 @@ impl Engine {
|
|||||||
// id.??? or id[???]
|
// id.??? or id[???]
|
||||||
Expr::Variable(id, modules, index, pos) => {
|
Expr::Variable(id, modules, index, pos) => {
|
||||||
let index = if state.always_search { None } else { *index };
|
let index = if state.always_search { None } else { *index };
|
||||||
|
let (target, typ) = search_scope(scope, id, modules, index, *pos)?;
|
||||||
let (target, typ) = if let Some(modules) = modules {
|
|
||||||
search_scope_modules(scope, id, modules, index, *pos)?
|
|
||||||
} else {
|
|
||||||
search_scope_variables(scope, id, index, *pos)?
|
|
||||||
};
|
|
||||||
|
|
||||||
// Constants cannot be modified
|
// Constants cannot be modified
|
||||||
match typ {
|
match typ {
|
||||||
ScopeEntryType::SubScope => unreachable!(),
|
ScopeEntryType::Module => unreachable!(),
|
||||||
ScopeEntryType::Constant if new_val.is_some() => {
|
ScopeEntryType::Constant if new_val.is_some() => {
|
||||||
return Err(Box::new(EvalAltResult::ErrorAssignmentToConstant(
|
return Err(Box::new(EvalAltResult::ErrorAssignmentToConstant(
|
||||||
id.to_string(),
|
id.to_string(),
|
||||||
@ -1223,9 +1223,10 @@ impl Engine {
|
|||||||
for value in rhs_value.iter_mut() {
|
for value in rhs_value.iter_mut() {
|
||||||
let args = &mut [&mut lhs_value, value];
|
let args = &mut [&mut lhs_value, value];
|
||||||
let def_value = Some(&def_value);
|
let def_value = Some(&def_value);
|
||||||
|
let pos = rhs.position();
|
||||||
|
|
||||||
if self
|
if self
|
||||||
.call_fn_raw(None, fn_lib, "==", args, def_value, rhs.position(), level)?
|
.call_fn_raw(None, fn_lib, "==", &None, args, def_value, pos, level)?
|
||||||
.as_bool()
|
.as_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
@ -1268,13 +1269,7 @@ impl Engine {
|
|||||||
Expr::CharConstant(c, _) => Ok((*c).into()),
|
Expr::CharConstant(c, _) => Ok((*c).into()),
|
||||||
Expr::Variable(id, modules, index, pos) => {
|
Expr::Variable(id, modules, index, pos) => {
|
||||||
let index = if state.always_search { None } else { *index };
|
let index = if state.always_search { None } else { *index };
|
||||||
|
let val = search_scope(scope, id, modules, index, *pos)?;
|
||||||
let val = if let Some(modules) = modules {
|
|
||||||
search_scope_modules(scope, id, modules, index, *pos)?
|
|
||||||
} else {
|
|
||||||
search_scope_variables(scope, id, index, *pos)?
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(val.0.clone())
|
Ok(val.0.clone())
|
||||||
}
|
}
|
||||||
Expr::Property(_, _) => unreachable!(),
|
Expr::Property(_, _) => unreachable!(),
|
||||||
@ -1290,13 +1285,7 @@ impl Engine {
|
|||||||
// name = rhs
|
// name = rhs
|
||||||
Expr::Variable(name, modules, index, pos) => {
|
Expr::Variable(name, modules, index, pos) => {
|
||||||
let index = if state.always_search { None } else { *index };
|
let index = if state.always_search { None } else { *index };
|
||||||
let val = if let Some(modules) = modules {
|
match search_scope(scope, name, modules, index, *pos)? {
|
||||||
search_scope_modules(scope, name, modules, index, *pos)?
|
|
||||||
} else {
|
|
||||||
search_scope_variables(scope, name, index, *pos)?
|
|
||||||
};
|
|
||||||
|
|
||||||
match val {
|
|
||||||
(_, ScopeEntryType::Constant) => Err(Box::new(
|
(_, ScopeEntryType::Constant) => Err(Box::new(
|
||||||
EvalAltResult::ErrorAssignmentToConstant(name.to_string(), *op_pos),
|
EvalAltResult::ErrorAssignmentToConstant(name.to_string(), *op_pos),
|
||||||
)),
|
)),
|
||||||
@ -1304,8 +1293,8 @@ impl Engine {
|
|||||||
*value_ptr = rhs_val;
|
*value_ptr = rhs_val;
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
// End variable cannot be a sub-scope
|
// End variable cannot be a module
|
||||||
(_, ScopeEntryType::SubScope) => unreachable!(),
|
(_, ScopeEntryType::Module) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// idx_lhs[idx_expr] = rhs
|
// idx_lhs[idx_expr] = rhs
|
||||||
@ -1369,7 +1358,6 @@ impl Engine {
|
|||||||
.collect::<Result<HashMap<_, _>, _>>()?,
|
.collect::<Result<HashMap<_, _>, _>>()?,
|
||||||
)))),
|
)))),
|
||||||
|
|
||||||
// TODO - handle moduled function call
|
|
||||||
Expr::FnCall(fn_name, modules, arg_exprs, def_val, pos) => {
|
Expr::FnCall(fn_name, modules, arg_exprs, def_val, pos) => {
|
||||||
let mut arg_values = arg_exprs
|
let mut arg_values = arg_exprs
|
||||||
.iter()
|
.iter()
|
||||||
@ -1380,6 +1368,7 @@ impl Engine {
|
|||||||
|
|
||||||
// eval - only in function call style
|
// eval - only in function call style
|
||||||
if fn_name.as_ref() == KEYWORD_EVAL
|
if fn_name.as_ref() == KEYWORD_EVAL
|
||||||
|
&& modules.is_none()
|
||||||
&& args.len() == 1
|
&& args.len() == 1
|
||||||
&& !self.has_override(fn_lib, KEYWORD_EVAL)
|
&& !self.has_override(fn_lib, KEYWORD_EVAL)
|
||||||
{
|
{
|
||||||
@ -1399,7 +1388,8 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Normal function call - except for eval (handled above)
|
// Normal function call - except for eval (handled above)
|
||||||
self.exec_fn_call(fn_lib, fn_name, &mut args, def_val.as_deref(), *pos, level)
|
let def_value = def_val.as_deref();
|
||||||
|
self.exec_fn_call(fn_lib, fn_name, modules, &mut args, def_value, *pos, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::In(lhs, rhs, _) => {
|
Expr::In(lhs, rhs, _) => {
|
||||||
@ -1634,13 +1624,13 @@ impl Engine {
|
|||||||
.eval_expr(scope, state, fn_lib, expr, level)?
|
.eval_expr(scope, state, fn_lib, expr, level)?
|
||||||
.try_cast::<String>()
|
.try_cast::<String>()
|
||||||
{
|
{
|
||||||
let mut module = SubScope::new();
|
let mut module = Module::new();
|
||||||
module.insert("kitty".to_string(), "foo".to_string().into());
|
module.insert("kitty".to_string(), "foo".to_string().into());
|
||||||
module.insert("path".to_string(), path.into());
|
module.insert("path".to_string(), path.into());
|
||||||
|
|
||||||
// TODO - avoid copying module name in inner block?
|
// TODO - avoid copying module name in inner block?
|
||||||
let mod_name = name.as_ref().clone();
|
let mod_name = name.as_ref().clone();
|
||||||
scope.push_sub_scope(mod_name, module);
|
scope.push_module(mod_name, module);
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
} else {
|
} else {
|
||||||
Err(Box::new(EvalAltResult::ErrorImportExpr(expr.position())))
|
Err(Box::new(EvalAltResult::ErrorImportExpr(expr.position())))
|
||||||
|
@ -103,9 +103,6 @@ pub use engine::Array;
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub use engine::Map;
|
pub use engine::Map;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_import"))]
|
|
||||||
pub use engine::SubScope;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
pub use parser::FLOAT;
|
pub use parser::FLOAT;
|
||||||
|
|
||||||
|
@ -231,6 +231,8 @@ fn optimize_stmt<'a>(stmt: Stmt, state: &mut State<'a>, preserve_result: bool) -
|
|||||||
}
|
}
|
||||||
// let id;
|
// let id;
|
||||||
Stmt::Let(_, None, _) => stmt,
|
Stmt::Let(_, None, _) => stmt,
|
||||||
|
// import expr as id;
|
||||||
|
Stmt::Import(expr, id, pos) => Stmt::Import(Box::new(optimize_expr(*expr, state)), id, pos),
|
||||||
// { block }
|
// { block }
|
||||||
Stmt::Block(block, pos) => {
|
Stmt::Block(block, pos) => {
|
||||||
let orig_len = block.len(); // Original number of statements in the block, for change detection
|
let orig_len = block.len(); // Original number of statements in the block, for change detection
|
||||||
@ -260,7 +262,7 @@ fn optimize_stmt<'a>(stmt: Stmt, state: &mut State<'a>, preserve_result: bool) -
|
|||||||
result.push(stmt);
|
result.push(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all let statements at the end of a block - the new variables will go away anyway.
|
// Remove all let/import statements at the end of a block - the new variables will go away anyway.
|
||||||
// But be careful only remove ones that have no initial values or have values that are pure expressions,
|
// But be careful only remove ones that have no initial values or have values that are pure expressions,
|
||||||
// otherwise there may be side effects.
|
// otherwise there may be side effects.
|
||||||
let mut removed = false;
|
let mut removed = false;
|
||||||
@ -268,7 +270,8 @@ fn optimize_stmt<'a>(stmt: Stmt, state: &mut State<'a>, preserve_result: bool) -
|
|||||||
while let Some(expr) = result.pop() {
|
while let Some(expr) = result.pop() {
|
||||||
match expr {
|
match expr {
|
||||||
Stmt::Let(_, None, _) => removed = true,
|
Stmt::Let(_, None, _) => removed = true,
|
||||||
Stmt::Let(_, Some(val_expr), _) if val_expr.is_pure() => removed = true,
|
Stmt::Let(_, Some(val_expr), _) => removed = val_expr.is_pure(),
|
||||||
|
Stmt::Import(expr, _, _) => removed = expr.is_pure(),
|
||||||
_ => {
|
_ => {
|
||||||
result.push(expr);
|
result.push(expr);
|
||||||
break;
|
break;
|
||||||
@ -323,6 +326,8 @@ fn optimize_stmt<'a>(stmt: Stmt, state: &mut State<'a>, preserve_result: bool) -
|
|||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
Stmt::Noop(pos)
|
Stmt::Noop(pos)
|
||||||
}
|
}
|
||||||
|
// Only one let/import statement - leave it alone
|
||||||
|
[Stmt::Let(_, _, _)] | [Stmt::Import(_, _, _)] => Stmt::Block(result, pos),
|
||||||
// Only one statement - promote
|
// Only one statement - promote
|
||||||
[_] => {
|
[_] => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -666,7 +671,10 @@ fn optimize<'a>(
|
|||||||
_ => {
|
_ => {
|
||||||
// Keep all variable declarations at this level
|
// Keep all variable declarations at this level
|
||||||
// and always keep the last return value
|
// and always keep the last return value
|
||||||
let keep = matches!(stmt, Stmt::Let(_, _, _)) || i == num_statements - 1;
|
let keep = match stmt {
|
||||||
|
Stmt::Let(_, _, _) | Stmt::Import(_, _, _) => true,
|
||||||
|
_ => i == num_statements - 1,
|
||||||
|
};
|
||||||
optimize_stmt(stmt, &mut state, keep)
|
optimize_stmt(stmt, &mut state, keep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,8 @@ pub type FLOAT = f64;
|
|||||||
|
|
||||||
type PERR = ParseErrorType;
|
type PERR = ParseErrorType;
|
||||||
|
|
||||||
|
pub type ModuleRef = Option<Box<StaticVec<(String, Position)>>>;
|
||||||
|
|
||||||
/// Compiled AST (abstract syntax tree) of a Rhai script.
|
/// Compiled AST (abstract syntax tree) of a Rhai script.
|
||||||
///
|
///
|
||||||
/// Currently, `AST` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
|
/// Currently, `AST` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
|
||||||
@ -204,7 +206,7 @@ impl Stack {
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, (n, typ))| match typ {
|
.find(|(_, (n, typ))| match typ {
|
||||||
ScopeEntryType::Normal | ScopeEntryType::Constant => *n == name,
|
ScopeEntryType::Normal | ScopeEntryType::Constant => *n == name,
|
||||||
ScopeEntryType::SubScope => false,
|
ScopeEntryType::Module => false,
|
||||||
})
|
})
|
||||||
.and_then(|(i, _)| NonZeroUsize::new(i + 1))
|
.and_then(|(i, _)| NonZeroUsize::new(i + 1))
|
||||||
}
|
}
|
||||||
@ -218,7 +220,7 @@ impl Stack {
|
|||||||
.rev()
|
.rev()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, (n, typ))| match typ {
|
.find(|(_, (n, typ))| match typ {
|
||||||
ScopeEntryType::SubScope => *n == name,
|
ScopeEntryType::Module => *n == name,
|
||||||
ScopeEntryType::Normal | ScopeEntryType::Constant => false,
|
ScopeEntryType::Normal | ScopeEntryType::Constant => false,
|
||||||
})
|
})
|
||||||
.and_then(|(i, _)| NonZeroUsize::new(i + 1))
|
.and_then(|(i, _)| NonZeroUsize::new(i + 1))
|
||||||
@ -344,12 +346,7 @@ pub enum Expr {
|
|||||||
/// String constant.
|
/// String constant.
|
||||||
StringConstant(String, Position),
|
StringConstant(String, Position),
|
||||||
/// Variable access - (variable name, optional modules, optional index, position)
|
/// Variable access - (variable name, optional modules, optional index, position)
|
||||||
Variable(
|
Variable(Box<String>, ModuleRef, Option<NonZeroUsize>, Position),
|
||||||
Box<String>,
|
|
||||||
Option<Box<StaticVec<(String, Position)>>>,
|
|
||||||
Option<NonZeroUsize>,
|
|
||||||
Position,
|
|
||||||
),
|
|
||||||
/// Property access.
|
/// Property access.
|
||||||
Property(String, Position),
|
Property(String, Position),
|
||||||
/// { stmt }
|
/// { stmt }
|
||||||
@ -359,7 +356,7 @@ pub enum Expr {
|
|||||||
/// and the function names are predictable, so no need to allocate a new `String`.
|
/// and the function names are predictable, so no need to allocate a new `String`.
|
||||||
FnCall(
|
FnCall(
|
||||||
Box<Cow<'static, str>>,
|
Box<Cow<'static, str>>,
|
||||||
Option<Box<StaticVec<(String, Position)>>>,
|
ModuleRef,
|
||||||
Box<Vec<Expr>>,
|
Box<Vec<Expr>>,
|
||||||
Option<Box<Dynamic>>,
|
Option<Box<Dynamic>>,
|
||||||
Position,
|
Position,
|
||||||
@ -575,12 +572,12 @@ impl Expr {
|
|||||||
|
|
||||||
Self::Variable(_, None, _, _) => match token {
|
Self::Variable(_, None, _, _) => match token {
|
||||||
Token::LeftBracket | Token::LeftParen => true,
|
Token::LeftBracket | Token::LeftParen => true,
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Token::DoubleColon => true,
|
Token::DoubleColon => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
Self::Variable(_, _, _, _) => match token {
|
Self::Variable(_, _, _, _) => match token {
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Token::DoubleColon => true,
|
Token::DoubleColon => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
@ -659,7 +656,7 @@ fn parse_call_expr<'a>(
|
|||||||
input: &mut Peekable<TokenIterator<'a>>,
|
input: &mut Peekable<TokenIterator<'a>>,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
id: String,
|
id: String,
|
||||||
modules: Option<Box<StaticVec<(String, Position)>>>,
|
modules: ModuleRef,
|
||||||
begin: Position,
|
begin: Position,
|
||||||
allow_stmt_expr: bool,
|
allow_stmt_expr: bool,
|
||||||
) -> Result<Expr, Box<ParseError>> {
|
) -> Result<Expr, Box<ParseError>> {
|
||||||
@ -1071,7 +1068,7 @@ fn parse_primary<'a>(
|
|||||||
parse_call_expr(input, stack, id, None, pos, allow_stmt_expr)?
|
parse_call_expr(input, stack, id, None, pos, allow_stmt_expr)?
|
||||||
}
|
}
|
||||||
// module access
|
// module access
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
(Expr::Variable(id, mut modules, mut index, pos), Token::DoubleColon) => {
|
(Expr::Variable(id, mut modules, mut index, pos), Token::DoubleColon) => {
|
||||||
match input.next().unwrap() {
|
match input.next().unwrap() {
|
||||||
(Token::Identifier(id2), pos2) => {
|
(Token::Identifier(id2), pos2) => {
|
||||||
@ -1790,7 +1787,7 @@ fn parse_let<'a>(
|
|||||||
Err(PERR::ForbiddenConstantExpr(name).into_err(init_value.position()))
|
Err(PERR::ForbiddenConstantExpr(name).into_err(init_value.position()))
|
||||||
}
|
}
|
||||||
// Variable cannot be a sub-scope
|
// Variable cannot be a sub-scope
|
||||||
ScopeEntryType::SubScope => unreachable!(),
|
ScopeEntryType::Module => unreachable!(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// let name
|
// let name
|
||||||
@ -1799,7 +1796,7 @@ fn parse_let<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an import statement.
|
/// Parse an import statement.
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
fn parse_import<'a>(
|
fn parse_import<'a>(
|
||||||
input: &mut Peekable<TokenIterator<'a>>,
|
input: &mut Peekable<TokenIterator<'a>>,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
@ -1829,7 +1826,7 @@ fn parse_import<'a>(
|
|||||||
(_, pos) => return Err(PERR::VariableExpected.into_err(pos)),
|
(_, pos) => return Err(PERR::VariableExpected.into_err(pos)),
|
||||||
};
|
};
|
||||||
|
|
||||||
stack.push((name.clone(), ScopeEntryType::SubScope));
|
stack.push((name.clone(), ScopeEntryType::Module));
|
||||||
Ok(Stmt::Import(Box::new(expr), Box::new(name), pos))
|
Ok(Stmt::Import(Box::new(expr), Box::new(name), pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
63
src/scope.rs
63
src/scope.rs
@ -1,7 +1,7 @@
|
|||||||
//! Module that defines the `Scope` type representing a function call-stack scope.
|
//! Module that defines the `Scope` type representing a function call-stack scope.
|
||||||
|
|
||||||
use crate::any::{Dynamic, Union, Variant};
|
use crate::any::{Dynamic, Union, Variant};
|
||||||
use crate::engine::SubScope;
|
use crate::engine::Module;
|
||||||
use crate::parser::{map_dynamic_to_expr, Expr};
|
use crate::parser::{map_dynamic_to_expr, Expr};
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
|
||||||
@ -14,8 +14,9 @@ pub enum EntryType {
|
|||||||
Normal,
|
Normal,
|
||||||
/// Immutable constant value.
|
/// Immutable constant value.
|
||||||
Constant,
|
Constant,
|
||||||
/// Name of a sub-scope, allowing member access with the :: operator.
|
/// Name of a module, allowing member access with the :: operator.
|
||||||
SubScope,
|
/// This is for internal use only.
|
||||||
|
Module,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An entry in the Scope.
|
/// An entry in the Scope.
|
||||||
@ -168,30 +169,14 @@ impl<'a> Scope<'a> {
|
|||||||
self.push_dynamic_value(name, EntryType::Normal, value, false);
|
self.push_dynamic_value(name, EntryType::Normal, value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add (push) a new sub-scope to the Scope.
|
/// Add (push) a new module to the Scope.
|
||||||
///
|
///
|
||||||
/// Sub-scopes are used for accessing members in modules and plugins under a namespace.
|
/// Modules are used for accessing member variables, functions and plugins under a namespace.
|
||||||
///
|
pub(crate) fn push_module<K: Into<Cow<'a, str>>>(&mut self, name: K, value: Module) {
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use rhai::{Scope, SubScope};
|
|
||||||
///
|
|
||||||
/// let mut my_scope = Scope::new();
|
|
||||||
///
|
|
||||||
/// let mut sub_scope = SubScope::new();
|
|
||||||
/// sub_scope.insert("x".to_string(), 42_i64.into());
|
|
||||||
///
|
|
||||||
/// my_scope.push_sub_scope("my_plugin", sub_scope);
|
|
||||||
///
|
|
||||||
/// let s = my_scope.find_sub_scope("my_plugin").unwrap();
|
|
||||||
/// assert_eq!(*s.get("x").unwrap().downcast_ref::<i64>().unwrap(), 42);
|
|
||||||
/// ```
|
|
||||||
pub fn push_sub_scope<K: Into<Cow<'a, str>>>(&mut self, name: K, value: SubScope) {
|
|
||||||
self.push_dynamic_value(
|
self.push_dynamic_value(
|
||||||
name,
|
name,
|
||||||
EntryType::SubScope,
|
EntryType::Module,
|
||||||
Dynamic(Union::SubScope(Box::new(value))),
|
Dynamic(Union::Module(Box::new(value))),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -295,8 +280,6 @@ impl<'a> Scope<'a> {
|
|||||||
|
|
||||||
/// Does the scope contain the entry?
|
/// Does the scope contain the entry?
|
||||||
///
|
///
|
||||||
/// Sub-scopes are ignored.
|
|
||||||
///
|
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@ -314,13 +297,13 @@ impl<'a> Scope<'a> {
|
|||||||
.rev() // Always search a Scope in reverse order
|
.rev() // Always search a Scope in reverse order
|
||||||
.any(|Entry { name: key, typ, .. }| match typ {
|
.any(|Entry { name: key, typ, .. }| match typ {
|
||||||
EntryType::Normal | EntryType::Constant => name == key,
|
EntryType::Normal | EntryType::Constant => name == key,
|
||||||
EntryType::SubScope => false,
|
EntryType::Module => false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find an entry in the Scope, starting from the last.
|
/// Find an entry in the Scope, starting from the last.
|
||||||
///
|
///
|
||||||
/// Sub-scopes are ignored.
|
/// modules are ignored.
|
||||||
pub(crate) fn get_index(&self, name: &str) -> Option<(usize, EntryType)> {
|
pub(crate) fn get_index(&self, name: &str) -> Option<(usize, EntryType)> {
|
||||||
self.0
|
self.0
|
||||||
.iter()
|
.iter()
|
||||||
@ -334,18 +317,18 @@ impl<'a> Scope<'a> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EntryType::SubScope => None,
|
EntryType::Module => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find a sub-scope in the Scope, starting from the last.
|
/// Find a module in the Scope, starting from the last.
|
||||||
pub(crate) fn get_sub_scope_index(&self, name: &str) -> Option<usize> {
|
pub(crate) fn get_module_index(&self, name: &str) -> Option<usize> {
|
||||||
self.0
|
self.0
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.rev() // Always search a Scope in reverse order
|
.rev() // Always search a Scope in reverse order
|
||||||
.find_map(|(index, Entry { name: key, typ, .. })| match typ {
|
.find_map(|(index, Entry { name: key, typ, .. })| match typ {
|
||||||
EntryType::SubScope => {
|
EntryType::Module => {
|
||||||
if name == key {
|
if name == key {
|
||||||
Some(index)
|
Some(index)
|
||||||
} else {
|
} else {
|
||||||
@ -356,15 +339,15 @@ impl<'a> Scope<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find a sub-scope in the Scope, starting from the last entry.
|
/// Find a module in the Scope, starting from the last entry.
|
||||||
pub fn find_sub_scope(&mut self, name: &str) -> Option<&mut SubScope> {
|
pub fn find_module(&mut self, name: &str) -> Option<&mut Module> {
|
||||||
let index = self.get_sub_scope_index(name)?;
|
let index = self.get_module_index(name)?;
|
||||||
self.get_mut(index).0.downcast_mut::<SubScope>()
|
self.get_mut(index).0.downcast_mut::<Module>()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
///
|
///
|
||||||
/// Sub-scopes are ignored.
|
/// modules are ignored.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@ -382,7 +365,7 @@ impl<'a> Scope<'a> {
|
|||||||
.rev()
|
.rev()
|
||||||
.find(|Entry { name: key, typ, .. }| match typ {
|
.find(|Entry { name: key, typ, .. }| match typ {
|
||||||
EntryType::Normal | EntryType::Constant => name == key,
|
EntryType::Normal | EntryType::Constant => name == key,
|
||||||
EntryType::SubScope => false,
|
EntryType::Module => false,
|
||||||
})
|
})
|
||||||
.and_then(|Entry { value, .. }| value.downcast_ref::<T>().cloned())
|
.and_then(|Entry { value, .. }| value.downcast_ref::<T>().cloned())
|
||||||
}
|
}
|
||||||
@ -415,8 +398,8 @@ impl<'a> Scope<'a> {
|
|||||||
Some((index, EntryType::Normal)) => {
|
Some((index, EntryType::Normal)) => {
|
||||||
self.0.get_mut(index).unwrap().value = Dynamic::from(value)
|
self.0.get_mut(index).unwrap().value = Dynamic::from(value)
|
||||||
}
|
}
|
||||||
// Sub-scopes cannot be modified
|
// modules cannot be modified
|
||||||
Some((_, EntryType::SubScope)) => unreachable!(),
|
Some((_, EntryType::Module)) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
24
src/token.rs
24
src/token.rs
@ -153,7 +153,7 @@ pub enum Token {
|
|||||||
RightShift,
|
RightShift,
|
||||||
SemiColon,
|
SemiColon,
|
||||||
Colon,
|
Colon,
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
DoubleColon,
|
DoubleColon,
|
||||||
Comma,
|
Comma,
|
||||||
Period,
|
Period,
|
||||||
@ -199,11 +199,11 @@ pub enum Token {
|
|||||||
XOrAssign,
|
XOrAssign,
|
||||||
ModuloAssign,
|
ModuloAssign,
|
||||||
PowerOfAssign,
|
PowerOfAssign,
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Import,
|
Import,
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Export,
|
Export,
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
As,
|
As,
|
||||||
LexError(Box<LexError>),
|
LexError(Box<LexError>),
|
||||||
EOF,
|
EOF,
|
||||||
@ -238,7 +238,7 @@ impl Token {
|
|||||||
Divide => "/",
|
Divide => "/",
|
||||||
SemiColon => ";",
|
SemiColon => ";",
|
||||||
Colon => ":",
|
Colon => ":",
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
DoubleColon => "::",
|
DoubleColon => "::",
|
||||||
Comma => ",",
|
Comma => ",",
|
||||||
Period => ".",
|
Period => ".",
|
||||||
@ -288,11 +288,11 @@ impl Token {
|
|||||||
ModuloAssign => "%=",
|
ModuloAssign => "%=",
|
||||||
PowerOf => "~",
|
PowerOf => "~",
|
||||||
PowerOfAssign => "~=",
|
PowerOfAssign => "~=",
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Import => "import",
|
Import => "import",
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Export => "export",
|
Export => "export",
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
As => "as",
|
As => "as",
|
||||||
EOF => "{EOF}",
|
EOF => "{EOF}",
|
||||||
_ => panic!("operator should be match in outer scope"),
|
_ => panic!("operator should be match in outer scope"),
|
||||||
@ -763,11 +763,11 @@ impl<'a> TokenIterator<'a> {
|
|||||||
"for" => Token::For,
|
"for" => Token::For,
|
||||||
"in" => Token::In,
|
"in" => Token::In,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
"import" => Token::Import,
|
"import" => Token::Import,
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
"export" => Token::Export,
|
"export" => Token::Export,
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
"as" => Token::As,
|
"as" => Token::As,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
@ -924,7 +924,7 @@ impl<'a> TokenIterator<'a> {
|
|||||||
}
|
}
|
||||||
('=', _) => return Some((Token::Equals, pos)),
|
('=', _) => return Some((Token::Equals, pos)),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_import"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
(':', ':') => {
|
(':', ':') => {
|
||||||
self.eat_next();
|
self.eat_next();
|
||||||
return Some((Token::DoubleColon, pos));
|
return Some((Token::DoubleColon, pos));
|
||||||
|
@ -1,15 +1 @@
|
|||||||
use rhai::{EvalAltResult, Scope, SubScope, INT};
|
use rhai::{EvalAltResult, Scope, INT};
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[cfg(not(feature = "no_import"))]
|
|
||||||
fn test_sub_scope() {
|
|
||||||
let mut my_scope = Scope::new();
|
|
||||||
|
|
||||||
let mut sub_scope = SubScope::new();
|
|
||||||
sub_scope.insert("x".to_string(), (42 as INT).into());
|
|
||||||
|
|
||||||
my_scope.push_sub_scope("my_plugin", sub_scope);
|
|
||||||
|
|
||||||
let s = my_scope.find_sub_scope("my_plugin").unwrap();
|
|
||||||
assert_eq!(*s.get("x").unwrap().downcast_ref::<INT>().unwrap(), 42);
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user