Make sure all features compile correctly.
This commit is contained in:
parent
88fec57394
commit
d75a8bc6cd
115
src/any.rs
115
src/any.rs
@ -1,12 +1,19 @@
|
|||||||
//! 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};
|
#[cfg(not(feature = "no_module"))]
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
|
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::parser::FLOAT;
|
use crate::parser::FLOAT;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
use crate::engine::Array;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
use crate::engine::Map;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::{type_name, Any, TypeId},
|
any::{type_name, Any, TypeId},
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
@ -134,8 +141,11 @@ pub enum Union {
|
|||||||
Int(INT),
|
Int(INT),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Float(FLOAT),
|
Float(FLOAT),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Array(Box<Array>),
|
Array(Box<Array>),
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
Map(Box<Map>),
|
Map(Box<Map>),
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Module(Box<Module>),
|
Module(Box<Module>),
|
||||||
Variant(Box<Box<dyn Variant>>),
|
Variant(Box<Box<dyn Variant>>),
|
||||||
}
|
}
|
||||||
@ -165,8 +175,11 @@ impl Dynamic {
|
|||||||
Union::Int(_) => TypeId::of::<INT>(),
|
Union::Int(_) => TypeId::of::<INT>(),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Union::Float(_) => TypeId::of::<FLOAT>(),
|
Union::Float(_) => TypeId::of::<FLOAT>(),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(_) => TypeId::of::<Array>(),
|
Union::Array(_) => TypeId::of::<Array>(),
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(_) => TypeId::of::<Map>(),
|
Union::Map(_) => TypeId::of::<Map>(),
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Union::Module(_) => TypeId::of::<Module>(),
|
Union::Module(_) => TypeId::of::<Module>(),
|
||||||
Union::Variant(value) => (***value).type_id(),
|
Union::Variant(value) => (***value).type_id(),
|
||||||
}
|
}
|
||||||
@ -182,8 +195,11 @@ impl Dynamic {
|
|||||||
Union::Int(_) => type_name::<INT>(),
|
Union::Int(_) => type_name::<INT>(),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Union::Float(_) => type_name::<FLOAT>(),
|
Union::Float(_) => type_name::<FLOAT>(),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(_) => "array",
|
Union::Array(_) => "array",
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(_) => "map",
|
Union::Map(_) => "map",
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Union::Module(_) => "sub-scope",
|
Union::Module(_) => "sub-scope",
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
@ -203,8 +219,11 @@ impl fmt::Display for Dynamic {
|
|||||||
Union::Int(value) => write!(f, "{}", value),
|
Union::Int(value) => write!(f, "{}", value),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Union::Float(value) => write!(f, "{}", value),
|
Union::Float(value) => write!(f, "{}", value),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(value) => write!(f, "{:?}", value),
|
Union::Array(value) => write!(f, "{:?}", value),
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(value) => write!(f, "#{:?}", value),
|
Union::Map(value) => write!(f, "#{:?}", value),
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Union::Module(value) => write!(f, "{:?}", value),
|
Union::Module(value) => write!(f, "{:?}", value),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
@ -224,8 +243,11 @@ impl fmt::Debug for Dynamic {
|
|||||||
Union::Int(value) => write!(f, "{:?}", value),
|
Union::Int(value) => write!(f, "{:?}", value),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Union::Float(value) => write!(f, "{:?}", value),
|
Union::Float(value) => write!(f, "{:?}", value),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(value) => write!(f, "{:?}", value),
|
Union::Array(value) => write!(f, "{:?}", value),
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(value) => write!(f, "#{:?}", value),
|
Union::Map(value) => write!(f, "#{:?}", value),
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Union::Module(value) => write!(f, "{:?}", value),
|
Union::Module(value) => write!(f, "{:?}", value),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
@ -245,8 +267,11 @@ impl Clone for Dynamic {
|
|||||||
Union::Int(value) => Self(Union::Int(value)),
|
Union::Int(value) => Self(Union::Int(value)),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Union::Float(value) => Self(Union::Float(value)),
|
Union::Float(value) => Self(Union::Float(value)),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(ref value) => Self(Union::Array(value.clone())),
|
Union::Array(ref value) => Self(Union::Array(value.clone())),
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(ref value) => Self(Union::Map(value.clone())),
|
Union::Map(ref value) => Self(Union::Map(value.clone())),
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Union::Module(ref value) => Self(Union::Module(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(),
|
||||||
}
|
}
|
||||||
@ -260,13 +285,13 @@ impl Default for Dynamic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Cast a Boxed type into another type.
|
/// Cast a Boxed type into another type.
|
||||||
fn cast_box<X: Variant, T: Variant>(item: Box<X>) -> Result<T, Box<X>> {
|
fn cast_box<X: Variant, T: Variant>(item: Box<X>) -> Result<Box<T>, Box<X>> {
|
||||||
// Only allow casting to the exact same type
|
// Only allow casting to the exact same type
|
||||||
if TypeId::of::<X>() == TypeId::of::<T>() {
|
if TypeId::of::<X>() == TypeId::of::<T>() {
|
||||||
// SAFETY: just checked whether we are pointing to the correct type
|
// SAFETY: just checked whether we are pointing to the correct type
|
||||||
unsafe {
|
unsafe {
|
||||||
let raw: *mut dyn Any = Box::into_raw(item as Box<dyn Any>);
|
let raw: *mut dyn Any = Box::into_raw(item as Box<dyn Any>);
|
||||||
Ok(*Box::from_raw(raw as *mut T))
|
Ok(Box::from_raw(raw as *mut T))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Return the consumed item for chaining.
|
// Return the consumed item for chaining.
|
||||||
@ -320,31 +345,33 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let var = Box::new(value);
|
let mut var = Box::new(value);
|
||||||
|
|
||||||
Self(
|
var = match cast_box::<_, Dynamic>(var) {
|
||||||
cast_box::<_, Dynamic>(var)
|
Ok(d) => return *d,
|
||||||
.map(|x| x.0)
|
Err(var) => var,
|
||||||
.or_else(|var| {
|
};
|
||||||
cast_box::<_, String>(var)
|
var = match cast_box::<_, String>(var) {
|
||||||
.map(Box::new)
|
Ok(s) => return Self(Union::Str(s)),
|
||||||
.map(Union::Str)
|
Err(var) => var,
|
||||||
.or_else(|var| {
|
};
|
||||||
cast_box::<_, Array>(var)
|
#[cfg(not(feature = "no_index"))]
|
||||||
.map(Box::new)
|
{
|
||||||
.map(Union::Array)
|
var = match cast_box::<_, Array>(var) {
|
||||||
.or_else(|var| {
|
Ok(array) => return Self(Union::Array(array)),
|
||||||
cast_box::<_, Map>(var)
|
Err(var) => var,
|
||||||
.map(Box::new)
|
};
|
||||||
.map(Union::Map)
|
}
|
||||||
.or_else(|var| -> Result<Union, ()> {
|
|
||||||
Ok(Union::Variant(Box::new(var)))
|
#[cfg(not(feature = "no_object"))]
|
||||||
})
|
{
|
||||||
})
|
var = match cast_box::<_, Map>(var) {
|
||||||
})
|
Ok(map) => return Self(Union::Map(map)),
|
||||||
})
|
Err(var) => var,
|
||||||
.unwrap(),
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
|
Self(Union::Variant(Box::new(var)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a copy of the `Dynamic` value as a specific type.
|
/// Get a copy of the `Dynamic` value as a specific type.
|
||||||
@ -363,20 +390,23 @@ impl Dynamic {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn try_cast<T: Variant + Clone>(self) -> Option<T> {
|
pub fn try_cast<T: Variant + Clone>(self) -> Option<T> {
|
||||||
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
|
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
|
||||||
return cast_box::<_, T>(Box::new(self)).ok();
|
return cast_box::<_, T>(Box::new(self)).ok().map(|v| *v);
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Unit(ref value) => (value as &dyn Any).downcast_ref::<T>().cloned(),
|
Union::Unit(ref value) => (value as &dyn Any).downcast_ref::<T>().cloned(),
|
||||||
Union::Bool(ref value) => (value as &dyn Any).downcast_ref::<T>().cloned(),
|
Union::Bool(ref value) => (value as &dyn Any).downcast_ref::<T>().cloned(),
|
||||||
Union::Str(value) => cast_box::<_, T>(value).ok(),
|
Union::Str(value) => cast_box::<_, T>(value).ok().map(|v| *v),
|
||||||
Union::Char(ref value) => (value as &dyn Any).downcast_ref::<T>().cloned(),
|
Union::Char(ref value) => (value as &dyn Any).downcast_ref::<T>().cloned(),
|
||||||
Union::Int(ref value) => (value as &dyn Any).downcast_ref::<T>().cloned(),
|
Union::Int(ref value) => (value as &dyn Any).downcast_ref::<T>().cloned(),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
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(),
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Map(value) => cast_box::<_, T>(value).ok(),
|
Union::Array(value) => cast_box::<_, T>(value).ok().map(|v| *v),
|
||||||
Union::Module(value) => cast_box::<_, T>(value).ok(),
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
Union::Map(value) => cast_box::<_, T>(value).ok().map(|v| *v),
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Union::Module(value) => cast_box::<_, T>(value).ok().map(|v| *v),
|
||||||
Union::Variant(value) => value.as_any().downcast_ref::<T>().cloned(),
|
Union::Variant(value) => value.as_any().downcast_ref::<T>().cloned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -401,20 +431,23 @@ impl Dynamic {
|
|||||||
//self.try_cast::<T>().unwrap()
|
//self.try_cast::<T>().unwrap()
|
||||||
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
|
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
|
||||||
return cast_box::<_, T>(Box::new(self)).unwrap();
|
return *cast_box::<_, T>(Box::new(self)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Unit(ref value) => (value as &dyn Any).downcast_ref::<T>().unwrap().clone(),
|
Union::Unit(ref value) => (value as &dyn Any).downcast_ref::<T>().unwrap().clone(),
|
||||||
Union::Bool(ref value) => (value as &dyn Any).downcast_ref::<T>().unwrap().clone(),
|
Union::Bool(ref value) => (value as &dyn Any).downcast_ref::<T>().unwrap().clone(),
|
||||||
Union::Str(value) => cast_box::<_, T>(value).unwrap(),
|
Union::Str(value) => *cast_box::<_, T>(value).unwrap(),
|
||||||
Union::Char(ref value) => (value as &dyn Any).downcast_ref::<T>().unwrap().clone(),
|
Union::Char(ref value) => (value as &dyn Any).downcast_ref::<T>().unwrap().clone(),
|
||||||
Union::Int(ref value) => (value as &dyn Any).downcast_ref::<T>().unwrap().clone(),
|
Union::Int(ref value) => (value as &dyn Any).downcast_ref::<T>().unwrap().clone(),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
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(),
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Map(value) => cast_box::<_, T>(value).unwrap(),
|
Union::Array(value) => *cast_box::<_, T>(value).unwrap(),
|
||||||
Union::Module(value) => cast_box::<_, T>(value).unwrap(),
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
Union::Map(value) => *cast_box::<_, T>(value).unwrap(),
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -435,8 +468,11 @@ impl Dynamic {
|
|||||||
Union::Int(value) => (value as &dyn Any).downcast_ref::<T>(),
|
Union::Int(value) => (value as &dyn Any).downcast_ref::<T>(),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Union::Float(value) => (value as &dyn Any).downcast_ref::<T>(),
|
Union::Float(value) => (value as &dyn Any).downcast_ref::<T>(),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(value) => (value.as_ref() as &dyn Any).downcast_ref::<T>(),
|
Union::Array(value) => (value.as_ref() as &dyn Any).downcast_ref::<T>(),
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(value) => (value.as_ref() as &dyn Any).downcast_ref::<T>(),
|
Union::Map(value) => (value.as_ref() as &dyn Any).downcast_ref::<T>(),
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Union::Module(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>(),
|
||||||
}
|
}
|
||||||
@ -458,8 +494,11 @@ impl Dynamic {
|
|||||||
Union::Int(value) => (value as &mut dyn Any).downcast_mut::<T>(),
|
Union::Int(value) => (value as &mut dyn Any).downcast_mut::<T>(),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Union::Float(value) => (value as &mut dyn Any).downcast_mut::<T>(),
|
Union::Float(value) => (value as &mut dyn Any).downcast_mut::<T>(),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
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>(),
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
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>(),
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Union::Module(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>(),
|
||||||
}
|
}
|
||||||
@ -542,6 +581,7 @@ impl From<String> for Dynamic {
|
|||||||
Self(Union::Str(Box::new(value)))
|
Self(Union::Str(Box::new(value)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
impl<T: Variant + Clone> From<Vec<T>> for Dynamic {
|
impl<T: Variant + Clone> From<Vec<T>> for Dynamic {
|
||||||
fn from(value: Vec<T>) -> Self {
|
fn from(value: Vec<T>) -> Self {
|
||||||
Self(Union::Array(Box::new(
|
Self(Union::Array(Box::new(
|
||||||
@ -549,6 +589,7 @@ impl<T: Variant + Clone> From<Vec<T>> for Dynamic {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
impl<T: Variant + Clone> From<HashMap<String, T>> for Dynamic {
|
impl<T: Variant + Clone> From<HashMap<String, T>> for Dynamic {
|
||||||
fn from(value: HashMap<String, T>) -> Self {
|
fn from(value: HashMap<String, T>) -> Self {
|
||||||
Self(Union::Map(Box::new(
|
Self(Union::Map(Box::new(
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Module that defines the extern API of `Engine`.
|
//! Module that defines the extern API of `Engine`.
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::engine::{make_getter, make_setter, Engine, Map, State, FUNC_INDEXER};
|
use crate::engine::{make_getter, make_setter, Engine, State, FUNC_INDEXER};
|
||||||
use crate::error::ParseError;
|
use crate::error::ParseError;
|
||||||
use crate::fn_call::FuncArgs;
|
use crate::fn_call::FuncArgs;
|
||||||
use crate::fn_register::RegisterFn;
|
use crate::fn_register::RegisterFn;
|
||||||
@ -11,6 +11,9 @@ use crate::result::EvalAltResult;
|
|||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use crate::token::{lex, Position};
|
use crate::token::{lex, Position};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
use crate::engine::Map;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::{type_name, TypeId},
|
any::{type_name, TypeId},
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
|
113
src/engine.rs
113
src/engine.rs
@ -3,7 +3,6 @@
|
|||||||
use crate::any::{Dynamic, Union};
|
use crate::any::{Dynamic, Union};
|
||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::error::ParseErrorType;
|
use crate::error::ParseErrorType;
|
||||||
use crate::module::{resolvers, Module, ModuleResolver};
|
|
||||||
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, ModuleRef, ReturnType, Stmt, AST};
|
use crate::parser::{Expr, FnDef, ModuleRef, ReturnType, Stmt, AST};
|
||||||
@ -12,6 +11,9 @@ use crate::scope::{EntryType as ScopeEntryType, Scope};
|
|||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::utils::{calc_fn_def, StaticVec};
|
use crate::utils::{calc_fn_def, StaticVec};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
use crate::module::{resolvers, Module, ModuleResolver};
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
@ -30,11 +32,13 @@ use crate::stdlib::{
|
|||||||
/// An dynamic array of `Dynamic` values.
|
/// An dynamic array of `Dynamic` values.
|
||||||
///
|
///
|
||||||
/// Not available under the `no_index` feature.
|
/// Not available under the `no_index` feature.
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub type Array = Vec<Dynamic>;
|
pub type Array = Vec<Dynamic>;
|
||||||
|
|
||||||
/// An dynamic hash map of `Dynamic` values with `String` keys.
|
/// An dynamic hash map of `Dynamic` values with `String` keys.
|
||||||
///
|
///
|
||||||
/// Not available under the `no_object` feature.
|
/// Not available under the `no_object` feature.
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub type Map = HashMap<String, Dynamic>;
|
pub type Map = HashMap<String, Dynamic>;
|
||||||
|
|
||||||
pub type FnCallArgs<'a> = [&'a mut Dynamic];
|
pub type FnCallArgs<'a> = [&'a mut Dynamic];
|
||||||
@ -262,6 +266,7 @@ pub struct Engine {
|
|||||||
pub(crate) type_iterators: HashMap<TypeId, Box<IteratorFn>>,
|
pub(crate) type_iterators: HashMap<TypeId, Box<IteratorFn>>,
|
||||||
|
|
||||||
/// A module resolution service.
|
/// A module resolution service.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub(crate) module_resolver: Option<Box<dyn ModuleResolver>>,
|
pub(crate) module_resolver: Option<Box<dyn ModuleResolver>>,
|
||||||
|
|
||||||
/// A hashmap mapping type names to pretty-print names.
|
/// A hashmap mapping type names to pretty-print names.
|
||||||
@ -301,7 +306,8 @@ impl Default for Engine {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
module_resolver: Some(Box::new(resolvers::FileModuleResolver::new())),
|
module_resolver: Some(Box::new(resolvers::FileModuleResolver::new())),
|
||||||
#[cfg(any(feature = "no_std", feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
#[cfg(feature = "no_std")]
|
||||||
module_resolver: None,
|
module_resolver: None,
|
||||||
|
|
||||||
type_names: Default::default(),
|
type_names: Default::default(),
|
||||||
@ -391,6 +397,8 @@ fn search_scope<'a>(
|
|||||||
index: Option<NonZeroUsize>,
|
index: Option<NonZeroUsize>,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> Result<(&'a mut Dynamic, ScopeEntryType), Box<EvalAltResult>> {
|
) -> Result<(&'a mut Dynamic, ScopeEntryType), Box<EvalAltResult>> {
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
{
|
||||||
if let Some(modules) = modules {
|
if let Some(modules) = modules {
|
||||||
let (id, root_pos) = modules.get(0); // First module
|
let (id, root_pos) = modules.get(0); // First module
|
||||||
|
|
||||||
@ -401,17 +409,19 @@ fn search_scope<'a>(
|
|||||||
.downcast_mut::<Module>()
|
.downcast_mut::<Module>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
} else {
|
} else {
|
||||||
scope
|
scope.find_module(id).ok_or_else(|| {
|
||||||
.find_module(id)
|
Box::new(EvalAltResult::ErrorModuleNotFound(id.into(), *root_pos))
|
||||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorModuleNotFound(id.into(), *root_pos)))?
|
})?
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((
|
return Ok((
|
||||||
module.get_qualified_var_mut(name, modules.as_ref(), pos)?,
|
module.get_qualified_var_mut(name, modules.as_ref(), pos)?,
|
||||||
// Module variables are constant
|
// Module variables are constant
|
||||||
ScopeEntryType::Constant,
|
ScopeEntryType::Constant,
|
||||||
))
|
));
|
||||||
} 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 {
|
||||||
@ -422,7 +432,6 @@ fn search_scope<'a>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(scope.get_mut(index))
|
Ok(scope.get_mut(index))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
@ -438,7 +447,10 @@ impl Engine {
|
|||||||
packages: Default::default(),
|
packages: Default::default(),
|
||||||
functions: HashMap::with_capacity(FUNCTIONS_COUNT / 2),
|
functions: HashMap::with_capacity(FUNCTIONS_COUNT / 2),
|
||||||
type_iterators: Default::default(),
|
type_iterators: Default::default(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
module_resolver: None,
|
module_resolver: None,
|
||||||
|
|
||||||
type_names: Default::default(),
|
type_names: Default::default(),
|
||||||
print: Box::new(|_| {}),
|
print: Box::new(|_| {}),
|
||||||
debug: Box::new(|_| {}),
|
debug: Box::new(|_| {}),
|
||||||
@ -721,7 +733,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let statements = mem::take(ast.statements_mut());
|
let statements = mem::take(ast.statements_mut());
|
||||||
ast = AST::new(statements, fn_lib.clone());
|
let ast = AST::new(statements, fn_lib.clone());
|
||||||
|
|
||||||
// Evaluate the AST
|
// Evaluate the AST
|
||||||
self.eval_ast_with_scope_raw(scope, &ast)
|
self.eval_ast_with_scope_raw(scope, &ast)
|
||||||
@ -779,7 +791,7 @@ impl Engine {
|
|||||||
// xxx.fn_name(arg_expr_list)
|
// xxx.fn_name(arg_expr_list)
|
||||||
Expr::FnCall(fn_name, None,_, def_val, pos) => {
|
Expr::FnCall(fn_name, None,_, def_val, pos) => {
|
||||||
let mut args: Vec<_> = once(obj)
|
let mut args: Vec<_> = once(obj)
|
||||||
.chain(idx_val.downcast_mut::<Array>().unwrap().iter_mut())
|
.chain(idx_val.downcast_mut::<Vec<Dynamic>>().unwrap().iter_mut())
|
||||||
.collect();
|
.collect();
|
||||||
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
|
||||||
@ -789,6 +801,7 @@ impl Engine {
|
|||||||
// xxx.module::fn_name(...) - syntax error
|
// xxx.module::fn_name(...) - syntax error
|
||||||
Expr::FnCall(_,_,_,_,_) => unreachable!(),
|
Expr::FnCall(_,_,_,_,_) => unreachable!(),
|
||||||
// {xxx:map}.id = ???
|
// {xxx:map}.id = ???
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Property(id, pos) if obj.is::<Map>() && new_val.is_some() => {
|
Expr::Property(id, pos) if obj.is::<Map>() && new_val.is_some() => {
|
||||||
let mut indexed_val =
|
let mut indexed_val =
|
||||||
self.get_indexed_mut(fn_lib, obj, id.to_string().into(), *pos, op_pos, true)?;
|
self.get_indexed_mut(fn_lib, obj, id.to_string().into(), *pos, op_pos, true)?;
|
||||||
@ -796,6 +809,7 @@ impl Engine {
|
|||||||
Ok((Default::default(), true))
|
Ok((Default::default(), true))
|
||||||
}
|
}
|
||||||
// {xxx:map}.id
|
// {xxx:map}.id
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Property(id, pos) if obj.is::<Map>() => {
|
Expr::Property(id, pos) if obj.is::<Map>() => {
|
||||||
let indexed_val =
|
let indexed_val =
|
||||||
self.get_indexed_mut(fn_lib, obj, id.to_string().into(), *pos, op_pos, false)?;
|
self.get_indexed_mut(fn_lib, obj, id.to_string().into(), *pos, op_pos, false)?;
|
||||||
@ -813,6 +827,7 @@ impl Engine {
|
|||||||
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, &mut args, None, *pos, 0).map(|v| (v, false))
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
// {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) |
|
||||||
// {xxx:map}.dot_lhs.rhs
|
// {xxx:map}.dot_lhs.rhs
|
||||||
@ -959,7 +974,10 @@ impl Engine {
|
|||||||
.map(|arg_expr| self.eval_expr(scope, state, fn_lib, arg_expr, level))
|
.map(|arg_expr| self.eval_expr(scope, state, fn_lib, arg_expr, level))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
idx_values.push(arg_values)
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
idx_values.push(arg_values);
|
||||||
|
#[cfg(feature = "no_index")]
|
||||||
|
idx_values.push(Dynamic::from(arg_values));
|
||||||
}
|
}
|
||||||
Expr::FnCall(_, _, _, _, _) => unreachable!(),
|
Expr::FnCall(_, _, _, _, _) => unreachable!(),
|
||||||
Expr::Property(_, _) => idx_values.push(()), // Store a placeholder - no need to copy the property name
|
Expr::Property(_, _) => idx_values.push(()), // Store a placeholder - no need to copy the property name
|
||||||
@ -994,6 +1012,7 @@ impl Engine {
|
|||||||
let type_name = self.map_type_name(val.type_name());
|
let type_name = self.map_type_name(val.type_name());
|
||||||
|
|
||||||
match val {
|
match val {
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Dynamic(Union::Array(arr)) => {
|
Dynamic(Union::Array(arr)) => {
|
||||||
// val_array[idx]
|
// val_array[idx]
|
||||||
let index = idx
|
let index = idx
|
||||||
@ -1015,6 +1034,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
Dynamic(Union::Map(map)) => {
|
Dynamic(Union::Map(map)) => {
|
||||||
// val_map[idx]
|
// val_map[idx]
|
||||||
let index = idx
|
let index = idx
|
||||||
@ -1030,6 +1050,7 @@ impl Engine {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Dynamic(Union::Str(s)) => {
|
Dynamic(Union::Str(s)) => {
|
||||||
// val_string[idx]
|
// val_string[idx]
|
||||||
let index = idx
|
let index = idx
|
||||||
@ -1088,6 +1109,7 @@ impl Engine {
|
|||||||
let rhs_value = self.eval_expr(scope, state, fn_lib, rhs, level)?;
|
let rhs_value = self.eval_expr(scope, state, fn_lib, rhs, level)?;
|
||||||
|
|
||||||
match rhs_value {
|
match rhs_value {
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Dynamic(Union::Array(mut rhs_value)) => {
|
Dynamic(Union::Array(mut rhs_value)) => {
|
||||||
let def_value = false.into();
|
let def_value = false.into();
|
||||||
|
|
||||||
@ -1108,6 +1130,7 @@ impl Engine {
|
|||||||
|
|
||||||
Ok(false.into())
|
Ok(false.into())
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
Dynamic(Union::Map(rhs_value)) => match lhs_value {
|
Dynamic(Union::Map(rhs_value)) => match lhs_value {
|
||||||
// Only allows String or char
|
// Only allows String or char
|
||||||
Dynamic(Union::Str(s)) => Ok(rhs_value.contains_key(s.as_ref()).into()),
|
Dynamic(Union::Str(s)) => Ok(rhs_value.contains_key(s.as_ref()).into()),
|
||||||
@ -1230,7 +1253,8 @@ impl Engine {
|
|||||||
.collect::<Result<HashMap<_, _>, _>>()?,
|
.collect::<Result<HashMap<_, _>, _>>()?,
|
||||||
)))),
|
)))),
|
||||||
|
|
||||||
Expr::FnCall(fn_name, modules, arg_exprs, def_val, pos) => {
|
// Normal function call
|
||||||
|
Expr::FnCall(fn_name, None, arg_exprs, def_val, pos) => {
|
||||||
let mut arg_values = arg_exprs
|
let mut arg_values = arg_exprs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|expr| self.eval_expr(scope, state, fn_lib, expr, level))
|
.map(|expr| self.eval_expr(scope, state, fn_lib, expr, level))
|
||||||
@ -1238,32 +1262,7 @@ impl Engine {
|
|||||||
|
|
||||||
let mut args: Vec<_> = arg_values.iter_mut().collect();
|
let mut args: Vec<_> = arg_values.iter_mut().collect();
|
||||||
|
|
||||||
if let Some(modules) = modules {
|
if fn_name.as_ref() == KEYWORD_EVAL
|
||||||
// Module-qualified function call
|
|
||||||
let modules = modules.as_ref();
|
|
||||||
|
|
||||||
let (id, root_pos) = modules.get(0); // First module
|
|
||||||
|
|
||||||
let module = scope.find_module(id).ok_or_else(|| {
|
|
||||||
Box::new(EvalAltResult::ErrorModuleNotFound(id.into(), *root_pos))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// First search in script-defined functions (can override built-in)
|
|
||||||
if let Some(fn_def) =
|
|
||||||
module.get_qualified_fn_lib(fn_name, args.len(), modules)?
|
|
||||||
{
|
|
||||||
self.call_fn_from_lib(None, fn_lib, fn_def, &mut args, *pos, level)
|
|
||||||
} else {
|
|
||||||
// Then search in Rust functions
|
|
||||||
let hash = calc_fn_hash(fn_name, args.iter().map(|a| a.type_id()));
|
|
||||||
|
|
||||||
match module.get_qualified_fn(fn_name, hash, modules, *pos) {
|
|
||||||
Ok(func) => func(&mut args, *pos),
|
|
||||||
Err(_) if def_val.is_some() => Ok(def_val.as_deref().unwrap().clone()),
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if fn_name.as_ref() == KEYWORD_EVAL
|
|
||||||
&& args.len() == 1
|
&& args.len() == 1
|
||||||
&& !self.has_override(fn_lib, KEYWORD_EVAL)
|
&& !self.has_override(fn_lib, KEYWORD_EVAL)
|
||||||
{
|
{
|
||||||
@ -1288,6 +1287,39 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Module-qualified function call
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Expr::FnCall(fn_name, Some(modules), arg_exprs, def_val, pos) => {
|
||||||
|
let modules = modules.as_ref();
|
||||||
|
|
||||||
|
let mut arg_values = arg_exprs
|
||||||
|
.iter()
|
||||||
|
.map(|expr| self.eval_expr(scope, state, fn_lib, expr, level))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
let mut args: Vec<_> = arg_values.iter_mut().collect();
|
||||||
|
|
||||||
|
let (id, root_pos) = modules.get(0); // First module
|
||||||
|
|
||||||
|
let module = scope.find_module(id).ok_or_else(|| {
|
||||||
|
Box::new(EvalAltResult::ErrorModuleNotFound(id.into(), *root_pos))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// First search in script-defined functions (can override built-in)
|
||||||
|
if let Some(fn_def) = module.get_qualified_fn_lib(fn_name, args.len(), modules)? {
|
||||||
|
self.call_fn_from_lib(None, fn_lib, fn_def, &mut args, *pos, level)
|
||||||
|
} else {
|
||||||
|
// Then search in Rust functions
|
||||||
|
let hash = calc_fn_hash(fn_name, args.iter().map(|a| a.type_id()));
|
||||||
|
|
||||||
|
match module.get_qualified_fn(fn_name, hash, modules, *pos) {
|
||||||
|
Ok(func) => func(&mut args, *pos),
|
||||||
|
Err(_) if def_val.is_some() => Ok(def_val.as_deref().unwrap().clone()),
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Expr::In(lhs, rhs, _) => {
|
Expr::In(lhs, rhs, _) => {
|
||||||
self.eval_in_expr(scope, state, fn_lib, lhs.as_ref(), rhs.as_ref(), level)
|
self.eval_in_expr(scope, state, fn_lib, lhs.as_ref(), rhs.as_ref(), level)
|
||||||
}
|
}
|
||||||
@ -1519,6 +1551,8 @@ impl Engine {
|
|||||||
#[cfg(feature = "no_module")]
|
#[cfg(feature = "no_module")]
|
||||||
unreachable!();
|
unreachable!();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
{
|
||||||
if let Some(path) = self
|
if let Some(path) = self
|
||||||
.eval_expr(scope, state, fn_lib, expr, level)?
|
.eval_expr(scope, state, fn_lib, expr, level)?
|
||||||
.try_cast::<String>()
|
.try_cast::<String>()
|
||||||
@ -1542,6 +1576,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Map a type_name into a pretty-print name
|
/// Map a type_name into a pretty-print name
|
||||||
pub(crate) fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str {
|
pub(crate) fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str {
|
||||||
|
445
src/module.rs
445
src/module.rs
@ -1,9 +1,10 @@
|
|||||||
//! Module defining external-loaded modules for Rhai.
|
//! Module defining external-loaded modules for Rhai.
|
||||||
|
#![cfg(not(feature = "no_module"))]
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::engine::{Engine, FnAny, FnCallArgs, FunctionsLib};
|
use crate::engine::{Engine, FnAny, FnCallArgs, FunctionsLib};
|
||||||
use crate::parser::FnDef;
|
use crate::parser::{FnDef, AST};
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
|
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
@ -12,11 +13,12 @@ use crate::utils::StaticVec;
|
|||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
|
boxed::Box,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt, mem,
|
fmt, mem,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
string::String,
|
string::{String, ToString},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -70,21 +72,61 @@ impl fmt::Debug for Module {
|
|||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
/// Create a new module.
|
/// Create a new module.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// module.set_var("answer", 42_i64);
|
||||||
|
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42);
|
||||||
|
/// ```
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does a variable exist in the module?
|
/// Does a variable exist in the module?
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// module.set_var("answer", 42_i64);
|
||||||
|
/// assert!(module.contains_var("answer"));
|
||||||
|
/// ```
|
||||||
pub fn contains_var(&self, name: &str) -> bool {
|
pub fn contains_var(&self, name: &str) -> bool {
|
||||||
self.variables.contains_key(name)
|
self.variables.contains_key(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the value of a module variable.
|
/// Get the value of a module variable.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// module.set_var("answer", 42_i64);
|
||||||
|
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42);
|
||||||
|
/// ```
|
||||||
pub fn get_var_value<T: Variant + Clone>(&self, name: &str) -> Option<T> {
|
pub fn get_var_value<T: Variant + Clone>(&self, name: &str) -> Option<T> {
|
||||||
self.get_var(name).and_then(|v| v.try_cast::<T>())
|
self.get_var(name).and_then(|v| v.try_cast::<T>())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a module variable.
|
/// Get a module variable as a `Dynamic`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// module.set_var("answer", 42_i64);
|
||||||
|
/// assert_eq!(module.get_var("answer").unwrap().cast::<i64>(), 42);
|
||||||
|
/// ```
|
||||||
pub fn get_var(&self, name: &str) -> Option<Dynamic> {
|
pub fn get_var(&self, name: &str) -> Option<Dynamic> {
|
||||||
self.variables.get(name).cloned()
|
self.variables.get(name).cloned()
|
||||||
}
|
}
|
||||||
@ -97,6 +139,16 @@ impl Module {
|
|||||||
/// Set a variable into the module.
|
/// Set a variable into the module.
|
||||||
///
|
///
|
||||||
/// If there is an existing variable of the same name, it is replaced.
|
/// If there is an existing variable of the same name, it is replaced.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// module.set_var("answer", 42_i64);
|
||||||
|
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42);
|
||||||
|
/// ```
|
||||||
pub fn set_var<K: Into<String>, T: Into<Dynamic>>(&mut self, name: K, value: T) {
|
pub fn set_var<K: Into<String>, T: Into<Dynamic>>(&mut self, name: K, value: T) {
|
||||||
self.variables.insert(name.into(), value.into());
|
self.variables.insert(name.into(), value.into());
|
||||||
}
|
}
|
||||||
@ -115,16 +167,49 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Does a sub-module exist in the module?
|
/// Does a sub-module exist in the module?
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// let sub_module = Module::new();
|
||||||
|
/// module.set_sub_module("question", sub_module);
|
||||||
|
/// assert!(module.contains_sub_module("question"));
|
||||||
|
/// ```
|
||||||
pub fn contains_sub_module(&self, name: &str) -> bool {
|
pub fn contains_sub_module(&self, name: &str) -> bool {
|
||||||
self.modules.contains_key(name)
|
self.modules.contains_key(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a sub-module.
|
/// Get a sub-module.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// let sub_module = Module::new();
|
||||||
|
/// module.set_sub_module("question", sub_module);
|
||||||
|
/// assert!(module.get_sub_module("question").is_some());
|
||||||
|
/// ```
|
||||||
pub fn get_sub_module(&self, name: &str) -> Option<&Module> {
|
pub fn get_sub_module(&self, name: &str) -> Option<&Module> {
|
||||||
self.modules.get(name)
|
self.modules.get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a mutable reference to a sub-module.
|
/// Get a mutable reference to a sub-module.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// let sub_module = Module::new();
|
||||||
|
/// module.set_sub_module("question", sub_module);
|
||||||
|
/// assert!(module.get_sub_module_mut("question").is_some());
|
||||||
|
/// ```
|
||||||
pub fn get_sub_module_mut(&mut self, name: &str) -> Option<&mut Module> {
|
pub fn get_sub_module_mut(&mut self, name: &str) -> Option<&mut Module> {
|
||||||
self.modules.get_mut(name)
|
self.modules.get_mut(name)
|
||||||
}
|
}
|
||||||
@ -132,6 +217,17 @@ impl Module {
|
|||||||
/// Set a sub-module into the module.
|
/// Set a sub-module into the module.
|
||||||
///
|
///
|
||||||
/// If there is an existing sub-module of the same name, it is replaced.
|
/// If there is an existing sub-module of the same name, it is replaced.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// let sub_module = Module::new();
|
||||||
|
/// module.set_sub_module("question", sub_module);
|
||||||
|
/// assert!(module.get_sub_module("question").is_some());
|
||||||
|
/// ```
|
||||||
pub fn set_sub_module<K: Into<String>>(&mut self, name: K, sub_module: Module) {
|
pub fn set_sub_module<K: Into<String>>(&mut self, name: K, sub_module: Module) {
|
||||||
self.modules.insert(name.into(), sub_module.into());
|
self.modules.insert(name.into(), sub_module.into());
|
||||||
}
|
}
|
||||||
@ -160,6 +256,16 @@ impl Module {
|
|||||||
///
|
///
|
||||||
/// The `u64` hash is calculated by the function `crate::calc_fn_hash`.
|
/// The `u64` hash is calculated by the function `crate::calc_fn_hash`.
|
||||||
/// It is also returned by the `set_fn_XXX` calls.
|
/// It is also returned by the `set_fn_XXX` calls.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// let hash = module.set_fn_0("calc", || Ok(42_i64));
|
||||||
|
/// assert!(module.contains_fn(hash));
|
||||||
|
/// ```
|
||||||
pub fn contains_fn(&self, hash: u64) -> bool {
|
pub fn contains_fn(&self, hash: u64) -> bool {
|
||||||
self.functions.contains_key(&hash)
|
self.functions.contains_key(&hash)
|
||||||
}
|
}
|
||||||
@ -181,6 +287,16 @@ impl Module {
|
|||||||
/// Set a Rust function taking no parameters into the module, returning a hash key.
|
/// Set a Rust function taking no parameters into the module, returning a hash key.
|
||||||
///
|
///
|
||||||
/// If there is a similar existing Rust function, it is replaced.
|
/// If there is a similar existing Rust function, it is replaced.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// let hash = module.set_fn_0("calc", || Ok(42_i64));
|
||||||
|
/// assert!(module.get_fn(hash).is_some());
|
||||||
|
/// ```
|
||||||
pub fn set_fn_0<T: Into<Dynamic>>(
|
pub fn set_fn_0<T: Into<Dynamic>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
@ -199,6 +315,16 @@ impl Module {
|
|||||||
/// Set a Rust function taking one parameter into the module, returning a hash key.
|
/// Set a Rust function taking one parameter into the module, returning a hash key.
|
||||||
///
|
///
|
||||||
/// If there is a similar existing Rust function, it is replaced.
|
/// If there is a similar existing Rust function, it is replaced.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// let hash = module.set_fn_1("calc", |x: i64| Ok(x + 1));
|
||||||
|
/// assert!(module.get_fn(hash).is_some());
|
||||||
|
/// ```
|
||||||
pub fn set_fn_1<A: Variant + Clone, T: Into<Dynamic>>(
|
pub fn set_fn_1<A: Variant + Clone, T: Into<Dynamic>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
@ -217,6 +343,16 @@ impl Module {
|
|||||||
/// Set a Rust function taking one mutable parameter into the module, returning a hash key.
|
/// Set a Rust function taking one mutable parameter into the module, returning a hash key.
|
||||||
///
|
///
|
||||||
/// If there is a similar existing Rust function, it is replaced.
|
/// If there is a similar existing Rust function, it is replaced.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// let hash = module.set_fn_1_mut("calc", |x: &mut i64| { *x += 1; Ok(*x) });
|
||||||
|
/// assert!(module.get_fn(hash).is_some());
|
||||||
|
/// ```
|
||||||
pub fn set_fn_1_mut<A: Variant + Clone, T: Into<Dynamic>>(
|
pub fn set_fn_1_mut<A: Variant + Clone, T: Into<Dynamic>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
@ -235,6 +371,18 @@ impl Module {
|
|||||||
/// Set a Rust function taking two parameters into the module, returning a hash key.
|
/// Set a Rust function taking two parameters into the module, returning a hash key.
|
||||||
///
|
///
|
||||||
/// If there is a similar existing Rust function, it is replaced.
|
/// If there is a similar existing Rust function, it is replaced.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// let hash = module.set_fn_2("calc", |x: i64, y: String| {
|
||||||
|
/// Ok(x + y.len() as i64)
|
||||||
|
/// });
|
||||||
|
/// assert!(module.get_fn(hash).is_some());
|
||||||
|
/// ```
|
||||||
pub fn set_fn_2<A: Variant + Clone, B: Variant + Clone, T: Into<Dynamic>>(
|
pub fn set_fn_2<A: Variant + Clone, B: Variant + Clone, T: Into<Dynamic>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
@ -256,7 +404,17 @@ impl Module {
|
|||||||
/// Set a Rust function taking two parameters (the first one mutable) into the module,
|
/// Set a Rust function taking two parameters (the first one mutable) into the module,
|
||||||
/// returning a hash key.
|
/// returning a hash key.
|
||||||
///
|
///
|
||||||
/// If there is a similar existing Rust function, it is replaced.
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// let hash = module.set_fn_2_mut("calc", |x: &mut i64, y: String| {
|
||||||
|
/// *x += y.len() as i64; Ok(*x)
|
||||||
|
/// });
|
||||||
|
/// assert!(module.get_fn(hash).is_some());
|
||||||
|
/// ```
|
||||||
pub fn set_fn_2_mut<A: Variant + Clone, B: Variant + Clone, T: Into<Dynamic>>(
|
pub fn set_fn_2_mut<A: Variant + Clone, B: Variant + Clone, T: Into<Dynamic>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
@ -278,6 +436,18 @@ impl Module {
|
|||||||
/// Set a Rust function taking three parameters into the module, returning a hash key.
|
/// Set a Rust function taking three parameters into the module, returning a hash key.
|
||||||
///
|
///
|
||||||
/// If there is a similar existing Rust function, it is replaced.
|
/// If there is a similar existing Rust function, it is replaced.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// let hash = module.set_fn_3("calc", |x: i64, y: String, z: i64| {
|
||||||
|
/// Ok(x + y.len() as i64 + z)
|
||||||
|
/// });
|
||||||
|
/// assert!(module.get_fn(hash).is_some());
|
||||||
|
/// ```
|
||||||
pub fn set_fn_3<
|
pub fn set_fn_3<
|
||||||
A: Variant + Clone,
|
A: Variant + Clone,
|
||||||
B: Variant + Clone,
|
B: Variant + Clone,
|
||||||
@ -306,6 +476,18 @@ impl Module {
|
|||||||
/// returning a hash key.
|
/// returning a hash key.
|
||||||
///
|
///
|
||||||
/// If there is a similar existing Rust function, it is replaced.
|
/// If there is a similar existing Rust function, it is replaced.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// let hash = module.set_fn_3_mut("calc", |x: &mut i64, y: String, z: i64| {
|
||||||
|
/// *x += y.len() as i64 + z; Ok(*x)
|
||||||
|
/// });
|
||||||
|
/// assert!(module.get_fn(hash).is_some());
|
||||||
|
/// ```
|
||||||
pub fn set_fn_3_mut<
|
pub fn set_fn_3_mut<
|
||||||
A: Variant + Clone,
|
A: Variant + Clone,
|
||||||
B: Variant + Clone,
|
B: Variant + Clone,
|
||||||
@ -334,6 +516,16 @@ impl Module {
|
|||||||
///
|
///
|
||||||
/// The `u64` hash is calculated by the function `crate::calc_fn_hash`.
|
/// The `u64` hash is calculated by the function `crate::calc_fn_hash`.
|
||||||
/// It is also returned by the `set_fn_XXX` calls.
|
/// It is also returned by the `set_fn_XXX` calls.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// let hash = module.set_fn_1("calc", |x: i64| Ok(x + 1));
|
||||||
|
/// assert!(module.get_fn(hash).is_some());
|
||||||
|
/// ```
|
||||||
pub fn get_fn(&self, hash: u64) -> Option<&Box<FnAny>> {
|
pub fn get_fn(&self, hash: u64) -> Option<&Box<FnAny>> {
|
||||||
self.functions.get(&hash).map(|v| v.as_ref())
|
self.functions.get(&hash).map(|v| v.as_ref())
|
||||||
}
|
}
|
||||||
@ -366,7 +558,16 @@ impl Module {
|
|||||||
})?)
|
})?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a script-defined function.
|
/// Get the script-defined functions.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Module;
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
/// assert_eq!(module.get_fn_lib().len(), 0);
|
||||||
|
/// ```
|
||||||
pub fn get_fn_lib(&self) -> &FunctionsLib {
|
pub fn get_fn_lib(&self) -> &FunctionsLib {
|
||||||
&self.fn_lib
|
&self.fn_lib
|
||||||
}
|
}
|
||||||
@ -383,73 +584,29 @@ impl Module {
|
|||||||
.fn_lib
|
.fn_lib
|
||||||
.get_function(name, args))
|
.get_function(name, args))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Re-export module resolvers.
|
/// Create a new `Module` by evaluating an `AST`.
|
||||||
pub mod resolvers {
|
|
||||||
pub use super::file::FileModuleResolver;
|
|
||||||
pub use super::stat::StaticModuleResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Script file-based module resolver.
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
mod file {
|
|
||||||
use super::*;
|
|
||||||
use crate::stdlib::path::PathBuf;
|
|
||||||
|
|
||||||
/// A module resolution service that loads module script files from the file system.
|
|
||||||
///
|
///
|
||||||
/// The `new_with_path` and `new_with_path_and_extension` constructor functions
|
/// # Examples
|
||||||
/// allow specification of a base directory with module path used as a relative path offset
|
|
||||||
/// to the base directory. The script file is then forced to be in a specified extension
|
|
||||||
/// (default `.rhai`).
|
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
|
|
||||||
pub struct FileModuleResolver {
|
|
||||||
path: PathBuf,
|
|
||||||
extension: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FileModuleResolver {
|
|
||||||
/// Create a new `FileModuleResolver` with a specific base path.
|
|
||||||
pub fn new_with_path(path: PathBuf) -> Self {
|
|
||||||
Self::new_with_path_and_extension(path, "rhai".to_string())
|
|
||||||
}
|
|
||||||
/// Create a new `FileModuleResolver` with a specific base path and file extension.
|
|
||||||
///
|
///
|
||||||
/// The default extension is `.rhai`.
|
/// ```
|
||||||
pub fn new_with_path_and_extension(path: PathBuf, extension: String) -> Self {
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||||
Self { path, extension }
|
/// use rhai::{Engine, Module};
|
||||||
}
|
///
|
||||||
/// Create a new `FileModuleResolver` with the current directory as base path.
|
/// let engine = Engine::new();
|
||||||
pub fn new() -> Self {
|
/// let ast = engine.compile("let answer = 42;")?;
|
||||||
Default::default()
|
/// let module = Module::eval_ast_as_new(&ast, &engine)?;
|
||||||
}
|
/// assert!(module.contains_var("answer"));
|
||||||
}
|
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42);
|
||||||
|
/// # Ok(())
|
||||||
impl ModuleResolver for FileModuleResolver {
|
/// # }
|
||||||
fn resolve(
|
/// ```
|
||||||
&self,
|
pub fn eval_ast_as_new(ast: &AST, engine: &Engine) -> FuncReturn<Self> {
|
||||||
engine: &Engine,
|
|
||||||
path: &str,
|
|
||||||
pos: Position,
|
|
||||||
) -> Result<Module, Box<EvalAltResult>> {
|
|
||||||
// Construct the script file path
|
|
||||||
let mut file_path = self.path.clone();
|
|
||||||
file_path.push(path);
|
|
||||||
file_path.set_extension(&self.extension); // Force extension
|
|
||||||
|
|
||||||
// Compile it
|
|
||||||
let ast = engine
|
|
||||||
.compile_file(file_path)
|
|
||||||
.map_err(|err| EvalAltResult::set_position(err, pos))?;
|
|
||||||
|
|
||||||
// Use new scope
|
// Use new scope
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
// Run the script
|
// Run the script
|
||||||
engine
|
engine.eval_ast_with_scope_raw(&mut scope, &ast)?;
|
||||||
.eval_ast_with_scope_raw(&mut scope, &ast)
|
|
||||||
.map_err(|err| EvalAltResult::set_position(err, pos))?;
|
|
||||||
|
|
||||||
// Create new module
|
// Create new module
|
||||||
let mut module = Module::new();
|
let mut module = Module::new();
|
||||||
@ -477,6 +634,134 @@ mod file {
|
|||||||
|
|
||||||
Ok(module)
|
Ok(module)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Re-export module resolvers.
|
||||||
|
pub mod resolvers {
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
|
pub use super::file::FileModuleResolver;
|
||||||
|
pub use super::stat::StaticModuleResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Script file-based module resolver.
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
|
mod file {
|
||||||
|
use super::*;
|
||||||
|
use crate::stdlib::path::PathBuf;
|
||||||
|
|
||||||
|
/// A module resolution service that loads module script files from the file system.
|
||||||
|
///
|
||||||
|
/// The `new_with_path` and `new_with_path_and_extension` constructor functions
|
||||||
|
/// allow specification of a base directory with module path used as a relative path offset
|
||||||
|
/// to the base directory. The script file is then forced to be in a specified extension
|
||||||
|
/// (default `.rhai`).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Engine;
|
||||||
|
/// use rhai::module_resolvers::FileModuleResolver;
|
||||||
|
///
|
||||||
|
/// // Create a new 'FileModuleResolver' loading scripts from the 'scripts' subdirectory
|
||||||
|
/// // with file extension '.x'.
|
||||||
|
/// let resolver = FileModuleResolver::new_with_path_and_extension("./scripts", "x");
|
||||||
|
///
|
||||||
|
/// let mut engine = Engine::new();
|
||||||
|
/// engine.set_module_resolver(Some(resolver));
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||||
|
pub struct FileModuleResolver {
|
||||||
|
path: PathBuf,
|
||||||
|
extension: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileModuleResolver {
|
||||||
|
/// Create a new `FileModuleResolver` with a specific base path.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Engine;
|
||||||
|
/// use rhai::module_resolvers::FileModuleResolver;
|
||||||
|
///
|
||||||
|
/// // Create a new 'FileModuleResolver' loading scripts from the 'scripts' subdirectory
|
||||||
|
/// // with file extension '.rhai' (the default).
|
||||||
|
/// let resolver = FileModuleResolver::new_with_path("./scripts");
|
||||||
|
///
|
||||||
|
/// let mut engine = Engine::new();
|
||||||
|
/// engine.set_module_resolver(Some(resolver));
|
||||||
|
/// ```
|
||||||
|
pub fn new_with_path<P: Into<PathBuf>>(path: P) -> Self {
|
||||||
|
Self::new_with_path_and_extension(path, "rhai")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new `FileModuleResolver` with a specific base path and file extension.
|
||||||
|
///
|
||||||
|
/// The default extension is `.rhai`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Engine;
|
||||||
|
/// use rhai::module_resolvers::FileModuleResolver;
|
||||||
|
///
|
||||||
|
/// // Create a new 'FileModuleResolver' loading scripts from the 'scripts' subdirectory
|
||||||
|
/// // with file extension '.x'.
|
||||||
|
/// let resolver = FileModuleResolver::new_with_path_and_extension("./scripts", "x");
|
||||||
|
///
|
||||||
|
/// let mut engine = Engine::new();
|
||||||
|
/// engine.set_module_resolver(Some(resolver));
|
||||||
|
/// ```
|
||||||
|
pub fn new_with_path_and_extension<P: Into<PathBuf>, E: Into<String>>(
|
||||||
|
path: P,
|
||||||
|
extension: E,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
path: path.into(),
|
||||||
|
extension: extension.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new `FileModuleResolver` with the current directory as base path.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::Engine;
|
||||||
|
/// use rhai::module_resolvers::FileModuleResolver;
|
||||||
|
///
|
||||||
|
/// // Create a new 'FileModuleResolver' loading scripts from the current directory
|
||||||
|
/// // with file extension '.rhai' (the default).
|
||||||
|
/// let resolver = FileModuleResolver::new();
|
||||||
|
///
|
||||||
|
/// let mut engine = Engine::new();
|
||||||
|
/// engine.set_module_resolver(Some(resolver));
|
||||||
|
/// ```
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleResolver for FileModuleResolver {
|
||||||
|
fn resolve(
|
||||||
|
&self,
|
||||||
|
engine: &Engine,
|
||||||
|
path: &str,
|
||||||
|
pos: Position,
|
||||||
|
) -> Result<Module, Box<EvalAltResult>> {
|
||||||
|
// Construct the script file path
|
||||||
|
let mut file_path = self.path.clone();
|
||||||
|
file_path.push(path);
|
||||||
|
file_path.set_extension(&self.extension); // Force extension
|
||||||
|
|
||||||
|
// Compile it
|
||||||
|
let ast = engine
|
||||||
|
.compile_file(file_path)
|
||||||
|
.map_err(|err| EvalAltResult::set_position(err, pos))?;
|
||||||
|
|
||||||
|
Module::eval_ast_as_new(&ast, engine)
|
||||||
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,11 +770,41 @@ mod stat {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A module resolution service that serves modules added into it.
|
/// A module resolution service that serves modules added into it.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::{Engine, Module};
|
||||||
|
/// use rhai::module_resolvers::StaticModuleResolver;
|
||||||
|
///
|
||||||
|
/// let mut resolver = StaticModuleResolver::new();
|
||||||
|
///
|
||||||
|
/// let module = Module::new();
|
||||||
|
/// resolver.insert("hello".to_string(), module);
|
||||||
|
///
|
||||||
|
/// let mut engine = Engine::new();
|
||||||
|
/// engine.set_module_resolver(Some(resolver));
|
||||||
|
/// ```
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct StaticModuleResolver(HashMap<String, Module>);
|
pub struct StaticModuleResolver(HashMap<String, Module>);
|
||||||
|
|
||||||
impl StaticModuleResolver {
|
impl StaticModuleResolver {
|
||||||
/// Create a new `StaticModuleResolver`.
|
/// Create a new `StaticModuleResolver`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use rhai::{Engine, Module};
|
||||||
|
/// use rhai::module_resolvers::StaticModuleResolver;
|
||||||
|
///
|
||||||
|
/// let mut resolver = StaticModuleResolver::new();
|
||||||
|
///
|
||||||
|
/// let module = Module::new();
|
||||||
|
/// resolver.insert("hello".to_string(), module);
|
||||||
|
///
|
||||||
|
/// let mut engine = Engine::new();
|
||||||
|
/// engine.set_module_resolver(Some(resolver));
|
||||||
|
/// ```
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
@ -711,11 +711,16 @@ pub fn optimize_into_ast(
|
|||||||
#[cfg(feature = "no_optimize")]
|
#[cfg(feature = "no_optimize")]
|
||||||
const level: OptimizationLevel = OptimizationLevel::None;
|
const level: OptimizationLevel = OptimizationLevel::None;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
let fn_lib: Vec<_> = functions
|
let fn_lib: Vec<_> = functions
|
||||||
.iter()
|
.iter()
|
||||||
.map(|fn_def| (fn_def.name.as_str(), fn_def.params.len()))
|
.map(|fn_def| (fn_def.name.as_str(), fn_def.params.len()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
#[cfg(feature = "no_function")]
|
||||||
|
const fn_lib: &[(&str, usize)] = &[];
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
let lib = FunctionsLib::from_vec(
|
let lib = FunctionsLib::from_vec(
|
||||||
functions
|
functions
|
||||||
.iter()
|
.iter()
|
||||||
@ -745,6 +750,9 @@ pub fn optimize_into_ast(
|
|||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[cfg(feature = "no_function")]
|
||||||
|
let lib: FunctionsLib = Default::default();
|
||||||
|
|
||||||
AST::new(
|
AST::new(
|
||||||
match level {
|
match level {
|
||||||
OptimizationLevel::None => statements,
|
OptimizationLevel::None => statements,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#![cfg(not(feature = "no_index"))]
|
||||||
|
|
||||||
use super::{reg_binary, reg_binary_mut, reg_trinary_mut, reg_unary_mut};
|
use super::{reg_binary, reg_binary_mut, reg_trinary_mut, reg_unary_mut};
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#![cfg(not(feature = "no_object"))]
|
||||||
|
|
||||||
use super::{reg_binary, reg_binary_mut, reg_unary_mut};
|
use super::{reg_binary, reg_binary_mut, reg_unary_mut};
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::any::Dynamic;
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
use super::{reg_binary, reg_binary_mut, reg_none, reg_unary, reg_unary_mut};
|
use super::{reg_binary, reg_binary_mut, reg_none, reg_unary, reg_unary_mut};
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::engine::{Array, Map, FUNC_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT};
|
use crate::engine::{FUNC_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT};
|
||||||
use crate::fn_register::map_dynamic as map;
|
use crate::fn_register::map_dynamic as map;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
use crate::engine::Array;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
use crate::engine::Map;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
format,
|
format,
|
||||||
@ -18,6 +24,7 @@ fn to_debug<T: Debug>(x: &mut T) -> String {
|
|||||||
fn to_string<T: Display>(x: &mut T) -> String {
|
fn to_string<T: Display>(x: &mut T) -> String {
|
||||||
format!("{}", x)
|
format!("{}", x)
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
fn format_map(x: &mut Map) -> String {
|
fn format_map(x: &mut Map) -> String {
|
||||||
format!("#{:?}", x)
|
format!("#{:?}", x)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use super::{reg_binary, reg_binary_mut, reg_trinary_mut, reg_unary_mut};
|
use super::{reg_binary, reg_binary_mut, reg_trinary_mut, reg_unary_mut};
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::engine::Array;
|
|
||||||
use crate::fn_register::map_dynamic as map;
|
use crate::fn_register::map_dynamic as map;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
use crate::engine::Array;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
format,
|
format,
|
||||||
|
@ -39,6 +39,7 @@ pub type INT = i32;
|
|||||||
/// The system floating-point type.
|
/// The system floating-point type.
|
||||||
///
|
///
|
||||||
/// Not available under the `no_float` feature.
|
/// Not available under the `no_float` feature.
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
pub type FLOAT = f64;
|
pub type FLOAT = f64;
|
||||||
|
|
||||||
type PERR = ParseErrorType;
|
type PERR = ParseErrorType;
|
||||||
@ -143,13 +144,11 @@ impl AST {
|
|||||||
(true, true) => vec![],
|
(true, true) => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "sync")]
|
Self::new(ast, functions.merge(other.1.as_ref()))
|
||||||
return Self(ast, Arc::new(functions.merge(other.1.as_ref())));
|
|
||||||
#[cfg(not(feature = "sync"))]
|
|
||||||
return Self(ast, Rc::new(functions.merge(other.1.as_ref())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear all function definitions in the `AST`.
|
/// Clear all function definitions in the `AST`.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub fn clear_functions(&mut self) {
|
pub fn clear_functions(&mut self) {
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
{
|
{
|
||||||
@ -162,6 +161,7 @@ impl AST {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Clear all statements in the `AST`, leaving only function definitions.
|
/// Clear all statements in the `AST`, leaving only function definitions.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub fn retain_functions(&mut self) {
|
pub fn retain_functions(&mut self) {
|
||||||
self.0 = vec![];
|
self.0 = vec![];
|
||||||
}
|
}
|
||||||
@ -351,6 +351,7 @@ pub enum Expr {
|
|||||||
/// Integer constant.
|
/// Integer constant.
|
||||||
IntegerConstant(INT, Position),
|
IntegerConstant(INT, Position),
|
||||||
/// Floating-point constant.
|
/// Floating-point constant.
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
FloatConstant(FLOAT, Position),
|
FloatConstant(FLOAT, Position),
|
||||||
/// Character constant.
|
/// Character constant.
|
||||||
CharConstant(char, Position),
|
CharConstant(char, Position),
|
||||||
@ -413,6 +414,7 @@ impl Expr {
|
|||||||
Self::False(_) => false.into(),
|
Self::False(_) => false.into(),
|
||||||
Self::Unit(_) => ().into(),
|
Self::Unit(_) => ().into(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::Array(items, _) if items.iter().all(Self::is_constant) => {
|
Self::Array(items, _) if items.iter().all(Self::is_constant) => {
|
||||||
Dynamic(Union::Array(Box::new(
|
Dynamic(Union::Array(Box::new(
|
||||||
items
|
items
|
||||||
@ -422,6 +424,7 @@ impl Expr {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
Self::Map(items, _) if items.iter().all(|(_, v, _)| v.is_constant()) => {
|
Self::Map(items, _) if items.iter().all(|(_, v, _)| v.is_constant()) => {
|
||||||
Dynamic(Union::Map(Box::new(
|
Dynamic(Union::Map(Box::new(
|
||||||
items
|
items
|
||||||
@ -442,8 +445,10 @@ impl Expr {
|
|||||||
/// Panics when the expression is not constant.
|
/// Panics when the expression is not constant.
|
||||||
pub fn get_constant_str(&self) -> String {
|
pub fn get_constant_str(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::IntegerConstant(i, _) => i.to_string(),
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(f, _) => f.to_string(),
|
Self::FloatConstant(f, _) => f.to_string(),
|
||||||
|
|
||||||
|
Self::IntegerConstant(i, _) => i.to_string(),
|
||||||
Self::CharConstant(c, _) => c.to_string(),
|
Self::CharConstant(c, _) => c.to_string(),
|
||||||
Self::StringConstant(_, _) => "string".to_string(),
|
Self::StringConstant(_, _) => "string".to_string(),
|
||||||
Self::True(_) => "true".to_string(),
|
Self::True(_) => "true".to_string(),
|
||||||
@ -459,8 +464,10 @@ impl Expr {
|
|||||||
/// Get the `Position` of the expression.
|
/// Get the `Position` of the expression.
|
||||||
pub fn position(&self) -> Position {
|
pub fn position(&self) -> Position {
|
||||||
match self {
|
match self {
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Self::FloatConstant(_, pos) => *pos,
|
||||||
|
|
||||||
Self::IntegerConstant(_, pos)
|
Self::IntegerConstant(_, pos)
|
||||||
| Self::FloatConstant(_, pos)
|
|
||||||
| Self::CharConstant(_, pos)
|
| Self::CharConstant(_, pos)
|
||||||
| Self::StringConstant(_, pos)
|
| Self::StringConstant(_, pos)
|
||||||
| Self::Array(_, pos)
|
| Self::Array(_, pos)
|
||||||
@ -485,8 +492,10 @@ impl Expr {
|
|||||||
/// Get the `Position` of the expression.
|
/// Get the `Position` of the expression.
|
||||||
pub(crate) fn set_position(mut self, new_pos: Position) -> Self {
|
pub(crate) fn set_position(mut self, new_pos: Position) -> Self {
|
||||||
match &mut self {
|
match &mut self {
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Self::FloatConstant(_, pos) => *pos = new_pos,
|
||||||
|
|
||||||
Self::IntegerConstant(_, pos)
|
Self::IntegerConstant(_, pos)
|
||||||
| Self::FloatConstant(_, pos)
|
|
||||||
| Self::CharConstant(_, pos)
|
| Self::CharConstant(_, pos)
|
||||||
| Self::StringConstant(_, pos)
|
| Self::StringConstant(_, pos)
|
||||||
| Self::Array(_, pos)
|
| Self::Array(_, pos)
|
||||||
@ -531,8 +540,10 @@ impl Expr {
|
|||||||
/// Is the expression a constant?
|
/// Is the expression a constant?
|
||||||
pub fn is_constant(&self) -> bool {
|
pub fn is_constant(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Self::FloatConstant(_, _) => true,
|
||||||
|
|
||||||
Self::IntegerConstant(_, _)
|
Self::IntegerConstant(_, _)
|
||||||
| Self::FloatConstant(_, _)
|
|
||||||
| Self::CharConstant(_, _)
|
| Self::CharConstant(_, _)
|
||||||
| Self::StringConstant(_, _)
|
| Self::StringConstant(_, _)
|
||||||
| Self::True(_)
|
| Self::True(_)
|
||||||
@ -559,8 +570,10 @@ impl Expr {
|
|||||||
/// Is a particular token allowed as a postfix operator to this expression?
|
/// Is a particular token allowed as a postfix operator to this expression?
|
||||||
pub fn is_valid_postfix(&self, token: &Token) -> bool {
|
pub fn is_valid_postfix(&self, token: &Token) -> bool {
|
||||||
match self {
|
match self {
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Self::FloatConstant(_, _) => false,
|
||||||
|
|
||||||
Self::IntegerConstant(_, _)
|
Self::IntegerConstant(_, _)
|
||||||
| Self::FloatConstant(_, _)
|
|
||||||
| Self::CharConstant(_, _)
|
| Self::CharConstant(_, _)
|
||||||
| Self::In(_, _, _)
|
| Self::In(_, _, _)
|
||||||
| Self::And(_, _, _)
|
| Self::And(_, _, _)
|
||||||
@ -764,8 +777,15 @@ fn parse_index_chain<'a>(
|
|||||||
.into_err(*pos))
|
.into_err(*pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::FloatConstant(_, pos)
|
#[cfg(not(feature = "no_float"))]
|
||||||
| Expr::CharConstant(_, pos)
|
Expr::FloatConstant(_, pos) => {
|
||||||
|
return Err(PERR::MalformedIndexExpr(
|
||||||
|
"Only arrays, object maps and strings can be indexed".into(),
|
||||||
|
)
|
||||||
|
.into_err(pos))
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr::CharConstant(_, pos)
|
||||||
| Expr::Assignment(_, _, pos)
|
| Expr::Assignment(_, _, pos)
|
||||||
| Expr::And(_, _, pos)
|
| Expr::And(_, _, pos)
|
||||||
| Expr::Or(_, _, pos)
|
| Expr::Or(_, _, pos)
|
||||||
@ -792,8 +812,16 @@ fn parse_index_chain<'a>(
|
|||||||
)
|
)
|
||||||
.into_err(*pos))
|
.into_err(*pos))
|
||||||
}
|
}
|
||||||
Expr::FloatConstant(_, pos)
|
|
||||||
| Expr::CharConstant(_, pos)
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Expr::FloatConstant(_, pos) => {
|
||||||
|
return Err(PERR::MalformedIndexExpr(
|
||||||
|
"Only arrays, object maps and strings can be indexed".into(),
|
||||||
|
)
|
||||||
|
.into_err(pos))
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr::CharConstant(_, pos)
|
||||||
| Expr::Assignment(_, _, pos)
|
| Expr::Assignment(_, _, pos)
|
||||||
| Expr::And(_, _, pos)
|
| Expr::And(_, _, pos)
|
||||||
| Expr::Or(_, _, pos)
|
| Expr::Or(_, _, pos)
|
||||||
@ -811,6 +839,7 @@ fn parse_index_chain<'a>(
|
|||||||
},
|
},
|
||||||
|
|
||||||
// lhs[float]
|
// lhs[float]
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
Expr::FloatConstant(_, pos) => {
|
Expr::FloatConstant(_, pos) => {
|
||||||
return Err(PERR::MalformedIndexExpr(
|
return Err(PERR::MalformedIndexExpr(
|
||||||
"Array access expects integer index, not a float".into(),
|
"Array access expects integer index, not a float".into(),
|
||||||
@ -1095,6 +1124,7 @@ fn parse_primary<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Indexing
|
// Indexing
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
(expr, Token::LeftBracket) => {
|
(expr, Token::LeftBracket) => {
|
||||||
parse_index_chain(input, stack, expr, token_pos, allow_stmt_expr)?
|
parse_index_chain(input, stack, expr, token_pos, allow_stmt_expr)?
|
||||||
}
|
}
|
||||||
@ -1280,7 +1310,6 @@ fn make_dot_expr(
|
|||||||
fn make_in_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, Box<ParseError>> {
|
fn make_in_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, Box<ParseError>> {
|
||||||
match (&lhs, &rhs) {
|
match (&lhs, &rhs) {
|
||||||
(_, Expr::IntegerConstant(_, pos))
|
(_, Expr::IntegerConstant(_, pos))
|
||||||
| (_, Expr::FloatConstant(_, pos))
|
|
||||||
| (_, Expr::And(_, _, pos))
|
| (_, Expr::And(_, _, pos))
|
||||||
| (_, Expr::Or(_, _, pos))
|
| (_, Expr::Or(_, _, pos))
|
||||||
| (_, Expr::In(_, _, pos))
|
| (_, Expr::In(_, _, pos))
|
||||||
@ -1294,11 +1323,20 @@ fn make_in_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, Box<Pars
|
|||||||
.into_err(*pos))
|
.into_err(*pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
(_, Expr::FloatConstant(_, pos)) => {
|
||||||
|
return Err(PERR::MalformedInExpr(
|
||||||
|
"'in' expression expects a string, array or object map".into(),
|
||||||
|
)
|
||||||
|
.into_err(*pos))
|
||||||
|
}
|
||||||
|
|
||||||
// "xxx" in "xxxx", 'x' in "xxxx" - OK!
|
// "xxx" in "xxxx", 'x' in "xxxx" - OK!
|
||||||
(Expr::StringConstant(_, _), Expr::StringConstant(_, _))
|
(Expr::StringConstant(_, _), Expr::StringConstant(_, _))
|
||||||
| (Expr::CharConstant(_, _), Expr::StringConstant(_, _)) => (),
|
| (Expr::CharConstant(_, _), Expr::StringConstant(_, _)) => (),
|
||||||
|
|
||||||
// 123.456 in "xxxx"
|
// 123.456 in "xxxx"
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
(Expr::FloatConstant(_, pos), Expr::StringConstant(_, _)) => {
|
(Expr::FloatConstant(_, pos), Expr::StringConstant(_, _)) => {
|
||||||
return Err(PERR::MalformedInExpr(
|
return Err(PERR::MalformedInExpr(
|
||||||
"'in' expression for a string expects a string, not a float".into(),
|
"'in' expression for a string expects a string, not a float".into(),
|
||||||
@ -1352,6 +1390,7 @@ fn make_in_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, Box<Pars
|
|||||||
| (Expr::CharConstant(_, _), Expr::Map(_, _)) => (),
|
| (Expr::CharConstant(_, _), Expr::Map(_, _)) => (),
|
||||||
|
|
||||||
// 123.456 in #{...}
|
// 123.456 in #{...}
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
(Expr::FloatConstant(_, pos), Expr::Map(_, _)) => {
|
(Expr::FloatConstant(_, pos), Expr::Map(_, _)) => {
|
||||||
return Err(PERR::MalformedInExpr(
|
return Err(PERR::MalformedInExpr(
|
||||||
"'in' expression for an object map expects a string, not a float".into(),
|
"'in' expression for an object map expects a string, not a float".into(),
|
||||||
@ -1975,6 +2014,7 @@ fn parse_stmt<'a>(
|
|||||||
Token::Let => parse_let(input, stack, ScopeEntryType::Normal, allow_stmt_expr),
|
Token::Let => parse_let(input, stack, ScopeEntryType::Normal, allow_stmt_expr),
|
||||||
Token::Const => parse_let(input, stack, ScopeEntryType::Constant, allow_stmt_expr),
|
Token::Const => parse_let(input, stack, ScopeEntryType::Constant, allow_stmt_expr),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
Token::Import => parse_import(input, stack, allow_stmt_expr),
|
Token::Import => parse_import(input, stack, allow_stmt_expr),
|
||||||
|
|
||||||
_ => parse_expr_stmt(input, stack, allow_stmt_expr),
|
_ => parse_expr_stmt(input, stack, allow_stmt_expr),
|
||||||
@ -2105,13 +2145,15 @@ fn parse_global_level<'a>(
|
|||||||
|
|
||||||
while !input.peek().unwrap().0.is_eof() {
|
while !input.peek().unwrap().0.is_eof() {
|
||||||
// Collect all the function definitions
|
// Collect all the function definitions
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
{
|
||||||
if let (Token::Fn, _) = input.peek().unwrap() {
|
if let (Token::Fn, _) = input.peek().unwrap() {
|
||||||
let mut stack = Stack::new();
|
let mut stack = Stack::new();
|
||||||
let f = parse_fn(input, &mut stack, true)?;
|
let f = parse_fn(input, &mut stack, true)?;
|
||||||
functions.insert(calc_fn_def(&f.name, f.params.len()), f);
|
functions.insert(calc_fn_def(&f.name, f.params.len()), f);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Actual statement
|
// Actual statement
|
||||||
let stmt = parse_stmt(input, &mut stack, false, true)?;
|
let stmt = parse_stmt(input, &mut stack, false, true)?;
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
//! 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::module::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;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
use crate::module::Module;
|
||||||
|
|
||||||
use crate::stdlib::{borrow::Cow, boxed::Box, iter, vec, vec::Vec};
|
use crate::stdlib::{borrow::Cow, boxed::Box, iter, vec, vec::Vec};
|
||||||
|
|
||||||
/// Type of an entry in the Scope.
|
/// Type of an entry in the Scope.
|
||||||
@ -172,6 +174,7 @@ impl<'a> Scope<'a> {
|
|||||||
/// Add (push) a new module to the Scope.
|
/// Add (push) a new module to the Scope.
|
||||||
///
|
///
|
||||||
/// Modules are used for accessing member variables, functions and plugins under a namespace.
|
/// Modules are used for accessing member variables, functions and plugins under a namespace.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub fn push_module<K: Into<Cow<'a, str>>>(&mut self, name: K, value: Module) {
|
pub fn push_module<K: Into<Cow<'a, str>>>(&mut self, name: K, value: Module) {
|
||||||
self.push_dynamic_value(
|
self.push_dynamic_value(
|
||||||
name,
|
name,
|
||||||
@ -340,6 +343,7 @@ impl<'a> Scope<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Find a module in the Scope, starting from the last entry.
|
/// Find a module in the Scope, starting from the last entry.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub fn find_module(&mut self, name: &str) -> Option<&mut Module> {
|
pub fn find_module(&mut self, name: &str) -> Option<&mut Module> {
|
||||||
let index = self.get_module_index(name)?;
|
let index = self.get_module_index(name)?;
|
||||||
self.get_mut(index).0.downcast_mut::<Module>()
|
self.get_mut(index).0.downcast_mut::<Module>()
|
||||||
|
Loading…
Reference in New Issue
Block a user