Change Dynamic to enum.
This commit is contained in:
parent
50a0f14bfc
commit
5152a40e93
23
README.md
23
README.md
@ -439,12 +439,10 @@ There is no easy way for Rust to decide, at run-time, what type the `Dynamic` va
|
|||||||
function and match against the name).
|
function and match against the name).
|
||||||
|
|
||||||
A `Dynamic` value's actual type can be checked via the `is` method.
|
A `Dynamic` value's actual type can be checked via the `is` method.
|
||||||
The `cast` method (from the `rhai::AnyExt` trait) then converts the value into a specific, known type.
|
The `cast` method then converts the value into a specific, known type.
|
||||||
Alternatively, use the `try_cast` method which does not panic but returns an error when the cast fails.
|
Alternatively, use the `try_cast` method which does not panic but returns an error when the cast fails.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use rhai::AnyExt; // pull in the trait.
|
|
||||||
|
|
||||||
let list: Array = engine.eval("...")?; // return type is 'Array'
|
let list: Array = engine.eval("...")?; // return type is 'Array'
|
||||||
let item = list[0]; // an element in an 'Array' is 'Dynamic'
|
let item = list[0]; // an element in an 'Array' is 'Dynamic'
|
||||||
|
|
||||||
@ -459,8 +457,6 @@ let value = item.try_cast::<i64>()?; // 'try_cast' does not panic whe
|
|||||||
The `type_name` method gets the name of the actual type as a static string slice, which you may match against.
|
The `type_name` method gets the name of the actual type as a static string slice, which you may match against.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use rhai::Any; // pull in the trait.
|
|
||||||
|
|
||||||
let list: Array = engine.eval("...")?; // return type is 'Array'
|
let list: Array = engine.eval("...")?; // return type is 'Array'
|
||||||
let item = list[0]; // an element in an 'Array' is 'Dynamic'
|
let item = list[0]; // an element in an 'Array' is 'Dynamic'
|
||||||
|
|
||||||
@ -499,8 +495,6 @@ A number of traits, under the `rhai::` module namespace, provide additional func
|
|||||||
|
|
||||||
| Trait | Description | Methods |
|
| Trait | Description | Methods |
|
||||||
| ------------------- | --------------------------------------------------------------------------------- | --------------------------------------- |
|
| ------------------- | --------------------------------------------------------------------------------- | --------------------------------------- |
|
||||||
| `Any` | Generic trait that represents a [`Dynamic`] type | `type_id`, `type_name`, `into_dynamic` |
|
|
||||||
| `AnyExt` | Extension trait to allows casting of a [`Dynamic`] value to Rust types | `cast`, `try_cast` |
|
|
||||||
| `RegisterFn` | Trait for registering functions | `register_fn` |
|
| `RegisterFn` | Trait for registering functions | `register_fn` |
|
||||||
| `RegisterDynamicFn` | Trait for registering functions returning [`Dynamic`] | `register_dynamic_fn` |
|
| `RegisterDynamicFn` | Trait for registering functions returning [`Dynamic`] | `register_dynamic_fn` |
|
||||||
| `RegisterResultFn` | Trait for registering fallible functions returning `Result<`_T_`, EvalAltResult>` | `register_result_fn` |
|
| `RegisterResultFn` | Trait for registering fallible functions returning `Result<`_T_`, EvalAltResult>` | `register_result_fn` |
|
||||||
@ -513,9 +507,9 @@ Rhai's scripting engine is very lightweight. It gets most of its abilities from
|
|||||||
To call these functions, they need to be registered with the [`Engine`].
|
To call these functions, they need to be registered with the [`Engine`].
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use rhai::{Engine, EvalAltResult};
|
use rhai::{Dynamic, Engine, EvalAltResult};
|
||||||
use rhai::RegisterFn; // use 'RegisterFn' trait for 'register_fn'
|
use rhai::RegisterFn; // use 'RegisterFn' trait for 'register_fn'
|
||||||
use rhai::{Any, Dynamic, RegisterDynamicFn}; // use 'RegisterDynamicFn' trait for 'register_dynamic_fn'
|
use rhai::{Dynamic, RegisterDynamicFn}; // use 'RegisterDynamicFn' trait for 'register_dynamic_fn'
|
||||||
|
|
||||||
// Normal function
|
// Normal function
|
||||||
fn add(x: i64, y: i64) -> i64 {
|
fn add(x: i64, y: i64) -> i64 {
|
||||||
@ -524,7 +518,7 @@ fn add(x: i64, y: i64) -> i64 {
|
|||||||
|
|
||||||
// Function that returns a Dynamic value
|
// Function that returns a Dynamic value
|
||||||
fn get_an_any() -> Dynamic {
|
fn get_an_any() -> Dynamic {
|
||||||
(42_i64).into_dynamic() // 'into_dynamic' is defined by the 'rhai::Any' trait
|
Dynamic::from(42_i64)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), EvalAltResult>
|
fn main() -> Result<(), EvalAltResult>
|
||||||
@ -548,17 +542,16 @@ fn main() -> Result<(), EvalAltResult>
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
To return a [`Dynamic`] value from a Rust function, use the `into_dynamic()` method
|
To return a [`Dynamic`] value from a Rust function, use the `Dynamic::from` method.
|
||||||
(under the `rhai::Any` trait) to convert it.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use rhai::Any; // pull in the trait
|
use rhai::Dynamic;
|
||||||
|
|
||||||
fn decide(yes_no: bool) -> Dynamic {
|
fn decide(yes_no: bool) -> Dynamic {
|
||||||
if yes_no {
|
if yes_no {
|
||||||
(42_i64).into_dynamic()
|
Dynamic::from(42_i64)
|
||||||
} else {
|
} else {
|
||||||
String::from("hello!").into_dynamic() // remember &str is not supported by Rhai
|
Dynamic::from(String::from("hello!")) // remember &str is not supported by Rhai
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
508
src/any.rs
508
src/any.rs
@ -1,70 +1,38 @@
|
|||||||
//! 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};
|
||||||
|
use crate::parser::INT;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
use crate::parser::FLOAT;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::{type_name, TypeId},
|
any::{type_name, Any, TypeId},
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
fmt,
|
fmt,
|
||||||
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An raw value of any type.
|
/// A trait to represent any type.
|
||||||
///
|
///
|
||||||
/// Currently, `Variant` is not `Send` nor `Sync`, so it can practically be any type.
|
/// Currently, `Variant` is not `Send` nor `Sync`, so it can practically be any type.
|
||||||
/// Turn on the `sync` feature to restrict it to only types that implement `Send + Sync`.
|
/// Turn on the `sync` feature to restrict it to only types that implement `Send + Sync`.
|
||||||
pub type Variant = dyn Any;
|
|
||||||
|
|
||||||
/// A boxed dynamic type containing any value.
|
|
||||||
///
|
|
||||||
/// Currently, `Dynamic` is not `Send` nor `Sync`, so it can practically be any type.
|
|
||||||
/// Turn on the `sync` feature to restrict it to only types that implement `Send + Sync`.
|
|
||||||
pub type Dynamic = Box<Variant>;
|
|
||||||
|
|
||||||
/// A trait covering any type.
|
|
||||||
#[cfg(feature = "sync")]
|
|
||||||
pub trait Any: crate::stdlib::any::Any + Send + Sync {
|
|
||||||
/// Get the `TypeId` of this type.
|
|
||||||
fn type_id(&self) -> TypeId;
|
|
||||||
|
|
||||||
/// Get the name of this type.
|
|
||||||
fn type_name(&self) -> &'static str;
|
|
||||||
|
|
||||||
/// Convert into `Dynamic`.
|
|
||||||
fn into_dynamic(&self) -> Dynamic;
|
|
||||||
|
|
||||||
/// This trait may only be implemented by `rhai`.
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn _closed(&self) -> _Private;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "sync")]
|
|
||||||
impl<T: crate::stdlib::any::Any + Clone + Send + Sync + ?Sized> Any for T {
|
|
||||||
fn type_id(&self) -> TypeId {
|
|
||||||
TypeId::of::<T>()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn type_name(&self) -> &'static str {
|
|
||||||
type_name::<T>()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_dynamic(&self) -> Dynamic {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _closed(&self) -> _Private {
|
|
||||||
_Private
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trait covering any type.
|
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
pub trait Any: crate::stdlib::any::Any {
|
pub trait Variant: Any {
|
||||||
/// Get the `TypeId` of this type.
|
/// Convert this `Variant` trait object to `&dyn Any`.
|
||||||
fn type_id(&self) -> TypeId;
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
|
/// Convert this `Variant` trait object to `&mut dyn Any`.
|
||||||
|
fn as_mut_any(&mut self) -> &mut dyn Any;
|
||||||
|
|
||||||
/// Get the name of this type.
|
/// Get the name of this type.
|
||||||
fn type_name(&self) -> &'static str;
|
fn type_name(&self) -> &'static str;
|
||||||
|
|
||||||
/// Convert into `Dynamic`.
|
/// Convert into `Dynamic`.
|
||||||
fn into_dynamic(&self) -> Dynamic;
|
fn into_dynamic(self) -> Dynamic;
|
||||||
|
|
||||||
|
/// Clone into `Dynamic`.
|
||||||
|
fn clone_into_dynamic(&self) -> Dynamic;
|
||||||
|
|
||||||
/// This trait may only be implemented by `rhai`.
|
/// This trait may only be implemented by `rhai`.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -72,101 +40,312 @@ pub trait Any: crate::stdlib::any::Any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
impl<T: crate::stdlib::any::Any + Clone + ?Sized> Any for T {
|
impl<T: Any + Clone> Variant for T {
|
||||||
fn type_id(&self) -> TypeId {
|
fn as_any(&self) -> &dyn Any {
|
||||||
TypeId::of::<T>()
|
self as &dyn Any
|
||||||
|
}
|
||||||
|
fn as_mut_any(&mut self) -> &mut dyn Any {
|
||||||
|
self as &mut dyn Any
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_name(&self) -> &'static str {
|
fn type_name(&self) -> &'static str {
|
||||||
type_name::<T>()
|
type_name::<T>()
|
||||||
}
|
}
|
||||||
|
fn into_dynamic(self) -> Dynamic {
|
||||||
fn into_dynamic(&self) -> Dynamic {
|
Dynamic::from(self)
|
||||||
Box::new(self.clone())
|
}
|
||||||
|
fn clone_into_dynamic(&self) -> Dynamic {
|
||||||
|
Dynamic::from(self.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _closed(&self) -> _Private {
|
fn _closed(&self) -> _Private {
|
||||||
_Private
|
_Private
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Variant {
|
/// A trait to represent any type.
|
||||||
|
#[cfg(feature = "sync")]
|
||||||
|
pub trait Variant: Any + Send + Sync {
|
||||||
|
/// Convert this `Variant` trait object to `&dyn Any`.
|
||||||
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
|
/// Convert this `Variant` trait object to `&mut dyn Any`.
|
||||||
|
fn as_mut_any(&mut self) -> &mut dyn Any;
|
||||||
|
|
||||||
|
/// Get the name of this type.
|
||||||
|
fn type_name(&self) -> &'static str;
|
||||||
|
|
||||||
|
/// Convert into `Dynamic`.
|
||||||
|
fn into_dynamic(self) -> Dynamic;
|
||||||
|
|
||||||
|
/// Clone into `Dynamic`.
|
||||||
|
fn clone_into_dynamic(&self) -> Dynamic;
|
||||||
|
|
||||||
|
/// This trait may only be implemented by `rhai`.
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn _closed(&self) -> _Private;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "sync")]
|
||||||
|
impl<T: Any + Clone + Send + Sync> Variant for T {
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self as &dyn Any
|
||||||
|
}
|
||||||
|
fn as_mut_any(&mut self) -> &mut dyn Any {
|
||||||
|
self as &mut dyn Any
|
||||||
|
}
|
||||||
|
fn type_name(&self) -> &'static str {
|
||||||
|
type_name::<T>()
|
||||||
|
}
|
||||||
|
fn into_dynamic(self) -> Dynamic {
|
||||||
|
Dynamic::from(self)
|
||||||
|
}
|
||||||
|
fn clone_into_dynamic(&self) -> Dynamic {
|
||||||
|
Dynamic::from(self.clone())
|
||||||
|
}
|
||||||
|
fn _closed(&self) -> _Private {
|
||||||
|
_Private
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl dyn Variant {
|
||||||
/// Is this `Variant` a specific type?
|
/// Is this `Variant` a specific type?
|
||||||
pub fn is<T: Any>(&self) -> bool {
|
pub fn is<T: Any>(&self) -> bool {
|
||||||
TypeId::of::<T>() == <Variant as Any>::type_id(self)
|
TypeId::of::<T>() == self.type_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference of a specific type to the `Variant`.
|
/// Get a reference of a specific type to the `Variant`.
|
||||||
/// Returns `None` if the cast fails.
|
/// Returns `None` if the cast fails.
|
||||||
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
|
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
|
||||||
if self.is::<T>() {
|
Any::downcast_ref::<T>(self.as_any())
|
||||||
unsafe { Some(&*(self as *const Variant as *const T)) }
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a mutable reference of a specific type to the `Variant`.
|
/// Get a mutable reference of a specific type to the `Variant`.
|
||||||
/// Returns `None` if the cast fails.
|
/// Returns `None` if the cast fails.
|
||||||
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
|
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
|
||||||
if self.is::<T>() {
|
Any::downcast_mut::<T>(self.as_mut_any())
|
||||||
unsafe { Some(&mut *(self as *mut Variant as *mut T)) }
|
}
|
||||||
} else {
|
}
|
||||||
None
|
|
||||||
|
/// A dynamic type containing any value.
|
||||||
|
pub struct Dynamic(pub(crate) Union);
|
||||||
|
|
||||||
|
/// Internal `Dynamic` representation.
|
||||||
|
pub enum Union {
|
||||||
|
Unit(()),
|
||||||
|
Bool(bool),
|
||||||
|
Str(String),
|
||||||
|
Char(char),
|
||||||
|
Int(INT),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Float(FLOAT),
|
||||||
|
Array(Array),
|
||||||
|
Map(Box<Map>), // Box it to reduce size
|
||||||
|
Variant(Box<dyn Variant>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dynamic {
|
||||||
|
/// Is the value held by this `Dynamic` a particular type?
|
||||||
|
pub fn is<T: Variant + Clone>(&self) -> bool {
|
||||||
|
self.type_id() == TypeId::of::<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the TypeId of the value held by this `Dynamic`.
|
||||||
|
pub fn type_id(&self) -> TypeId {
|
||||||
|
match &self.0 {
|
||||||
|
Union::Unit(_) => TypeId::of::<()>(),
|
||||||
|
Union::Bool(_) => TypeId::of::<bool>(),
|
||||||
|
Union::Str(_) => TypeId::of::<String>(),
|
||||||
|
Union::Char(_) => TypeId::of::<char>(),
|
||||||
|
Union::Int(_) => TypeId::of::<INT>(),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Union::Float(_) => TypeId::of::<FLOAT>(),
|
||||||
|
Union::Array(_) => TypeId::of::<Array>(),
|
||||||
|
Union::Map(_) => TypeId::of::<Map>(),
|
||||||
|
Union::Variant(value) => (**value).type_id(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the name of the type of the value held by this `Dynamic`.
|
||||||
|
pub fn type_name(&self) -> &'static str {
|
||||||
|
match &self.0 {
|
||||||
|
Union::Unit(_) => "()",
|
||||||
|
Union::Bool(_) => "bool",
|
||||||
|
Union::Str(_) => "string",
|
||||||
|
Union::Char(_) => "char",
|
||||||
|
Union::Int(_) => type_name::<INT>(),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Union::Float(_) => type_name::<FLOAT>(),
|
||||||
|
Union::Array(_) => "array",
|
||||||
|
Union::Map(_) => "map",
|
||||||
|
|
||||||
|
Union::Variant(value) if value.is::<Instant>() => "timestamp",
|
||||||
|
Union::Variant(value) => (**value).type_name(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Variant {
|
impl fmt::Display for Dynamic {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.pad("?")
|
match &self.0 {
|
||||||
|
Union::Unit(_) => write!(f, ""),
|
||||||
|
Union::Bool(value) => write!(f, "{}", value),
|
||||||
|
Union::Str(value) => write!(f, "{}", value),
|
||||||
|
Union::Char(value) => write!(f, "{}", value),
|
||||||
|
Union::Int(value) => write!(f, "{}", value),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Union::Float(value) => write!(f, "{}", value),
|
||||||
|
Union::Array(value) => write!(f, "{:?}", value),
|
||||||
|
Union::Map(value) => write!(f, "{:?}", value),
|
||||||
|
Union::Variant(_) => write!(f, "?"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Dynamic {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match &self.0 {
|
||||||
|
Union::Unit(value) => write!(f, "{:?}", value),
|
||||||
|
Union::Bool(value) => write!(f, "{:?}", value),
|
||||||
|
Union::Str(value) => write!(f, "{:?}", value),
|
||||||
|
Union::Char(value) => write!(f, "{:?}", value),
|
||||||
|
Union::Int(value) => write!(f, "{:?}", value),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Union::Float(value) => write!(f, "{:?}", value),
|
||||||
|
Union::Array(value) => write!(f, "{:?}", value),
|
||||||
|
Union::Map(value) => write!(f, "{:?}", value),
|
||||||
|
Union::Variant(_) => write!(f, "?"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Dynamic {
|
impl Clone for Dynamic {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
self.as_ref().into_dynamic()
|
match &self.0 {
|
||||||
|
Union::Unit(value) => Self(Union::Unit(value.clone())),
|
||||||
|
Union::Bool(value) => Self(Union::Bool(value.clone())),
|
||||||
|
Union::Str(value) => Self(Union::Str(value.clone())),
|
||||||
|
Union::Char(value) => Self(Union::Char(value.clone())),
|
||||||
|
Union::Int(value) => Self(Union::Int(value.clone())),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Union::Float(value) => Self(Union::Float(value.clone())),
|
||||||
|
Union::Array(value) => Self(Union::Array(value.clone())),
|
||||||
|
Union::Map(value) => Self(Union::Map(value.clone())),
|
||||||
|
Union::Variant(value) => (**value).clone_into_dynamic(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An extension trait that allows down-casting a `Dynamic` value to a specific type.
|
impl Dynamic {
|
||||||
pub trait AnyExt: Sized {
|
/// Create a `Dynamic` from any type.
|
||||||
/// Get a copy of a `Dynamic` value as a specific type.
|
|
||||||
fn try_cast<T: Any + Clone>(self) -> Result<T, Self>;
|
|
||||||
|
|
||||||
/// Get a copy of a `Dynamic` value as a specific type.
|
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Panics if the cast fails (e.g. the type of the actual value is not the same as the specified type).
|
/// ```
|
||||||
fn cast<T: Any + Clone>(self) -> T;
|
/// use rhai::Dynamic;
|
||||||
|
///
|
||||||
|
/// let result = Dynamic::from(42_i64);
|
||||||
|
/// assert_eq!(result.type_name(), "i64");
|
||||||
|
/// assert_eq!(result.to_string(), "42");
|
||||||
|
///
|
||||||
|
/// let result = Dynamic::from("hello".to_string());
|
||||||
|
/// assert_eq!(result.type_name(), "string");
|
||||||
|
/// assert_eq!(result.to_string(), "hello");
|
||||||
|
/// ```
|
||||||
|
pub fn from<T: Variant + Clone>(value: T) -> Self {
|
||||||
|
if let Some(result) = (&value as &dyn Variant)
|
||||||
|
.downcast_ref::<()>()
|
||||||
|
.cloned()
|
||||||
|
.map(Union::Unit)
|
||||||
|
.or_else(|| {
|
||||||
|
(&value as &dyn Variant)
|
||||||
|
.downcast_ref::<bool>()
|
||||||
|
.cloned()
|
||||||
|
.map(Union::Bool)
|
||||||
|
.or_else(|| {
|
||||||
|
(&value as &dyn Variant)
|
||||||
|
.downcast_ref::<INT>()
|
||||||
|
.cloned()
|
||||||
|
.map(Union::Int)
|
||||||
|
.or_else(|| {
|
||||||
|
(&value as &dyn Variant)
|
||||||
|
.downcast_ref::<char>()
|
||||||
|
.cloned()
|
||||||
|
.map(Union::Char)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
{
|
||||||
|
return Self(result);
|
||||||
|
}
|
||||||
|
|
||||||
/// This trait may only be implemented by `rhai`.
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[doc(hidden)]
|
{
|
||||||
fn _closed(&self) -> _Private;
|
if let Some(result) = (&value as &dyn Variant)
|
||||||
}
|
.downcast_ref::<char>()
|
||||||
|
.cloned()
|
||||||
|
.map(Union::Char)
|
||||||
|
{
|
||||||
|
return Self(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cast_box<X: Variant, T: Variant>(item: Box<X>) -> Result<T, Box<X>> {
|
||||||
|
if TypeId::of::<X>() == TypeId::of::<T>() {
|
||||||
|
unsafe {
|
||||||
|
let raw: *mut dyn Any = Box::into_raw(item as Box<dyn Any>);
|
||||||
|
Ok(*Box::from_raw(raw as *mut T))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let var = Box::new(value);
|
||||||
|
|
||||||
|
Self(
|
||||||
|
cast_box::<_, String>(var)
|
||||||
|
.map(Union::Str)
|
||||||
|
.or_else(|var| {
|
||||||
|
cast_box::<_, Array>(var).map(Union::Array).or_else(|var| {
|
||||||
|
cast_box::<_, Map>(var)
|
||||||
|
.map(|v| Union::Map(Box::new(v)))
|
||||||
|
.or_else(|var| -> Result<Union, ()> {
|
||||||
|
Ok(Union::Variant(var as Box<dyn Variant>))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
impl AnyExt for Dynamic {
|
|
||||||
/// Get a copy of the `Dynamic` value as a specific type.
|
/// Get a copy of the `Dynamic` value as a specific type.
|
||||||
///
|
///
|
||||||
|
/// Returns an error with the name of the value's actual type when the cast fails.
|
||||||
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use rhai::{Dynamic, Any, AnyExt};
|
/// use rhai::Dynamic;
|
||||||
///
|
///
|
||||||
/// let x: Dynamic = 42_u32.into_dynamic();
|
/// let x = Dynamic::from(42_u32);
|
||||||
///
|
///
|
||||||
/// assert_eq!(x.try_cast::<u32>().unwrap(), 42);
|
/// assert_eq!(x.try_cast::<u32>().unwrap(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
fn try_cast<T: Any + Clone>(self) -> Result<T, Self> {
|
pub fn try_cast<T: Variant + Clone>(self) -> Result<T, Self> {
|
||||||
if self.is::<T>() {
|
match &self.0 {
|
||||||
unsafe {
|
Union::Unit(value) => (value as &dyn Variant).downcast_ref::<T>().cloned(),
|
||||||
let raw: *mut Variant = Box::into_raw(self);
|
Union::Bool(value) => (value as &dyn Variant).downcast_ref::<T>().cloned(),
|
||||||
Ok(*Box::from_raw(raw as *mut T))
|
Union::Str(value) => (value as &dyn Variant).downcast_ref::<T>().cloned(),
|
||||||
}
|
Union::Char(value) => (value as &dyn Variant).downcast_ref::<T>().cloned(),
|
||||||
} else {
|
Union::Int(value) => (value as &dyn Variant).downcast_ref::<T>().cloned(),
|
||||||
Err(self)
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Union::Float(value) => (value as &dyn Variant).downcast_ref::<T>().cloned(),
|
||||||
|
Union::Array(value) => (value as &dyn Variant).downcast_ref::<T>().cloned(),
|
||||||
|
Union::Map(value) => (value.as_ref() as &dyn Variant)
|
||||||
|
.downcast_ref::<T>()
|
||||||
|
.cloned(),
|
||||||
|
Union::Variant(value) => value.as_ref().downcast_ref::<T>().cloned(),
|
||||||
}
|
}
|
||||||
|
.ok_or(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a copy of the `Dynamic` value as a specific type.
|
/// Get a copy of the `Dynamic` value as a specific type.
|
||||||
@ -178,18 +357,141 @@ impl AnyExt for Dynamic {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use rhai::{Dynamic, Any, AnyExt};
|
/// use rhai::Dynamic;
|
||||||
///
|
///
|
||||||
/// let x: Dynamic = 42_u32.into_dynamic();
|
/// let x = Dynamic::from(42_u32);
|
||||||
///
|
///
|
||||||
/// assert_eq!(x.cast::<u32>(), 42);
|
/// assert_eq!(x.cast::<u32>(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
fn cast<T: Any + Clone>(self) -> T {
|
pub fn cast<T: Variant + Clone>(self) -> T {
|
||||||
self.try_cast::<T>().expect("cast failed")
|
self.try_cast::<T>().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _closed(&self) -> _Private {
|
/// Get a reference of a specific type to the `Dynamic`.
|
||||||
_Private
|
/// Returns `None` if the cast fails.
|
||||||
|
pub fn downcast_ref<T: Variant + Clone>(&self) -> Option<&T> {
|
||||||
|
match &self.0 {
|
||||||
|
Union::Unit(value) => (value as &dyn Variant).downcast_ref::<T>(),
|
||||||
|
Union::Bool(value) => (value as &dyn Variant).downcast_ref::<T>(),
|
||||||
|
Union::Str(value) => (value as &dyn Variant).downcast_ref::<T>(),
|
||||||
|
Union::Char(value) => (value as &dyn Variant).downcast_ref::<T>(),
|
||||||
|
Union::Int(value) => (value as &dyn Variant).downcast_ref::<T>(),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Union::Float(value) => (value as &dyn Variant).downcast_ref::<T>(),
|
||||||
|
Union::Array(value) => (value as &dyn Variant).downcast_ref::<T>(),
|
||||||
|
Union::Map(value) => (value.as_ref() as &dyn Variant).downcast_ref::<T>(),
|
||||||
|
Union::Variant(value) => value.as_ref().downcast_ref::<T>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a mutable reference of a specific type to the `Dynamic`.
|
||||||
|
/// Returns `None` if the cast fails.
|
||||||
|
pub fn downcast_mut<T: Variant + Clone>(&mut self) -> Option<&mut T> {
|
||||||
|
match &mut self.0 {
|
||||||
|
Union::Unit(value) => (value as &mut dyn Variant).downcast_mut::<T>(),
|
||||||
|
Union::Bool(value) => (value as &mut dyn Variant).downcast_mut::<T>(),
|
||||||
|
Union::Str(value) => (value as &mut dyn Variant).downcast_mut::<T>(),
|
||||||
|
Union::Char(value) => (value as &mut dyn Variant).downcast_mut::<T>(),
|
||||||
|
Union::Int(value) => (value as &mut dyn Variant).downcast_mut::<T>(),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Union::Float(value) => (value as &mut dyn Variant).downcast_mut::<T>(),
|
||||||
|
Union::Array(value) => (value as &mut dyn Variant).downcast_mut::<T>(),
|
||||||
|
Union::Map(value) => (value.as_mut() as &mut dyn Variant).downcast_mut::<T>(),
|
||||||
|
Union::Variant(value) => value.as_mut().downcast_mut::<T>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cast the `Dynamic` as the system integer type `INT` and return it.
|
||||||
|
/// Returns the name of the actual type if the cast fails.
|
||||||
|
pub(crate) fn as_int(&self) -> Result<INT, &'static str> {
|
||||||
|
match self.0 {
|
||||||
|
Union::Int(n) => Ok(n),
|
||||||
|
_ => Err(self.type_name()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cast the `Dynamic` as the system integer type `INT` and return it.
|
||||||
|
/// Returns the name of the actual type if the cast fails.
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
pub(crate) fn as_float(&self) -> Result<FLOAT, &'static str> {
|
||||||
|
match self.0 {
|
||||||
|
Union::Float(n) => Ok(n),
|
||||||
|
_ => Err(self.type_name()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cast the `Dynamic` as a `bool` and return it.
|
||||||
|
/// Returns the name of the actual type if the cast fails.
|
||||||
|
pub(crate) fn as_bool(&self) -> Result<bool, &'static str> {
|
||||||
|
match self.0 {
|
||||||
|
Union::Bool(b) => Ok(b),
|
||||||
|
_ => Err(self.type_name()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cast the `Dynamic` as a `char` and return it.
|
||||||
|
/// Returns the name of the actual type if the cast fails.
|
||||||
|
pub(crate) fn as_char(&self) -> Result<char, &'static str> {
|
||||||
|
match self.0 {
|
||||||
|
Union::Char(n) => Ok(n),
|
||||||
|
_ => Err(self.type_name()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cast the `Dynamic` as a string and return the string slice.
|
||||||
|
/// Returns the name of the actual type if the cast fails.
|
||||||
|
pub(crate) fn as_str(&self) -> Result<&str, &'static str> {
|
||||||
|
match &self.0 {
|
||||||
|
Union::Str(s) => Ok(s),
|
||||||
|
_ => Err(self.type_name()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the `Dynamic` into `String` and return it.
|
||||||
|
/// Returns the name of the actual type if the cast fails.
|
||||||
|
pub(crate) fn take_string(self) -> Result<String, &'static str> {
|
||||||
|
match self.0 {
|
||||||
|
Union::Str(s) => Ok(s),
|
||||||
|
_ => Err(self.type_name()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cast the `Dynamic` as an `Array` and return a reference to it.
|
||||||
|
/// Returns the name of the actual type if the cast fails.
|
||||||
|
pub(crate) fn as_array(&self) -> Result<&Array, &'static str> {
|
||||||
|
match &self.0 {
|
||||||
|
Union::Array(array) => Ok(array),
|
||||||
|
_ => Err(self.type_name()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cast the `Dynamic` as a `Map` and return a reference to it.
|
||||||
|
/// Returns the name of the actual type if the cast fails.
|
||||||
|
pub(crate) fn as_map(&self) -> Result<&Map, &'static str> {
|
||||||
|
match &self.0 {
|
||||||
|
Union::Map(map) => Ok(map),
|
||||||
|
_ => Err(self.type_name()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_unit() -> Self {
|
||||||
|
Self(Union::Unit(()))
|
||||||
|
}
|
||||||
|
pub(crate) fn from_bool(value: bool) -> Self {
|
||||||
|
Self(Union::Bool(value))
|
||||||
|
}
|
||||||
|
pub(crate) fn from_int(value: INT) -> Self {
|
||||||
|
Self(Union::Int(value))
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
pub(crate) fn from_float(value: FLOAT) -> Self {
|
||||||
|
Self(Union::Float(value))
|
||||||
|
}
|
||||||
|
pub(crate) fn from_char(value: char) -> Self {
|
||||||
|
Self(Union::Char(value))
|
||||||
|
}
|
||||||
|
pub(crate) fn from_string(value: String) -> Self {
|
||||||
|
Self(Union::Str(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
50
src/api.rs
50
src/api.rs
@ -1,6 +1,6 @@
|
|||||||
//! Module that defines the extern API of `Engine`.
|
//! Module that defines the extern API of `Engine`.
|
||||||
|
|
||||||
use crate::any::{Any, AnyExt, Dynamic};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::engine::{make_getter, make_setter, Engine, FnAny, FnSpec, Map};
|
use crate::engine::{make_getter, make_setter, Engine, FnAny, FnSpec, Map};
|
||||||
use crate::error::ParseError;
|
use crate::error::ParseError;
|
||||||
use crate::fn_call::FuncArgs;
|
use crate::fn_call::FuncArgs;
|
||||||
@ -109,7 +109,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub fn register_type<T: Any + Clone>(&mut self) {
|
pub fn register_type<T: Variant + Clone>(&mut self) {
|
||||||
self.register_type_with_name::<T>(type_name::<T>());
|
self.register_type_with_name::<T>(type_name::<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub fn register_type_with_name<T: Any + Clone>(&mut self, name: &str) {
|
pub fn register_type_with_name<T: Variant + Clone>(&mut self, name: &str) {
|
||||||
if self.type_names.is_none() {
|
if self.type_names.is_none() {
|
||||||
self.type_names = Some(HashMap::new());
|
self.type_names = Some(HashMap::new());
|
||||||
}
|
}
|
||||||
@ -171,7 +171,7 @@ impl<'e> Engine<'e> {
|
|||||||
|
|
||||||
/// Register an iterator adapter for a type with the `Engine`.
|
/// Register an iterator adapter for a type with the `Engine`.
|
||||||
/// This is an advanced feature.
|
/// This is an advanced feature.
|
||||||
pub fn register_iterator<T: Any, F: IteratorCallback>(&mut self, f: F) {
|
pub fn register_iterator<T: Variant + Clone, F: IteratorCallback>(&mut self, f: F) {
|
||||||
if self.type_iterators.is_none() {
|
if self.type_iterators.is_none() {
|
||||||
self.type_iterators = Some(HashMap::new());
|
self.type_iterators = Some(HashMap::new());
|
||||||
}
|
}
|
||||||
@ -221,8 +221,8 @@ impl<'e> Engine<'e> {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub fn register_get<T, U, F>(&mut self, name: &str, callback: F)
|
pub fn register_get<T, U, F>(&mut self, name: &str, callback: F)
|
||||||
where
|
where
|
||||||
T: Any + Clone,
|
T: Variant + Clone,
|
||||||
U: Any + Clone,
|
U: Variant + Clone,
|
||||||
F: ObjectGetCallback<T, U>,
|
F: ObjectGetCallback<T, U>,
|
||||||
{
|
{
|
||||||
self.register_fn(&make_getter(name), callback);
|
self.register_fn(&make_getter(name), callback);
|
||||||
@ -267,8 +267,8 @@ impl<'e> Engine<'e> {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub fn register_set<T, U, F>(&mut self, name: &str, callback: F)
|
pub fn register_set<T, U, F>(&mut self, name: &str, callback: F)
|
||||||
where
|
where
|
||||||
T: Any + Clone,
|
T: Variant + Clone,
|
||||||
U: Any + Clone,
|
U: Variant + Clone,
|
||||||
F: ObjectSetCallback<T, U>,
|
F: ObjectSetCallback<T, U>,
|
||||||
{
|
{
|
||||||
self.register_fn(&make_setter(name), callback);
|
self.register_fn(&make_setter(name), callback);
|
||||||
@ -315,8 +315,8 @@ impl<'e> Engine<'e> {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub fn register_get_set<T, U, G, S>(&mut self, name: &str, get_fn: G, set_fn: S)
|
pub fn register_get_set<T, U, G, S>(&mut self, name: &str, get_fn: G, set_fn: S)
|
||||||
where
|
where
|
||||||
T: Any + Clone,
|
T: Variant + Clone,
|
||||||
U: Any + Clone,
|
U: Variant + Clone,
|
||||||
G: ObjectGetCallback<T, U>,
|
G: ObjectGetCallback<T, U>,
|
||||||
S: ObjectSetCallback<T, U>,
|
S: ObjectSetCallback<T, U>,
|
||||||
{
|
{
|
||||||
@ -487,7 +487,7 @@ impl<'e> Engine<'e> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
/// # fn main() -> Result<(), rhai::EvalAltResult> {
|
||||||
/// use rhai::{Engine, AnyExt};
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
///
|
///
|
||||||
@ -612,7 +612,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
pub fn eval_file<T: Any + Clone>(&self, path: PathBuf) -> Result<T, EvalAltResult> {
|
pub fn eval_file<T: Variant + Clone>(&self, path: PathBuf) -> Result<T, EvalAltResult> {
|
||||||
Self::read_file(path).and_then(|contents| self.eval::<T>(&contents))
|
Self::read_file(path).and_then(|contents| self.eval::<T>(&contents))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -636,7 +636,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
pub fn eval_file_with_scope<T: Any + Clone>(
|
pub fn eval_file_with_scope<T: Variant + Clone>(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
@ -658,7 +658,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn eval<T: Any + Clone>(&self, script: &str) -> Result<T, EvalAltResult> {
|
pub fn eval<T: Variant + Clone>(&self, script: &str) -> Result<T, EvalAltResult> {
|
||||||
self.eval_with_scope(&mut Scope::new(), script)
|
self.eval_with_scope(&mut Scope::new(), script)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -684,7 +684,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn eval_with_scope<T: Any + Clone>(
|
pub fn eval_with_scope<T: Variant + Clone>(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
script: &str,
|
script: &str,
|
||||||
@ -709,7 +709,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn eval_expression<T: Any + Clone>(&self, script: &str) -> Result<T, EvalAltResult> {
|
pub fn eval_expression<T: Variant + Clone>(&self, script: &str) -> Result<T, EvalAltResult> {
|
||||||
self.eval_expression_with_scope(&mut Scope::new(), script)
|
self.eval_expression_with_scope(&mut Scope::new(), script)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -731,7 +731,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn eval_expression_with_scope<T: Any + Clone>(
|
pub fn eval_expression_with_scope<T: Variant + Clone>(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
script: &str,
|
script: &str,
|
||||||
@ -761,7 +761,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn eval_ast<T: Any + Clone>(&self, ast: &AST) -> Result<T, EvalAltResult> {
|
pub fn eval_ast<T: Variant + Clone>(&self, ast: &AST) -> Result<T, EvalAltResult> {
|
||||||
self.eval_ast_with_scope(&mut Scope::new(), ast)
|
self.eval_ast_with_scope(&mut Scope::new(), ast)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,7 +794,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn eval_ast_with_scope<T: Any + Clone>(
|
pub fn eval_ast_with_scope<T: Variant + Clone>(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
@ -803,7 +803,7 @@ impl<'e> Engine<'e> {
|
|||||||
.try_cast::<T>()
|
.try_cast::<T>()
|
||||||
.map_err(|a| {
|
.map_err(|a| {
|
||||||
EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
self.map_type_name((*a).type_name()).to_string(),
|
self.map_type_name(a.type_name()).to_string(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -816,7 +816,7 @@ impl<'e> Engine<'e> {
|
|||||||
) -> Result<Dynamic, EvalAltResult> {
|
) -> Result<Dynamic, EvalAltResult> {
|
||||||
ast.0
|
ast.0
|
||||||
.iter()
|
.iter()
|
||||||
.try_fold(().into_dynamic(), |_, stmt| {
|
.try_fold(Dynamic::from_unit(), |_, stmt| {
|
||||||
self.eval_stmt(scope, Some(ast.1.as_ref()), stmt, 0)
|
self.eval_stmt(scope, Some(ast.1.as_ref()), stmt, 0)
|
||||||
})
|
})
|
||||||
.or_else(|err| match err {
|
.or_else(|err| match err {
|
||||||
@ -875,7 +875,7 @@ impl<'e> Engine<'e> {
|
|||||||
) -> Result<(), EvalAltResult> {
|
) -> Result<(), EvalAltResult> {
|
||||||
ast.0
|
ast.0
|
||||||
.iter()
|
.iter()
|
||||||
.try_fold(().into_dynamic(), |_, stmt| {
|
.try_fold(Dynamic::from_unit(), |_, stmt| {
|
||||||
self.eval_stmt(scope, Some(ast.1.as_ref()), stmt, 0)
|
self.eval_stmt(scope, Some(ast.1.as_ref()), stmt, 0)
|
||||||
})
|
})
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
@ -921,7 +921,7 @@ impl<'e> Engine<'e> {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub fn call_fn<A: FuncArgs, T: Any + Clone>(
|
pub fn call_fn<A: FuncArgs, T: Variant + Clone>(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
@ -929,7 +929,7 @@ impl<'e> Engine<'e> {
|
|||||||
args: A,
|
args: A,
|
||||||
) -> Result<T, EvalAltResult> {
|
) -> Result<T, EvalAltResult> {
|
||||||
let mut arg_values = args.into_vec();
|
let mut arg_values = args.into_vec();
|
||||||
let mut args: Vec<_> = arg_values.iter_mut().map(Dynamic::as_mut).collect();
|
let mut args: Vec<_> = arg_values.iter_mut().collect();
|
||||||
let fn_lib = Some(ast.1.as_ref());
|
let fn_lib = Some(ast.1.as_ref());
|
||||||
let pos = Position::none();
|
let pos = Position::none();
|
||||||
|
|
||||||
@ -937,7 +937,7 @@ impl<'e> Engine<'e> {
|
|||||||
.try_cast()
|
.try_cast()
|
||||||
.map_err(|a| {
|
.map_err(|a| {
|
||||||
EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
self.map_type_name((*a).type_name()).into(),
|
self.map_type_name(a.type_name()).into(),
|
||||||
pos,
|
pos,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Helper module that allows registration of the _core library_ and
|
//! Helper module that allows registration of the _core library_ and
|
||||||
//! _standard library_ of utility functions.
|
//! _standard library_ of utility functions.
|
||||||
|
|
||||||
use crate::any::{Any, Dynamic};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::engine::{Engine, FUNC_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT};
|
use crate::engine::{Engine, FUNC_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT};
|
||||||
use crate::fn_register::{RegisterDynamicFn, RegisterFn, RegisterResultFn};
|
use crate::fn_register::{RegisterDynamicFn, RegisterFn, RegisterResultFn};
|
||||||
use crate::parser::{Position, INT};
|
use crate::parser::{Position, INT};
|
||||||
@ -628,8 +628,8 @@ impl Engine<'_> {
|
|||||||
// Register map access functions
|
// Register map access functions
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
self.register_fn("keys", |map: Map| {
|
self.register_fn("keys", |map: Map| {
|
||||||
map.into_iter()
|
map.iter()
|
||||||
.map(|(k, _)| k.into_dynamic())
|
.map(|(k, _)| Dynamic::from(k.clone()))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -641,15 +641,16 @@ impl Engine<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register range function
|
// Register range function
|
||||||
fn reg_range<T: Any + Clone>(engine: &mut Engine)
|
fn reg_range<T: Variant + Clone>(engine: &mut Engine)
|
||||||
where
|
where
|
||||||
Range<T>: Iterator<Item = T>,
|
Range<T>: Iterator<Item = T>,
|
||||||
{
|
{
|
||||||
engine.register_iterator::<Range<T>, _>(|a: &Dynamic| {
|
engine.register_iterator::<Range<T>, _>(|source: &Dynamic| {
|
||||||
Box::new(
|
Box::new(
|
||||||
a.downcast_ref::<Range<T>>()
|
source
|
||||||
|
.downcast_ref::<Range<T>>()
|
||||||
|
.cloned()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone()
|
|
||||||
.map(|x| x.into_dynamic()),
|
.map(|x| x.into_dynamic()),
|
||||||
) as Box<dyn Iterator<Item = Dynamic>>
|
) as Box<dyn Iterator<Item = Dynamic>>
|
||||||
});
|
});
|
||||||
@ -678,12 +679,12 @@ impl Engine<'_> {
|
|||||||
struct StepRange<T>(T, T, T)
|
struct StepRange<T>(T, T, T)
|
||||||
where
|
where
|
||||||
for<'a> &'a T: Add<&'a T, Output = T>,
|
for<'a> &'a T: Add<&'a T, Output = T>,
|
||||||
T: Any + Clone + PartialOrd;
|
T: Variant + Clone + PartialOrd;
|
||||||
|
|
||||||
impl<T> Iterator for StepRange<T>
|
impl<T> Iterator for StepRange<T>
|
||||||
where
|
where
|
||||||
for<'a> &'a T: Add<&'a T, Output = T>,
|
for<'a> &'a T: Add<&'a T, Output = T>,
|
||||||
T: Any + Clone + PartialOrd,
|
T: Variant + Clone + PartialOrd,
|
||||||
{
|
{
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
@ -701,14 +702,15 @@ impl Engine<'_> {
|
|||||||
fn reg_step<T>(engine: &mut Engine)
|
fn reg_step<T>(engine: &mut Engine)
|
||||||
where
|
where
|
||||||
for<'a> &'a T: Add<&'a T, Output = T>,
|
for<'a> &'a T: Add<&'a T, Output = T>,
|
||||||
T: Any + Clone + PartialOrd,
|
T: Variant + Clone + PartialOrd,
|
||||||
StepRange<T>: Iterator<Item = T>,
|
StepRange<T>: Iterator<Item = T>,
|
||||||
{
|
{
|
||||||
engine.register_iterator::<StepRange<T>, _>(|a: &Dynamic| {
|
engine.register_iterator::<StepRange<T>, _>(|source: &Dynamic| {
|
||||||
Box::new(
|
Box::new(
|
||||||
a.downcast_ref::<StepRange<T>>()
|
source
|
||||||
|
.downcast_ref::<StepRange<T>>()
|
||||||
|
.cloned()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone()
|
|
||||||
.map(|x| x.into_dynamic()),
|
.map(|x| x.into_dynamic()),
|
||||||
) as Box<dyn Iterator<Item = Dynamic>>
|
) as Box<dyn Iterator<Item = Dynamic>>
|
||||||
});
|
});
|
||||||
@ -866,19 +868,19 @@ impl Engine<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register array utility functions
|
// Register array utility functions
|
||||||
fn push<T: Any>(list: &mut Array, item: T) {
|
fn push<T: Variant + Clone>(list: &mut Array, item: T) {
|
||||||
list.push(Box::new(item));
|
list.push(Dynamic::from(item));
|
||||||
}
|
}
|
||||||
fn ins<T: Any>(list: &mut Array, position: INT, item: T) {
|
fn ins<T: Variant + Clone>(list: &mut Array, position: INT, item: T) {
|
||||||
if position <= 0 {
|
if position <= 0 {
|
||||||
list.insert(0, Box::new(item));
|
list.insert(0, Dynamic::from(item));
|
||||||
} else if (position as usize) >= list.len() - 1 {
|
} else if (position as usize) >= list.len() - 1 {
|
||||||
push(list, item);
|
push(list, item);
|
||||||
} else {
|
} else {
|
||||||
list.insert(position as usize, Box::new(item));
|
list.insert(position as usize, Dynamic::from(item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn pad<T: Any + Clone>(list: &mut Array, len: INT, item: T) {
|
fn pad<T: Variant + Clone>(list: &mut Array, len: INT, item: T) {
|
||||||
if len >= 0 {
|
if len >= 0 {
|
||||||
while list.len() < len as usize {
|
while list.len() < len as usize {
|
||||||
push(list, item.clone());
|
push(list, item.clone());
|
||||||
@ -919,18 +921,18 @@ impl Engine<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.register_dynamic_fn("pop", |list: &mut Array| {
|
self.register_dynamic_fn("pop", |list: &mut Array| {
|
||||||
list.pop().unwrap_or_else(|| ().into_dynamic())
|
list.pop().unwrap_or_else(|| Dynamic::from_unit())
|
||||||
});
|
});
|
||||||
self.register_dynamic_fn("shift", |list: &mut Array| {
|
self.register_dynamic_fn("shift", |list: &mut Array| {
|
||||||
if !list.is_empty() {
|
if !list.is_empty() {
|
||||||
().into_dynamic()
|
Dynamic::from_unit()
|
||||||
} else {
|
} else {
|
||||||
list.remove(0)
|
list.remove(0)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.register_dynamic_fn("remove", |list: &mut Array, len: INT| {
|
self.register_dynamic_fn("remove", |list: &mut Array, len: INT| {
|
||||||
if len < 0 || (len as usize) >= list.len() {
|
if len < 0 || (len as usize) >= list.len() {
|
||||||
().into_dynamic()
|
Dynamic::from_unit()
|
||||||
} else {
|
} else {
|
||||||
list.remove(len as usize)
|
list.remove(len as usize)
|
||||||
}
|
}
|
||||||
@ -951,7 +953,7 @@ impl Engine<'_> {
|
|||||||
self.register_fn("len", |map: &mut Map| map.len() as INT);
|
self.register_fn("len", |map: &mut Map| map.len() as INT);
|
||||||
self.register_fn("clear", |map: &mut Map| map.clear());
|
self.register_fn("clear", |map: &mut Map| map.clear());
|
||||||
self.register_dynamic_fn("remove", |x: &mut Map, name: String| {
|
self.register_dynamic_fn("remove", |x: &mut Map, name: String| {
|
||||||
x.remove(&name).unwrap_or(().into_dynamic())
|
x.remove(&name).unwrap_or_else(|| Dynamic::from_unit())
|
||||||
});
|
});
|
||||||
self.register_fn("mixin", |map1: &mut Map, map2: Map| {
|
self.register_fn("mixin", |map1: &mut Map, map2: Map| {
|
||||||
map2.into_iter().for_each(|(key, value)| {
|
map2.into_iter().for_each(|(key, value)| {
|
||||||
|
352
src/engine.rs
352
src/engine.rs
@ -1,6 +1,6 @@
|
|||||||
//! Main module defining the script evaluation `Engine`.
|
//! Main module defining the script evaluation `Engine`.
|
||||||
|
|
||||||
use crate::any::{Any, AnyExt, Dynamic, Variant};
|
use crate::any::{Dynamic, Union};
|
||||||
use crate::error::ParseErrorType;
|
use crate::error::ParseErrorType;
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::parser::{Expr, FnDef, Position, ReturnType, Stmt, INT};
|
use crate::parser::{Expr, FnDef, Position, ReturnType, Stmt, INT};
|
||||||
@ -8,7 +8,7 @@ use crate::result::EvalAltResult;
|
|||||||
use crate::scope::{EntryRef as ScopeSource, EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryRef as ScopeSource, EntryType as ScopeEntryType, Scope};
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::{type_name, TypeId},
|
any::TypeId,
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
@ -19,7 +19,6 @@ use crate::stdlib::{
|
|||||||
rc::Rc,
|
rc::Rc,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::Instant,
|
|
||||||
vec,
|
vec,
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
@ -34,7 +33,7 @@ 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>;
|
||||||
|
|
||||||
pub type FnCallArgs<'a> = [&'a mut Variant];
|
pub type FnCallArgs<'a> = [&'a mut Dynamic];
|
||||||
|
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
pub type FnAny = dyn Fn(&mut FnCallArgs, Position) -> Result<Dynamic, EvalAltResult> + Send + Sync;
|
pub type FnAny = dyn Fn(&mut FnCallArgs, Position) -> Result<Dynamic, EvalAltResult> + Send + Sync;
|
||||||
@ -98,20 +97,20 @@ impl IndexValue {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Target<'a> {
|
enum Target<'a> {
|
||||||
Scope(ScopeSource<'a>),
|
Scope(ScopeSource<'a>),
|
||||||
Value(&'a mut Variant),
|
Value(&'a mut Dynamic),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Target<'a> {
|
impl<'a> Target<'a> {
|
||||||
fn from(value: &'a mut Variant) -> Self {
|
fn from(value: &'a mut Dynamic) -> Self {
|
||||||
Self::Value(value)
|
Self::Value(value)
|
||||||
}
|
}
|
||||||
fn from_src(src: ScopeSource<'a>) -> Self {
|
fn from_src(src: ScopeSource<'a>) -> Self {
|
||||||
Self::Scope(src)
|
Self::Scope(src)
|
||||||
}
|
}
|
||||||
fn get_mut(self, scope: &'a mut Scope) -> &'a mut Variant {
|
fn get_mut(self, scope: &'a mut Scope) -> &'a mut Dynamic {
|
||||||
match self {
|
match self {
|
||||||
Self::Value(t) => t,
|
Self::Value(t) => t,
|
||||||
Self::Scope(src) => scope.get_mut(src).as_mut(),
|
Self::Scope(src) => scope.get_mut(src),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,7 +299,6 @@ impl Default for Engine<'_> {
|
|||||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||||
};
|
};
|
||||||
|
|
||||||
engine.fill_type_names();
|
|
||||||
engine.register_core_lib();
|
engine.register_core_lib();
|
||||||
|
|
||||||
#[cfg(not(feature = "no_stdlib"))]
|
#[cfg(not(feature = "no_stdlib"))]
|
||||||
@ -353,25 +351,6 @@ fn extract_prop_from_setter(fn_name: &str) -> Option<&str> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Engine<'_> {
|
impl Engine<'_> {
|
||||||
fn fill_type_names(&mut self) {
|
|
||||||
// User-friendly names for built-in types
|
|
||||||
self.type_names = Some(
|
|
||||||
[
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
|
||||||
(type_name::<Array>(), "array"),
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
(type_name::<Map>(), "map"),
|
|
||||||
(type_name::<String>(), "string"),
|
|
||||||
(type_name::<Instant>(), "timestamp"),
|
|
||||||
(type_name::<Dynamic>(), "dynamic"),
|
|
||||||
(type_name::<Variant>(), "variant"),
|
|
||||||
]
|
|
||||||
.iter()
|
|
||||||
.map(|(k, v)| (k.to_string(), v.to_string()))
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new `Engine`
|
/// Create a new `Engine`
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
@ -400,7 +379,6 @@ impl Engine<'_> {
|
|||||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||||
};
|
};
|
||||||
|
|
||||||
engine.fill_type_names();
|
|
||||||
engine.register_core_lib();
|
engine.register_core_lib();
|
||||||
|
|
||||||
engine
|
engine
|
||||||
@ -452,7 +430,7 @@ impl Engine<'_> {
|
|||||||
fn_def
|
fn_def
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.zip(args.into_iter().map(|x| (*x).into_dynamic()))
|
.zip(args.into_iter().map(|v| v.clone()))
|
||||||
.map(|(name, value)| (name.clone(), ScopeEntryType::Normal, value)),
|
.map(|(name, value)| (name.clone(), ScopeEntryType::Normal, value)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -478,7 +456,7 @@ impl Engine<'_> {
|
|||||||
fn_def
|
fn_def
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.zip(args.into_iter().map(|x| (*x).into_dynamic()))
|
.zip(args.into_iter().map(|v| v.clone()))
|
||||||
.map(|(name, value)| (name, ScopeEntryType::Normal, value)),
|
.map(|(name, value)| (name, ScopeEntryType::Normal, value)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -496,14 +474,13 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
let spec = FnSpec {
|
let spec = FnSpec {
|
||||||
name: fn_name.into(),
|
name: fn_name.into(),
|
||||||
args: args.iter().map(|a| Any::type_id(*a)).collect(),
|
args: args.iter().map(|a| a.type_id()).collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Argument must be a string
|
// Argument must be a string
|
||||||
fn cast_to_string(r: &Variant, pos: Position) -> Result<&str, EvalAltResult> {
|
fn cast_to_string(r: &Dynamic, pos: Position) -> Result<&str, EvalAltResult> {
|
||||||
r.downcast_ref::<String>()
|
r.as_str()
|
||||||
.map(String::as_str)
|
.map_err(|type_name| EvalAltResult::ErrorMismatchOutputType(type_name.into(), pos))
|
||||||
.ok_or_else(|| EvalAltResult::ErrorMismatchOutputType(r.type_name().into(), pos))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search built-in's and external functions
|
// Search built-in's and external functions
|
||||||
@ -513,23 +490,26 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// See if the function match print/debug (which requires special processing)
|
// See if the function match print/debug (which requires special processing)
|
||||||
return match fn_name {
|
return match fn_name {
|
||||||
KEYWORD_PRINT if self.on_print.is_some() => Ok(self.on_print.as_ref().unwrap()(
|
KEYWORD_PRINT if self.on_print.is_some() => {
|
||||||
cast_to_string(result.as_ref(), pos)?,
|
self.on_print.as_ref().unwrap()(cast_to_string(&result, pos)?);
|
||||||
)
|
Ok(Dynamic::from_unit())
|
||||||
.into_dynamic()),
|
}
|
||||||
KEYWORD_DEBUG if self.on_debug.is_some() => Ok(self.on_debug.as_ref().unwrap()(
|
KEYWORD_DEBUG if self.on_debug.is_some() => {
|
||||||
cast_to_string(result.as_ref(), pos)?,
|
self.on_debug.as_ref().unwrap()(cast_to_string(&result, pos)?);
|
||||||
)
|
Ok(Dynamic::from_unit())
|
||||||
.into_dynamic()),
|
}
|
||||||
KEYWORD_PRINT | KEYWORD_DEBUG => Ok(().into_dynamic()),
|
KEYWORD_PRINT | KEYWORD_DEBUG => Ok(Dynamic::from_unit()),
|
||||||
_ => Ok(result),
|
_ => Ok(result),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(prop) = extract_prop_from_getter(fn_name) {
|
if let Some(prop) = extract_prop_from_getter(fn_name) {
|
||||||
// Map property access
|
// Map property access
|
||||||
if let Some(map) = args[0].downcast_ref::<Map>() {
|
if let Ok(map) = args[0].as_map() {
|
||||||
return Ok(map.get(prop).cloned().unwrap_or_else(|| ().into_dynamic()));
|
return Ok(map
|
||||||
|
.get(prop)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| Dynamic::from_unit()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getter function not found
|
// Getter function not found
|
||||||
@ -540,12 +520,12 @@ impl Engine<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(prop) = extract_prop_from_setter(fn_name) {
|
if let Some(prop) = extract_prop_from_setter(fn_name) {
|
||||||
let value = args[1].into_dynamic();
|
let value = args[1].clone();
|
||||||
|
|
||||||
// Map property update
|
// Map property update
|
||||||
if let Some(map) = args[0].downcast_mut::<Map>() {
|
if let Dynamic(Union::Map(map)) = args[0] {
|
||||||
map.insert(prop.to_string(), value);
|
map.insert(prop.to_string(), value);
|
||||||
return Ok(().into_dynamic());
|
return Ok(Dynamic::from_unit());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setter function not found
|
// Setter function not found
|
||||||
@ -592,9 +572,7 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
let this_ptr = target.get_mut(scope);
|
let this_ptr = target.get_mut(scope);
|
||||||
|
|
||||||
let mut args: Vec<_> = once(this_ptr)
|
let mut args: Vec<_> = once(this_ptr).chain(values.iter_mut()).collect();
|
||||||
.chain(values.iter_mut().map(Dynamic::as_mut))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let def_val = def_val.as_ref();
|
let def_val = def_val.as_ref();
|
||||||
|
|
||||||
@ -639,7 +617,7 @@ impl Engine<'_> {
|
|||||||
let mut args = [target.get_mut(scope)];
|
let mut args = [target.get_mut(scope)];
|
||||||
self.call_fn_raw(None, fn_lib, &make_getter(id), &mut args, None, *pos, 0)
|
self.call_fn_raw(None, fn_lib, &make_getter(id), &mut args, None, *pos, 0)
|
||||||
.and_then(|mut val| {
|
.and_then(|mut val| {
|
||||||
let target = Target::from(val.as_mut());
|
let target = Target::from(&mut val);
|
||||||
self.get_dot_val_helper(scope, fn_lib, target, rhs, level)
|
self.get_dot_val_helper(scope, fn_lib, target, rhs, level)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -667,7 +645,7 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
self.get_indexed_value(scope, fn_lib, &val, idx_expr, *op_pos, level)
|
self.get_indexed_value(scope, fn_lib, &val, idx_expr, *op_pos, level)
|
||||||
.and_then(|(mut val, _, _)| {
|
.and_then(|(mut val, _, _)| {
|
||||||
let target = Target::from(val.as_mut());
|
let target = Target::from(&mut val);
|
||||||
self.get_dot_val_helper(scope, fn_lib, target, rhs, level)
|
self.get_dot_val_helper(scope, fn_lib, target, rhs, level)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -712,7 +690,7 @@ impl Engine<'_> {
|
|||||||
Expr::Index(idx_lhs, idx_expr, op_pos) => {
|
Expr::Index(idx_lhs, idx_expr, op_pos) => {
|
||||||
let (idx_src_type, src, index, mut val) =
|
let (idx_src_type, src, index, mut val) =
|
||||||
self.eval_index_expr(scope, fn_lib, idx_lhs, idx_expr, *op_pos, level)?;
|
self.eval_index_expr(scope, fn_lib, idx_lhs, idx_expr, *op_pos, level)?;
|
||||||
let target = Target::from(val.as_mut());
|
let target = Target::from(&mut val);
|
||||||
let value = self.get_dot_val_helper(scope, fn_lib, target, dot_rhs, level);
|
let value = self.get_dot_val_helper(scope, fn_lib, target, dot_rhs, level);
|
||||||
|
|
||||||
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
|
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
|
||||||
@ -743,7 +721,7 @@ impl Engine<'_> {
|
|||||||
// {expr}.???
|
// {expr}.???
|
||||||
expr => {
|
expr => {
|
||||||
let mut val = self.eval_expr(scope, fn_lib, expr, level)?;
|
let mut val = self.eval_expr(scope, fn_lib, expr, level)?;
|
||||||
self.get_dot_val_helper(scope, fn_lib, Target::from(val.as_mut()), dot_rhs, level)
|
self.get_dot_val_helper(scope, fn_lib, Target::from(&mut val), dot_rhs, level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -772,16 +750,21 @@ impl Engine<'_> {
|
|||||||
let idx_pos = idx_expr.position();
|
let idx_pos = idx_expr.position();
|
||||||
|
|
||||||
// val_array[idx]
|
// val_array[idx]
|
||||||
if let Some(arr) = val.downcast_ref::<Array>() {
|
if let Ok(arr) = val.as_array() {
|
||||||
let index = self
|
let index = self
|
||||||
.eval_expr(scope, fn_lib, idx_expr, level)?
|
.eval_expr(scope, fn_lib, idx_expr, level)?
|
||||||
.try_cast::<INT>()
|
.as_int()
|
||||||
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_expr.position()))?;
|
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_expr.position()))?;
|
||||||
|
|
||||||
return if index >= 0 {
|
return if index >= 0 {
|
||||||
arr.get(index as usize)
|
arr.get(index as usize)
|
||||||
.cloned()
|
.map(|v| {
|
||||||
.map(|v| (v, IndexSourceType::Array, IndexValue::from_num(index)))
|
(
|
||||||
|
v.clone(),
|
||||||
|
IndexSourceType::Array,
|
||||||
|
IndexValue::from_num(index),
|
||||||
|
)
|
||||||
|
})
|
||||||
.ok_or_else(|| EvalAltResult::ErrorArrayBounds(arr.len(), index, idx_pos))
|
.ok_or_else(|| EvalAltResult::ErrorArrayBounds(arr.len(), index, idx_pos))
|
||||||
} else {
|
} else {
|
||||||
Err(EvalAltResult::ErrorArrayBounds(arr.len(), index, idx_pos))
|
Err(EvalAltResult::ErrorArrayBounds(arr.len(), index, idx_pos))
|
||||||
@ -789,26 +772,26 @@ impl Engine<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// val_map[idx]
|
// val_map[idx]
|
||||||
if let Some(map) = val.downcast_ref::<Map>() {
|
if let Ok(map) = val.as_map() {
|
||||||
let index = self
|
let index = self
|
||||||
.eval_expr(scope, fn_lib, idx_expr, level)?
|
.eval_expr(scope, fn_lib, idx_expr, level)?
|
||||||
.try_cast::<String>()
|
.take_string()
|
||||||
.map_err(|_| EvalAltResult::ErrorStringIndexExpr(idx_expr.position()))?;
|
.map_err(|_| EvalAltResult::ErrorStringIndexExpr(idx_expr.position()))?;
|
||||||
|
|
||||||
return Ok((
|
return Ok((
|
||||||
map.get(&index)
|
map.get(&index)
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_else(|| ().into_dynamic()),
|
.unwrap_or_else(|| Dynamic::from_unit()),
|
||||||
IndexSourceType::Map,
|
IndexSourceType::Map,
|
||||||
IndexValue::from_str(index),
|
IndexValue::from_str(index),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// val_string[idx]
|
// val_string[idx]
|
||||||
if let Some(s) = val.downcast_ref::<String>() {
|
if let Ok(s) = val.as_str() {
|
||||||
let index = self
|
let index = self
|
||||||
.eval_expr(scope, fn_lib, idx_expr, level)?
|
.eval_expr(scope, fn_lib, idx_expr, level)?
|
||||||
.try_cast::<INT>()
|
.as_int()
|
||||||
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_expr.position()))?;
|
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_expr.position()))?;
|
||||||
|
|
||||||
return if index >= 0 {
|
return if index >= 0 {
|
||||||
@ -816,7 +799,7 @@ impl Engine<'_> {
|
|||||||
.nth(index as usize)
|
.nth(index as usize)
|
||||||
.map(|ch| {
|
.map(|ch| {
|
||||||
(
|
(
|
||||||
ch.into_dynamic(),
|
Dynamic::from_char(ch),
|
||||||
IndexSourceType::String,
|
IndexSourceType::String,
|
||||||
IndexValue::from_num(index),
|
IndexValue::from_num(index),
|
||||||
)
|
)
|
||||||
@ -921,14 +904,14 @@ impl Engine<'_> {
|
|||||||
IndexSourceType::Array => {
|
IndexSourceType::Array => {
|
||||||
let arr = scope.get_mut_by_type::<Array>(src);
|
let arr = scope.get_mut_by_type::<Array>(src);
|
||||||
arr[idx.as_num()] = new_val.0;
|
arr[idx.as_num()] = new_val.0;
|
||||||
Ok(().into_dynamic())
|
Ok(Dynamic::from_unit())
|
||||||
}
|
}
|
||||||
|
|
||||||
// map_id[idx] = val
|
// map_id[idx] = val
|
||||||
IndexSourceType::Map => {
|
IndexSourceType::Map => {
|
||||||
let arr = scope.get_mut_by_type::<Map>(src);
|
let arr = scope.get_mut_by_type::<Map>(src);
|
||||||
arr.insert(idx.as_str(), new_val.0);
|
arr.insert(idx.as_str(), new_val.0);
|
||||||
Ok(().into_dynamic())
|
Ok(Dynamic::from_unit())
|
||||||
}
|
}
|
||||||
|
|
||||||
// string_id[idx] = val
|
// string_id[idx] = val
|
||||||
@ -938,10 +921,10 @@ impl Engine<'_> {
|
|||||||
// Value must be a character
|
// Value must be a character
|
||||||
let ch = new_val
|
let ch = new_val
|
||||||
.0
|
.0
|
||||||
.try_cast::<char>()
|
.as_char()
|
||||||
.map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?;
|
.map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?;
|
||||||
Self::str_replace_char(s, idx.as_num(), ch);
|
Self::str_replace_char(s, idx.as_num(), ch);
|
||||||
Ok(().into_dynamic())
|
Ok(Dynamic::from_unit())
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexSourceType::Expression => panic!("expression cannot be indexed for update"),
|
IndexSourceType::Expression => panic!("expression cannot be indexed for update"),
|
||||||
@ -955,27 +938,26 @@ impl Engine<'_> {
|
|||||||
new_val: Dynamic,
|
new_val: Dynamic,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> Result<Dynamic, EvalAltResult> {
|
) -> Result<Dynamic, EvalAltResult> {
|
||||||
if let Some(arr) = target.downcast_mut::<Array>() {
|
match target {
|
||||||
arr[idx.as_num()] = new_val;
|
Dynamic(Union::Array(ref mut arr)) => {
|
||||||
return Ok(target);
|
arr[idx.as_num()] = new_val;
|
||||||
|
}
|
||||||
|
Dynamic(Union::Map(ref mut map)) => {
|
||||||
|
map.insert(idx.as_str(), new_val);
|
||||||
|
}
|
||||||
|
Dynamic(Union::Str(ref mut s)) => {
|
||||||
|
// Value must be a character
|
||||||
|
let ch = new_val
|
||||||
|
.as_char()
|
||||||
|
.map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?;
|
||||||
|
|
||||||
|
Self::str_replace_char(s, idx.as_num(), ch);
|
||||||
|
}
|
||||||
|
// All other variable types should be an error
|
||||||
|
_ => panic!("array, map or string source type expected for indexing"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(map) = target.downcast_mut::<Map>() {
|
Ok(target)
|
||||||
map.insert(idx.as_str(), new_val);
|
|
||||||
return Ok(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(s) = target.downcast_mut::<String>() {
|
|
||||||
// Value must be a character
|
|
||||||
let ch = new_val
|
|
||||||
.try_cast::<char>()
|
|
||||||
.map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?;
|
|
||||||
Self::str_replace_char(s, idx.as_num(), ch);
|
|
||||||
return Ok(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
// All other variable types should be an error
|
|
||||||
panic!("array, map or string source type expected for indexing")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Chain-evaluate a dot setter
|
/// Chain-evaluate a dot setter
|
||||||
@ -983,7 +965,7 @@ impl Engine<'_> {
|
|||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
fn_lib: Option<&FunctionsLib>,
|
fn_lib: Option<&FunctionsLib>,
|
||||||
this_ptr: &mut Variant,
|
this_ptr: &mut Dynamic,
|
||||||
dot_rhs: &Expr,
|
dot_rhs: &Expr,
|
||||||
new_val: (&mut Dynamic, Position),
|
new_val: (&mut Dynamic, Position),
|
||||||
level: usize,
|
level: usize,
|
||||||
@ -991,7 +973,7 @@ impl Engine<'_> {
|
|||||||
match dot_rhs {
|
match dot_rhs {
|
||||||
// xxx.id
|
// xxx.id
|
||||||
Expr::Property(id, pos) => {
|
Expr::Property(id, pos) => {
|
||||||
let mut args = [this_ptr, new_val.0.as_mut()];
|
let mut args = [this_ptr, new_val.0];
|
||||||
self.call_fn_raw(None, fn_lib, &make_setter(id), &mut args, None, *pos, 0)
|
self.call_fn_raw(None, fn_lib, &make_setter(id), &mut args, None, *pos, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1010,7 +992,7 @@ impl Engine<'_> {
|
|||||||
})
|
})
|
||||||
.and_then(|mut val| {
|
.and_then(|mut val| {
|
||||||
let fn_name = make_setter(id);
|
let fn_name = make_setter(id);
|
||||||
let mut args = [this_ptr, val.as_mut()];
|
let mut args = [this_ptr, &mut val];
|
||||||
self.call_fn_raw(None, fn_lib, &fn_name, &mut args, None, *pos, 0)
|
self.call_fn_raw(None, fn_lib, &fn_name, &mut args, None, *pos, 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1029,13 +1011,12 @@ impl Engine<'_> {
|
|||||||
let fn_name = make_getter(id);
|
let fn_name = make_getter(id);
|
||||||
self.call_fn_raw(None, fn_lib, &fn_name, &mut [this_ptr], None, *pos, 0)
|
self.call_fn_raw(None, fn_lib, &fn_name, &mut [this_ptr], None, *pos, 0)
|
||||||
.and_then(|mut val| {
|
.and_then(|mut val| {
|
||||||
let value = val.as_mut();
|
self.set_dot_val_helper(scope, fn_lib, &mut val, rhs, new_val, level)
|
||||||
self.set_dot_val_helper(scope, fn_lib, value, rhs, new_val, level)
|
|
||||||
.map(|_| val) // Discard Ok return value
|
.map(|_| val) // Discard Ok return value
|
||||||
})
|
})
|
||||||
.and_then(|mut val| {
|
.and_then(|mut val| {
|
||||||
let fn_name = make_setter(id);
|
let fn_name = make_setter(id);
|
||||||
let mut args = [this_ptr, val.as_mut()];
|
let mut args = [this_ptr, &mut val];
|
||||||
self.call_fn_raw(None, fn_lib, &fn_name, &mut args, None, *pos, 0)
|
self.call_fn_raw(None, fn_lib, &fn_name, &mut args, None, *pos, 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1053,7 +1034,7 @@ impl Engine<'_> {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
let val_pos = new_val.1;
|
let val_pos = new_val.1;
|
||||||
let this_ptr = value.as_mut();
|
let this_ptr = &mut value;
|
||||||
self.set_dot_val_helper(
|
self.set_dot_val_helper(
|
||||||
scope, fn_lib, this_ptr, rhs, new_val, level,
|
scope, fn_lib, this_ptr, rhs, new_val, level,
|
||||||
)?;
|
)?;
|
||||||
@ -1063,7 +1044,7 @@ impl Engine<'_> {
|
|||||||
})
|
})
|
||||||
.and_then(|mut v| {
|
.and_then(|mut v| {
|
||||||
let fn_name = make_setter(id);
|
let fn_name = make_setter(id);
|
||||||
let mut args = [this_ptr, v.as_mut()];
|
let mut args = [this_ptr, &mut v];
|
||||||
self.call_fn_raw(None, fn_lib, &fn_name, &mut args, None, *pos, 0)
|
self.call_fn_raw(None, fn_lib, &fn_name, &mut args, None, *pos, 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1114,7 +1095,7 @@ impl Engine<'_> {
|
|||||||
_ => {
|
_ => {
|
||||||
// Avoid referencing scope which is used below as mut
|
// Avoid referencing scope which is used below as mut
|
||||||
let entry = ScopeSource { name: id, ..src };
|
let entry = ScopeSource { name: id, ..src };
|
||||||
let this_ptr = target.as_mut();
|
let this_ptr = &mut target;
|
||||||
let value = self
|
let value = self
|
||||||
.set_dot_val_helper(scope, fn_lib, this_ptr, dot_rhs, new_val, level);
|
.set_dot_val_helper(scope, fn_lib, this_ptr, dot_rhs, new_val, level);
|
||||||
|
|
||||||
@ -1132,7 +1113,7 @@ impl Engine<'_> {
|
|||||||
let (idx_src_type, src, index, mut target) =
|
let (idx_src_type, src, index, mut target) =
|
||||||
self.eval_index_expr(scope, fn_lib, lhs, idx_expr, *op_pos, level)?;
|
self.eval_index_expr(scope, fn_lib, lhs, idx_expr, *op_pos, level)?;
|
||||||
let val_pos = new_val.1;
|
let val_pos = new_val.1;
|
||||||
let this_ptr = target.as_mut();
|
let this_ptr = &mut target;
|
||||||
let value =
|
let value =
|
||||||
self.set_dot_val_helper(scope, fn_lib, this_ptr, dot_rhs, new_val, level);
|
self.set_dot_val_helper(scope, fn_lib, this_ptr, dot_rhs, new_val, level);
|
||||||
|
|
||||||
@ -1181,56 +1162,46 @@ impl Engine<'_> {
|
|||||||
let mut lhs_value = self.eval_expr(scope, fn_lib, lhs, level)?;
|
let mut lhs_value = self.eval_expr(scope, fn_lib, lhs, level)?;
|
||||||
let rhs_value = self.eval_expr(scope, fn_lib, rhs, level)?;
|
let rhs_value = self.eval_expr(scope, fn_lib, rhs, level)?;
|
||||||
|
|
||||||
if rhs_value.is::<Array>() {
|
match rhs_value {
|
||||||
let mut rhs_value = rhs_value.cast::<Array>();
|
Dynamic(Union::Array(mut rhs_value)) => {
|
||||||
let def_value = false.into_dynamic();
|
let def_value = Dynamic::from_bool(false);
|
||||||
let mut result = false;
|
let mut result = false;
|
||||||
|
|
||||||
// Call the '==' operator to compare each value
|
// Call the '==' operator to compare each value
|
||||||
for value in rhs_value.iter_mut() {
|
for value in rhs_value.iter_mut() {
|
||||||
let args = &mut [lhs_value.as_mut(), value.as_mut()];
|
let args = &mut [&mut lhs_value, value];
|
||||||
let def_value = Some(&def_value);
|
let def_value = Some(&def_value);
|
||||||
if self
|
if self
|
||||||
.call_fn_raw(None, fn_lib, "==", args, def_value, rhs.position(), level)?
|
.call_fn_raw(None, fn_lib, "==", args, def_value, rhs.position(), level)?
|
||||||
.try_cast::<bool>()
|
.as_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
result = true;
|
result = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Dynamic::from_bool(result))
|
||||||
|
}
|
||||||
|
Dynamic(Union::Map(rhs_value)) => {
|
||||||
|
// Only allows String or char
|
||||||
|
match lhs_value {
|
||||||
|
Dynamic(Union::Str(s)) => Ok(Dynamic::from_bool(rhs_value.contains_key(&s))),
|
||||||
|
Dynamic(Union::Char(c)) => {
|
||||||
|
Ok(Dynamic::from_bool(rhs_value.contains_key(&c.to_string())))
|
||||||
|
}
|
||||||
|
_ => Err(EvalAltResult::ErrorInExpr(lhs.position())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Dynamic(Union::Str(rhs_value)) => {
|
||||||
Ok(result.into_dynamic())
|
// Only allows String or char
|
||||||
} else if rhs_value.is::<Map>() {
|
match lhs_value {
|
||||||
let rhs_value = rhs_value.cast::<Map>();
|
Dynamic(Union::Str(s)) => Ok(Dynamic::from_bool(rhs_value.contains(&s))),
|
||||||
|
Dynamic(Union::Char(c)) => Ok(Dynamic::from_bool(rhs_value.contains(c))),
|
||||||
// Only allows String or char
|
_ => Err(EvalAltResult::ErrorInExpr(lhs.position())),
|
||||||
if lhs_value.is::<String>() {
|
}
|
||||||
Ok(rhs_value
|
|
||||||
.contains_key(&lhs_value.cast::<String>())
|
|
||||||
.into_dynamic())
|
|
||||||
} else if lhs_value.is::<char>() {
|
|
||||||
Ok(rhs_value
|
|
||||||
.contains_key(&lhs_value.cast::<char>().to_string())
|
|
||||||
.into_dynamic())
|
|
||||||
} else {
|
|
||||||
Err(EvalAltResult::ErrorInExpr(lhs.position()))
|
|
||||||
}
|
}
|
||||||
} else if rhs_value.is::<String>() {
|
_ => Err(EvalAltResult::ErrorInExpr(rhs.position())),
|
||||||
let rhs_value = rhs_value.cast::<String>();
|
|
||||||
|
|
||||||
// Only allows String or char
|
|
||||||
if lhs_value.is::<String>() {
|
|
||||||
Ok(rhs_value
|
|
||||||
.contains(&lhs_value.cast::<String>())
|
|
||||||
.into_dynamic())
|
|
||||||
} else if lhs_value.is::<char>() {
|
|
||||||
Ok(rhs_value.contains(lhs_value.cast::<char>()).into_dynamic())
|
|
||||||
} else {
|
|
||||||
Err(EvalAltResult::ErrorInExpr(lhs.position()))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(EvalAltResult::ErrorInExpr(rhs.position()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1243,10 +1214,11 @@ impl Engine<'_> {
|
|||||||
level: usize,
|
level: usize,
|
||||||
) -> Result<Dynamic, EvalAltResult> {
|
) -> Result<Dynamic, EvalAltResult> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::IntegerConstant(i, _) => Ok(i.into_dynamic()),
|
Expr::IntegerConstant(i, _) => Ok(Dynamic::from_int(*i)),
|
||||||
Expr::FloatConstant(f, _) => Ok(f.into_dynamic()),
|
#[cfg(not(feature = "no_float"))]
|
||||||
Expr::StringConstant(s, _) => Ok(s.clone().into_owned().into_dynamic()),
|
Expr::FloatConstant(f, _) => Ok(Dynamic::from_float(*f)),
|
||||||
Expr::CharConstant(c, _) => Ok(c.into_dynamic()),
|
Expr::StringConstant(s, _) => Ok(Dynamic::from_string(s.to_string())),
|
||||||
|
Expr::CharConstant(c, _) => Ok(Dynamic::from_char(*c)),
|
||||||
Expr::Variable(id, pos) => Self::search_scope(scope, id, *pos).map(|(_, val)| val),
|
Expr::Variable(id, pos) => Self::search_scope(scope, id, *pos).map(|(_, val)| val),
|
||||||
Expr::Property(_, _) => panic!("unexpected property."),
|
Expr::Property(_, _) => panic!("unexpected property."),
|
||||||
|
|
||||||
@ -1262,7 +1234,7 @@ impl Engine<'_> {
|
|||||||
Expr::Variable(name, pos) => match scope.get(name) {
|
Expr::Variable(name, pos) => match scope.get(name) {
|
||||||
None => {
|
None => {
|
||||||
return Err(EvalAltResult::ErrorVariableNotFound(
|
return Err(EvalAltResult::ErrorVariableNotFound(
|
||||||
name.clone().into_owned(),
|
name.to_string(),
|
||||||
*pos,
|
*pos,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -1358,7 +1330,7 @@ impl Engine<'_> {
|
|||||||
.map(|val| arr.push(val))
|
.map(|val| arr.push(val))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok((arr).into_dynamic())
|
Ok(Dynamic(Union::Array(arr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -1371,7 +1343,7 @@ impl Engine<'_> {
|
|||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok((map).into_dynamic())
|
Ok(Dynamic(Union::Map(Box::new(map))))
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::FunctionCall(fn_name, args_expr_list, def_val, pos) => {
|
Expr::FunctionCall(fn_name, args_expr_list, def_val, pos) => {
|
||||||
@ -1396,10 +1368,9 @@ impl Engine<'_> {
|
|||||||
&& !has_override(self, fn_lib, KEYWORD_TYPE_OF) =>
|
&& !has_override(self, fn_lib, KEYWORD_TYPE_OF) =>
|
||||||
{
|
{
|
||||||
let result = self.eval_expr(scope, fn_lib, &args_expr_list[0], level)?;
|
let result = self.eval_expr(scope, fn_lib, &args_expr_list[0], level)?;
|
||||||
Ok(self
|
Ok(Dynamic::from_string(
|
||||||
.map_type_name((*result).type_name())
|
self.map_type_name(result.type_name()).to_string(),
|
||||||
.to_string()
|
))
|
||||||
.into_dynamic())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// eval
|
// eval
|
||||||
@ -1411,15 +1382,9 @@ impl Engine<'_> {
|
|||||||
let result = self.eval_expr(scope, fn_lib, &args_expr_list[0], level)?;
|
let result = self.eval_expr(scope, fn_lib, &args_expr_list[0], level)?;
|
||||||
|
|
||||||
// Get the script text by evaluating the expression
|
// Get the script text by evaluating the expression
|
||||||
let script = result
|
let script = result.as_str().map_err(|type_name| {
|
||||||
.downcast_ref::<String>()
|
EvalAltResult::ErrorMismatchOutputType(type_name.into(), pos)
|
||||||
.map(String::as_str)
|
})?;
|
||||||
.ok_or_else(|| {
|
|
||||||
EvalAltResult::ErrorMismatchOutputType(
|
|
||||||
result.type_name().into(),
|
|
||||||
pos,
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Compile the script text
|
// Compile the script text
|
||||||
// No optimizations because we only run it once
|
// No optimizations because we only run it once
|
||||||
@ -1461,7 +1426,7 @@ impl Engine<'_> {
|
|||||||
.map(|expr| self.eval_expr(scope, fn_lib, expr, level))
|
.map(|expr| self.eval_expr(scope, fn_lib, expr, level))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
let mut args: Vec<_> = arg_values.iter_mut().map(Dynamic::as_mut).collect();
|
let mut args: Vec<_> = arg_values.iter_mut().collect();
|
||||||
let def_val = def_val.as_ref();
|
let def_val = def_val.as_ref();
|
||||||
self.call_fn_raw(None, fn_lib, fn_name, &mut args, def_val, *pos, level)
|
self.call_fn_raw(None, fn_lib, fn_name, &mut args, def_val, *pos, level)
|
||||||
}
|
}
|
||||||
@ -1472,41 +1437,41 @@ impl Engine<'_> {
|
|||||||
self.eval_in_expr(scope, fn_lib, lhs.as_ref(), rhs.as_ref(), level)
|
self.eval_in_expr(scope, fn_lib, lhs.as_ref(), rhs.as_ref(), level)
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::And(lhs, rhs, _) => Ok(Box::new(
|
Expr::And(lhs, rhs, _) => Ok(Dynamic::from_bool(
|
||||||
self
|
self
|
||||||
.eval_expr(scope, fn_lib,lhs.as_ref(), level)?
|
.eval_expr(scope, fn_lib,lhs.as_ref(), level)?
|
||||||
.try_cast::<bool>()
|
.as_bool()
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
EvalAltResult::ErrorBooleanArgMismatch("AND".into(), lhs.position())
|
EvalAltResult::ErrorBooleanArgMismatch("AND".into(), lhs.position())
|
||||||
})?
|
})?
|
||||||
&& // Short-circuit using &&
|
&& // Short-circuit using &&
|
||||||
self
|
self
|
||||||
.eval_expr(scope, fn_lib,rhs.as_ref(), level)?
|
.eval_expr(scope, fn_lib,rhs.as_ref(), level)?
|
||||||
.try_cast::<bool>()
|
.as_bool()
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
EvalAltResult::ErrorBooleanArgMismatch("AND".into(), rhs.position())
|
EvalAltResult::ErrorBooleanArgMismatch("AND".into(), rhs.position())
|
||||||
})?,
|
})?,
|
||||||
)),
|
)),
|
||||||
|
|
||||||
Expr::Or(lhs, rhs, _) => Ok(Box::new(
|
Expr::Or(lhs, rhs, _) => Ok(Dynamic::from_bool(
|
||||||
self
|
self
|
||||||
.eval_expr(scope,fn_lib, lhs.as_ref(), level)?
|
.eval_expr(scope,fn_lib, lhs.as_ref(), level)?
|
||||||
.try_cast::<bool>()
|
.as_bool()
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
EvalAltResult::ErrorBooleanArgMismatch("OR".into(), lhs.position())
|
EvalAltResult::ErrorBooleanArgMismatch("OR".into(), lhs.position())
|
||||||
})?
|
})?
|
||||||
|| // Short-circuit using ||
|
|| // Short-circuit using ||
|
||||||
self
|
self
|
||||||
.eval_expr(scope,fn_lib, rhs.as_ref(), level)?
|
.eval_expr(scope,fn_lib, rhs.as_ref(), level)?
|
||||||
.try_cast::<bool>()
|
.as_bool()
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
EvalAltResult::ErrorBooleanArgMismatch("OR".into(), rhs.position())
|
EvalAltResult::ErrorBooleanArgMismatch("OR".into(), rhs.position())
|
||||||
})?,
|
})?,
|
||||||
)),
|
)),
|
||||||
|
|
||||||
Expr::True(_) => Ok(true.into_dynamic()),
|
Expr::True(_) => Ok(Dynamic::from_bool(true)),
|
||||||
Expr::False(_) => Ok(false.into_dynamic()),
|
Expr::False(_) => Ok(Dynamic::from_bool(false)),
|
||||||
Expr::Unit(_) => Ok(().into_dynamic()),
|
Expr::Unit(_) => Ok(Dynamic::from_unit()),
|
||||||
|
|
||||||
_ => panic!("should not appear: {:?}", expr),
|
_ => panic!("should not appear: {:?}", expr),
|
||||||
}
|
}
|
||||||
@ -1522,7 +1487,7 @@ impl Engine<'_> {
|
|||||||
) -> Result<Dynamic, EvalAltResult> {
|
) -> Result<Dynamic, EvalAltResult> {
|
||||||
match stmt {
|
match stmt {
|
||||||
// No-op
|
// No-op
|
||||||
Stmt::Noop(_) => Ok(().into_dynamic()),
|
Stmt::Noop(_) => Ok(Dynamic::from_unit()),
|
||||||
|
|
||||||
// Expression as statement
|
// Expression as statement
|
||||||
Stmt::Expr(expr) => {
|
Stmt::Expr(expr) => {
|
||||||
@ -1532,7 +1497,7 @@ impl Engine<'_> {
|
|||||||
result
|
result
|
||||||
} else {
|
} else {
|
||||||
// If it is an assignment, erase the result at the root
|
// If it is an assignment, erase the result at the root
|
||||||
().into_dynamic()
|
Dynamic::from_unit()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1540,7 +1505,7 @@ impl Engine<'_> {
|
|||||||
Stmt::Block(block, _) => {
|
Stmt::Block(block, _) => {
|
||||||
let prev_len = scope.len();
|
let prev_len = scope.len();
|
||||||
|
|
||||||
let result = block.iter().try_fold(().into_dynamic(), |_, stmt| {
|
let result = block.iter().try_fold(Dynamic::from_unit(), |_, stmt| {
|
||||||
self.eval_stmt(scope, fn_lib, stmt, level)
|
self.eval_stmt(scope, fn_lib, stmt, level)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1552,7 +1517,7 @@ impl Engine<'_> {
|
|||||||
// If-else statement
|
// If-else statement
|
||||||
Stmt::IfThenElse(guard, if_body, else_body) => self
|
Stmt::IfThenElse(guard, if_body, else_body) => self
|
||||||
.eval_expr(scope, fn_lib, guard, level)?
|
.eval_expr(scope, fn_lib, guard, level)?
|
||||||
.try_cast::<bool>()
|
.as_bool()
|
||||||
.map_err(|_| EvalAltResult::ErrorLogicGuard(guard.position()))
|
.map_err(|_| EvalAltResult::ErrorLogicGuard(guard.position()))
|
||||||
.and_then(|guard_val| {
|
.and_then(|guard_val| {
|
||||||
if guard_val {
|
if guard_val {
|
||||||
@ -1560,26 +1525,23 @@ impl Engine<'_> {
|
|||||||
} else if let Some(stmt) = else_body {
|
} else if let Some(stmt) = else_body {
|
||||||
self.eval_stmt(scope, fn_lib, stmt.as_ref(), level)
|
self.eval_stmt(scope, fn_lib, stmt.as_ref(), level)
|
||||||
} else {
|
} else {
|
||||||
Ok(().into_dynamic())
|
Ok(Dynamic::from_unit())
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// While loop
|
// While loop
|
||||||
Stmt::While(guard, body) => loop {
|
Stmt::While(guard, body) => loop {
|
||||||
match self
|
match self.eval_expr(scope, fn_lib, guard, level)?.as_bool() {
|
||||||
.eval_expr(scope, fn_lib, guard, level)?
|
|
||||||
.try_cast::<bool>()
|
|
||||||
{
|
|
||||||
Ok(guard_val) if guard_val => {
|
Ok(guard_val) if guard_val => {
|
||||||
match self.eval_stmt(scope, fn_lib, body, level) {
|
match self.eval_stmt(scope, fn_lib, body, level) {
|
||||||
Ok(_) | Err(EvalAltResult::ErrorLoopBreak(false, _)) => (),
|
Ok(_) | Err(EvalAltResult::ErrorLoopBreak(false, _)) => (),
|
||||||
Err(EvalAltResult::ErrorLoopBreak(true, _)) => {
|
Err(EvalAltResult::ErrorLoopBreak(true, _)) => {
|
||||||
return Ok(().into_dynamic())
|
return Ok(Dynamic::from_unit())
|
||||||
}
|
}
|
||||||
Err(x) => return Err(x),
|
Err(x) => return Err(x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(_) => return Ok(().into_dynamic()),
|
Ok(_) => return Ok(Dynamic::from_unit()),
|
||||||
Err(_) => return Err(EvalAltResult::ErrorLogicGuard(guard.position())),
|
Err(_) => return Err(EvalAltResult::ErrorLogicGuard(guard.position())),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1588,7 +1550,7 @@ impl Engine<'_> {
|
|||||||
Stmt::Loop(body) => loop {
|
Stmt::Loop(body) => loop {
|
||||||
match self.eval_stmt(scope, fn_lib, body, level) {
|
match self.eval_stmt(scope, fn_lib, body, level) {
|
||||||
Ok(_) | Err(EvalAltResult::ErrorLoopBreak(false, _)) => (),
|
Ok(_) | Err(EvalAltResult::ErrorLoopBreak(false, _)) => (),
|
||||||
Err(EvalAltResult::ErrorLoopBreak(true, _)) => return Ok(().into_dynamic()),
|
Err(EvalAltResult::ErrorLoopBreak(true, _)) => return Ok(Dynamic::from_unit()),
|
||||||
Err(x) => return Err(x),
|
Err(x) => return Err(x),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1596,7 +1558,7 @@ impl Engine<'_> {
|
|||||||
// For loop
|
// For loop
|
||||||
Stmt::For(name, expr, body) => {
|
Stmt::For(name, expr, body) => {
|
||||||
let arr = self.eval_expr(scope, fn_lib, expr, level)?;
|
let arr = self.eval_expr(scope, fn_lib, expr, level)?;
|
||||||
let tid = Any::type_id(arr.as_ref());
|
let tid = arr.type_id();
|
||||||
|
|
||||||
if let Some(iter_fn) = self.type_iterators.as_ref().and_then(|t| t.get(&tid)) {
|
if let Some(iter_fn) = self.type_iterators.as_ref().and_then(|t| t.get(&tid)) {
|
||||||
// Add the loop variable - variable name is copied
|
// Add the loop variable - variable name is copied
|
||||||
@ -1620,7 +1582,7 @@ impl Engine<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scope.rewind(scope.len() - 1);
|
scope.rewind(scope.len() - 1);
|
||||||
Ok(().into_dynamic())
|
Ok(Dynamic::from_unit())
|
||||||
} else {
|
} else {
|
||||||
Err(EvalAltResult::ErrorFor(expr.position()))
|
Err(EvalAltResult::ErrorFor(expr.position()))
|
||||||
}
|
}
|
||||||
@ -1634,7 +1596,7 @@ impl Engine<'_> {
|
|||||||
|
|
||||||
// Empty return
|
// Empty return
|
||||||
Stmt::ReturnWithVal(None, ReturnType::Return, pos) => {
|
Stmt::ReturnWithVal(None, ReturnType::Return, pos) => {
|
||||||
Err(EvalAltResult::Return(().into_dynamic(), *pos))
|
Err(EvalAltResult::Return(Dynamic::from_unit(), *pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return value
|
// Return value
|
||||||
@ -1652,7 +1614,7 @@ impl Engine<'_> {
|
|||||||
Stmt::ReturnWithVal(Some(a), ReturnType::Exception, pos) => {
|
Stmt::ReturnWithVal(Some(a), ReturnType::Exception, pos) => {
|
||||||
let val = self.eval_expr(scope, fn_lib, a, level)?;
|
let val = self.eval_expr(scope, fn_lib, a, level)?;
|
||||||
Err(EvalAltResult::ErrorRuntime(
|
Err(EvalAltResult::ErrorRuntime(
|
||||||
val.try_cast::<String>().unwrap_or_else(|_| "".to_string()),
|
val.take_string().unwrap_or_else(|_| "".to_string()),
|
||||||
*pos,
|
*pos,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -1662,13 +1624,13 @@ impl Engine<'_> {
|
|||||||
let val = self.eval_expr(scope, fn_lib, expr, level)?;
|
let val = self.eval_expr(scope, fn_lib, expr, level)?;
|
||||||
// TODO - avoid copying variable name in inner block?
|
// TODO - avoid copying variable name in inner block?
|
||||||
scope.push_dynamic_value(name.clone(), ScopeEntryType::Normal, val, false);
|
scope.push_dynamic_value(name.clone(), ScopeEntryType::Normal, val, false);
|
||||||
Ok(().into_dynamic())
|
Ok(Dynamic::from_unit())
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt::Let(name, None, _) => {
|
Stmt::Let(name, None, _) => {
|
||||||
// TODO - avoid copying variable name in inner block?
|
// TODO - avoid copying variable name in inner block?
|
||||||
scope.push(name.clone(), ());
|
scope.push(name.clone(), ());
|
||||||
Ok(().into_dynamic())
|
Ok(Dynamic::from_unit())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Const statement
|
// Const statement
|
||||||
@ -1676,7 +1638,7 @@ impl Engine<'_> {
|
|||||||
let val = self.eval_expr(scope, fn_lib, expr, level)?;
|
let val = self.eval_expr(scope, fn_lib, expr, level)?;
|
||||||
// TODO - avoid copying variable name in inner block?
|
// TODO - avoid copying variable name in inner block?
|
||||||
scope.push_dynamic_value(name.clone(), ScopeEntryType::Constant, val, true);
|
scope.push_dynamic_value(name.clone(), ScopeEntryType::Constant, val, true);
|
||||||
Ok(().into_dynamic())
|
Ok(Dynamic::from_unit())
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt::Const(_, _, _) => panic!("constant expression not constant!"),
|
Stmt::Const(_, _, _) => panic!("constant expression not constant!"),
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::any::{Any, Dynamic};
|
use crate::any::{Dynamic, Variant};
|
||||||
|
|
||||||
use crate::stdlib::{string::String, vec, vec::Vec};
|
use crate::stdlib::{string::String, vec, vec::Vec};
|
||||||
|
|
||||||
/// Trait that represent arguments to a function call.
|
/// Trait that represent arguments to a function call.
|
||||||
@ -18,7 +17,7 @@ pub trait FuncArgs {
|
|||||||
/// converted into `Dynamic`).
|
/// converted into `Dynamic`).
|
||||||
macro_rules! impl_args {
|
macro_rules! impl_args {
|
||||||
($($p:ident),*) => {
|
($($p:ident),*) => {
|
||||||
impl<$($p: Any + Clone),*> FuncArgs for ($($p,)*)
|
impl<$($p: Variant + Clone),*> FuncArgs for ($($p,)*)
|
||||||
{
|
{
|
||||||
fn into_vec(self) -> Vec<Dynamic> {
|
fn into_vec(self) -> Vec<Dynamic> {
|
||||||
let ($($p,)*) = self;
|
let ($($p,)*) = self;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#![cfg(not(feature = "no_function"))]
|
#![cfg(not(feature = "no_function"))]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::any::Any;
|
use crate::any::Variant;
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::error::ParseError;
|
use crate::error::ParseError;
|
||||||
use crate::parser::AST;
|
use crate::parser::AST;
|
||||||
@ -88,7 +88,7 @@ macro_rules! def_anonymous_fn {
|
|||||||
def_anonymous_fn!(imp);
|
def_anonymous_fn!(imp);
|
||||||
};
|
};
|
||||||
(imp $($par:ident),*) => {
|
(imp $($par:ident),*) => {
|
||||||
impl<'e, $($par: Any + Clone,)* RET: Any + Clone> Func<($($par,)*), RET> for Engine<'e>
|
impl<'e, $($par: Variant + Clone,)* RET: Variant + Clone> Func<($($par,)*), RET> for Engine<'e>
|
||||||
{
|
{
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
type Output = Box<dyn Fn($($par),*) -> Result<RET, EvalAltResult> + Send + Sync + 'e>;
|
type Output = Box<dyn Fn($($par),*) -> Result<RET, EvalAltResult> + Send + Sync + 'e>;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::any::{Any, Dynamic};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::engine::{Engine, FnCallArgs};
|
use crate::engine::{Engine, FnCallArgs};
|
||||||
use crate::parser::Position;
|
use crate::parser::Position;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
@ -53,7 +53,7 @@ pub trait RegisterDynamicFn<FN, ARGS> {
|
|||||||
///
|
///
|
||||||
/// // Function that returns a Dynamic value
|
/// // Function that returns a Dynamic value
|
||||||
/// fn return_the_same_as_dynamic(x: i64) -> Dynamic {
|
/// fn return_the_same_as_dynamic(x: i64) -> Dynamic {
|
||||||
/// Box::new(x)
|
/// Dynamic::from(x)
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let mut engine = Engine::new();
|
/// let mut engine = Engine::new();
|
||||||
@ -137,7 +137,7 @@ macro_rules! def_register {
|
|||||||
// ^ function parameter actual type (T, &T or &mut T)
|
// ^ function parameter actual type (T, &T or &mut T)
|
||||||
// ^ dereferencing function
|
// ^ dereferencing function
|
||||||
impl<
|
impl<
|
||||||
$($par: Any + Clone,)*
|
$($par: Variant + Clone,)*
|
||||||
|
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
FN: Fn($($param),*) -> RET + Send + Sync + 'static,
|
FN: Fn($($param),*) -> RET + Send + Sync + 'static,
|
||||||
@ -145,7 +145,7 @@ macro_rules! def_register {
|
|||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
FN: Fn($($param),*) -> RET + 'static,
|
FN: Fn($($param),*) -> RET + 'static,
|
||||||
|
|
||||||
RET: Any
|
RET: Variant + Clone
|
||||||
> RegisterFn<FN, ($($mark,)*), RET> for Engine<'_>
|
> RegisterFn<FN, ($($mark,)*), RET> for Engine<'_>
|
||||||
{
|
{
|
||||||
fn register_fn(&mut self, name: &str, f: FN) {
|
fn register_fn(&mut self, name: &str, f: FN) {
|
||||||
@ -163,13 +163,13 @@ macro_rules! def_register {
|
|||||||
let mut drain = args.iter_mut();
|
let mut drain = args.iter_mut();
|
||||||
$(
|
$(
|
||||||
// Downcast every element, return in case of a type mismatch
|
// Downcast every element, return in case of a type mismatch
|
||||||
let $par = drain.next().unwrap().downcast_mut::<$par>().unwrap();
|
let $par: &mut $par = drain.next().unwrap().downcast_mut().unwrap();
|
||||||
)*
|
)*
|
||||||
|
|
||||||
// Call the user-supplied function using ($clone) to
|
// Call the user-supplied function using ($clone) to
|
||||||
// potentially clone the value, otherwise pass the reference.
|
// potentially clone the value, otherwise pass the reference.
|
||||||
let r = f($(($clone)($par)),*);
|
let r = f($(($clone)($par)),*);
|
||||||
Ok(Box::new(r) as Dynamic)
|
Ok(r.into_dynamic())
|
||||||
};
|
};
|
||||||
|
|
||||||
self.register_fn_raw(name, vec![$(TypeId::of::<$par>()),*], Box::new(func));
|
self.register_fn_raw(name, vec![$(TypeId::of::<$par>()),*], Box::new(func));
|
||||||
@ -177,7 +177,7 @@ macro_rules! def_register {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
$($par: Any + Clone,)*
|
$($par: Variant + Clone,)*
|
||||||
|
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
FN: Fn($($param),*) -> Dynamic + Send + Sync + 'static,
|
FN: Fn($($param),*) -> Dynamic + Send + Sync + 'static,
|
||||||
@ -201,7 +201,7 @@ macro_rules! def_register {
|
|||||||
let mut drain = args.iter_mut();
|
let mut drain = args.iter_mut();
|
||||||
$(
|
$(
|
||||||
// Downcast every element, return in case of a type mismatch
|
// Downcast every element, return in case of a type mismatch
|
||||||
let $par = drain.next().unwrap().downcast_mut::<$par>().unwrap();
|
let $par: &mut $par = drain.next().unwrap().downcast_mut().unwrap();
|
||||||
)*
|
)*
|
||||||
|
|
||||||
// Call the user-supplied function using ($clone) to
|
// Call the user-supplied function using ($clone) to
|
||||||
@ -213,14 +213,14 @@ macro_rules! def_register {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
$($par: Any + Clone,)*
|
$($par: Variant + Clone,)*
|
||||||
|
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
FN: Fn($($param),*) -> Result<RET, EvalAltResult> + Send + Sync + 'static,
|
FN: Fn($($param),*) -> Result<RET, EvalAltResult> + Send + Sync + 'static,
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
FN: Fn($($param),*) -> Result<RET, EvalAltResult> + 'static,
|
FN: Fn($($param),*) -> Result<RET, EvalAltResult> + 'static,
|
||||||
|
|
||||||
RET: Any
|
RET: Variant + Clone
|
||||||
> RegisterResultFn<FN, ($($mark,)*), RET> for Engine<'_>
|
> RegisterResultFn<FN, ($($mark,)*), RET> for Engine<'_>
|
||||||
{
|
{
|
||||||
fn register_result_fn(&mut self, name: &str, f: FN) {
|
fn register_result_fn(&mut self, name: &str, f: FN) {
|
||||||
@ -238,12 +238,12 @@ macro_rules! def_register {
|
|||||||
let mut drain = args.iter_mut();
|
let mut drain = args.iter_mut();
|
||||||
$(
|
$(
|
||||||
// Downcast every element, return in case of a type mismatch
|
// Downcast every element, return in case of a type mismatch
|
||||||
let $par = drain.next().unwrap().downcast_mut::<$par>().unwrap();
|
let $par: &mut $par = drain.next().unwrap().downcast_mut().unwrap();
|
||||||
)*
|
)*
|
||||||
|
|
||||||
// Call the user-supplied function using ($clone) to
|
// Call the user-supplied function using ($clone) to
|
||||||
// potentially clone the value, otherwise pass the reference.
|
// potentially clone the value, otherwise pass the reference.
|
||||||
f($(($clone)($par)),*).map(|r| Box::new(r) as Dynamic)
|
f($(($clone)($par)),*).map(|r| r.into_dynamic())
|
||||||
.map_err(|err| err.set_position(pos))
|
.map_err(|err| err.set_position(pos))
|
||||||
};
|
};
|
||||||
self.register_fn_raw(name, vec![$(TypeId::of::<$par>()),*], Box::new(func));
|
self.register_fn_raw(name, vec![$(TypeId::of::<$par>()),*], Box::new(func));
|
||||||
|
@ -83,7 +83,7 @@ mod result;
|
|||||||
mod scope;
|
mod scope;
|
||||||
mod stdlib;
|
mod stdlib;
|
||||||
|
|
||||||
pub use any::{Any, AnyExt, Dynamic, Variant};
|
pub use any::Dynamic;
|
||||||
pub use engine::Engine;
|
pub use engine::Engine;
|
||||||
pub use error::{ParseError, ParseErrorType};
|
pub use error::{ParseError, ParseErrorType};
|
||||||
pub use fn_call::FuncArgs;
|
pub use fn_call::FuncArgs;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::any::{Any, Dynamic};
|
use crate::any::Dynamic;
|
||||||
use crate::engine::{
|
use crate::engine::{
|
||||||
Engine, FnAny, FnCallArgs, FnSpec, FunctionsLib, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT,
|
Engine, FnAny, FnCallArgs, FnSpec, FunctionsLib, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT,
|
||||||
KEYWORD_TYPE_OF,
|
KEYWORD_TYPE_OF,
|
||||||
@ -116,7 +116,7 @@ fn call_fn(
|
|||||||
) -> Result<Option<Dynamic>, EvalAltResult> {
|
) -> Result<Option<Dynamic>, EvalAltResult> {
|
||||||
let spec = FnSpec {
|
let spec = FnSpec {
|
||||||
name: fn_name.into(),
|
name: fn_name.into(),
|
||||||
args: args.iter().map(|a| Any::type_id(*a)).collect(),
|
args: args.iter().map(|a| a.type_id()).collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Search built-in's and external functions
|
// Search built-in's and external functions
|
||||||
@ -570,7 +570,7 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut arg_values: Vec<_> = args.iter().map(Expr::get_constant_value).collect();
|
let mut arg_values: Vec<_> = args.iter().map(Expr::get_constant_value).collect();
|
||||||
let mut call_args: Vec<_> = arg_values.iter_mut().map(Dynamic::as_mut).collect();
|
let mut call_args: Vec<_> = arg_values.iter_mut().collect();
|
||||||
|
|
||||||
// Save the typename of the first argument if it is `type_of()`
|
// Save the typename of the first argument if it is `type_of()`
|
||||||
// This is to avoid `call_args` being passed into the closure
|
// This is to avoid `call_args` being passed into the closure
|
||||||
@ -585,7 +585,7 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
result.or_else(|| {
|
result.or_else(|| {
|
||||||
if !arg_for_type_of.is_empty() {
|
if !arg_for_type_of.is_empty() {
|
||||||
// Handle `type_of()`
|
// Handle `type_of()`
|
||||||
Some(arg_for_type_of.to_string().into_dynamic())
|
Some(Dynamic::from_string(arg_for_type_of.to_string()))
|
||||||
} else {
|
} else {
|
||||||
// Otherwise use the default value, if any
|
// Otherwise use the default value, if any
|
||||||
def_value.clone()
|
def_value.clone()
|
||||||
|
148
src/parser.rs
148
src/parser.rs
@ -1,7 +1,7 @@
|
|||||||
//! Main module defining the lexer and parser.
|
//! Main module defining the lexer and parser.
|
||||||
|
|
||||||
use crate::any::{Any, AnyExt, Dynamic};
|
use crate::any::{Dynamic, Union};
|
||||||
use crate::engine::{Array, Engine, FunctionsLib, Map};
|
use crate::engine::{Engine, FunctionsLib};
|
||||||
use crate::error::{LexError, ParseError, ParseErrorType};
|
use crate::error::{LexError, ParseError, ParseErrorType};
|
||||||
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||||
@ -440,25 +440,30 @@ impl Expr {
|
|||||||
/// Panics when the expression is not constant.
|
/// Panics when the expression is not constant.
|
||||||
pub fn get_constant_value(&self) -> Dynamic {
|
pub fn get_constant_value(&self) -> Dynamic {
|
||||||
match self {
|
match self {
|
||||||
Self::IntegerConstant(i, _) => i.into_dynamic(),
|
Self::IntegerConstant(i, _) => Dynamic::from_int(*i),
|
||||||
Self::FloatConstant(f, _) => f.into_dynamic(),
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::CharConstant(c, _) => c.into_dynamic(),
|
Self::FloatConstant(f, _) => Dynamic::from_float(*f),
|
||||||
Self::StringConstant(s, _) => s.clone().into_owned().into_dynamic(),
|
Self::CharConstant(c, _) => Dynamic::from_char(*c),
|
||||||
Self::True(_) => true.into_dynamic(),
|
Self::StringConstant(s, _) => Dynamic::from_string(s.to_string()),
|
||||||
Self::False(_) => false.into_dynamic(),
|
Self::True(_) => Dynamic::from_bool(true),
|
||||||
Self::Unit(_) => ().into_dynamic(),
|
Self::False(_) => Dynamic::from_bool(false),
|
||||||
|
Self::Unit(_) => Dynamic::from_unit(),
|
||||||
|
|
||||||
Self::Array(items, _) if items.iter().all(Self::is_constant) => items
|
Self::Array(items, _) if items.iter().all(Self::is_constant) => Dynamic(Union::Array(
|
||||||
.iter()
|
items
|
||||||
.map(Self::get_constant_value)
|
.iter()
|
||||||
.collect::<Vec<_>>()
|
.map(Self::get_constant_value)
|
||||||
.into_dynamic(),
|
.collect::<Vec<_>>(),
|
||||||
|
)),
|
||||||
|
|
||||||
Self::Map(items, _) if items.iter().all(|(_, v, _)| v.is_constant()) => items
|
Self::Map(items, _) if items.iter().all(|(_, v, _)| v.is_constant()) => {
|
||||||
.iter()
|
Dynamic(Union::Map(Box::new(
|
||||||
.map(|(k, v, _)| (k.clone(), v.get_constant_value()))
|
items
|
||||||
.collect::<HashMap<_, _>>()
|
.iter()
|
||||||
.into_dynamic(),
|
.map(|(k, v, _)| (k.clone(), v.get_constant_value()))
|
||||||
|
.collect::<HashMap<_, _>>(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
_ => panic!("cannot get value of non-constant expression"),
|
_ => panic!("cannot get value of non-constant expression"),
|
||||||
}
|
}
|
||||||
@ -1958,7 +1963,7 @@ fn parse_unary<'a>(
|
|||||||
Ok(Expr::FunctionCall(
|
Ok(Expr::FunctionCall(
|
||||||
"!".into(),
|
"!".into(),
|
||||||
vec![parse_primary(input, allow_stmt_expr)?],
|
vec![parse_primary(input, allow_stmt_expr)?],
|
||||||
Some(Box::new(false)), // NOT operator, when operating on invalid operand, defaults to false
|
Some(Dynamic::from_bool(false)), // NOT operator, when operating on invalid operand, defaults to false
|
||||||
pos,
|
pos,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -2270,37 +2275,37 @@ fn parse_binary_op<'a>(
|
|||||||
Token::EqualsTo => Expr::FunctionCall(
|
Token::EqualsTo => Expr::FunctionCall(
|
||||||
"==".into(),
|
"==".into(),
|
||||||
vec![current_lhs, rhs],
|
vec![current_lhs, rhs],
|
||||||
Some((false).into_dynamic()),
|
Some(Dynamic::from_bool(false)),
|
||||||
pos,
|
pos,
|
||||||
),
|
),
|
||||||
Token::NotEqualsTo => Expr::FunctionCall(
|
Token::NotEqualsTo => Expr::FunctionCall(
|
||||||
"!=".into(),
|
"!=".into(),
|
||||||
vec![current_lhs, rhs],
|
vec![current_lhs, rhs],
|
||||||
Some((false).into_dynamic()),
|
Some(Dynamic::from_bool(false)),
|
||||||
pos,
|
pos,
|
||||||
),
|
),
|
||||||
Token::LessThan => Expr::FunctionCall(
|
Token::LessThan => Expr::FunctionCall(
|
||||||
"<".into(),
|
"<".into(),
|
||||||
vec![current_lhs, rhs],
|
vec![current_lhs, rhs],
|
||||||
Some((false).into_dynamic()),
|
Some(Dynamic::from_bool(false)),
|
||||||
pos,
|
pos,
|
||||||
),
|
),
|
||||||
Token::LessThanEqualsTo => Expr::FunctionCall(
|
Token::LessThanEqualsTo => Expr::FunctionCall(
|
||||||
"<=".into(),
|
"<=".into(),
|
||||||
vec![current_lhs, rhs],
|
vec![current_lhs, rhs],
|
||||||
Some((false).into_dynamic()),
|
Some(Dynamic::from_bool(false)),
|
||||||
pos,
|
pos,
|
||||||
),
|
),
|
||||||
Token::GreaterThan => Expr::FunctionCall(
|
Token::GreaterThan => Expr::FunctionCall(
|
||||||
">".into(),
|
">".into(),
|
||||||
vec![current_lhs, rhs],
|
vec![current_lhs, rhs],
|
||||||
Some((false).into_dynamic()),
|
Some(Dynamic::from_bool(false)),
|
||||||
pos,
|
pos,
|
||||||
),
|
),
|
||||||
Token::GreaterThanEqualsTo => Expr::FunctionCall(
|
Token::GreaterThanEqualsTo => Expr::FunctionCall(
|
||||||
">=".into(),
|
">=".into(),
|
||||||
vec![current_lhs, rhs],
|
vec![current_lhs, rhs],
|
||||||
Some((false).into_dynamic()),
|
Some(Dynamic::from_bool(false)),
|
||||||
pos,
|
pos,
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -2845,67 +2850,50 @@ pub fn parse<'a, 'e>(
|
|||||||
///
|
///
|
||||||
/// Returns Some(expression) if conversion is successful. Otherwise None.
|
/// Returns Some(expression) if conversion is successful. Otherwise None.
|
||||||
pub fn map_dynamic_to_expr(value: Dynamic, pos: Position) -> Option<Expr> {
|
pub fn map_dynamic_to_expr(value: Dynamic, pos: Position) -> Option<Expr> {
|
||||||
if value.is::<INT>() {
|
match value.0 {
|
||||||
Some(Expr::IntegerConstant(value.cast(), pos))
|
Union::Unit(_) => Some(Expr::Unit(pos)),
|
||||||
} else if value.is::<char>() {
|
Union::Int(value) => Some(Expr::IntegerConstant(value, pos)),
|
||||||
Some(Expr::CharConstant(value.cast(), pos))
|
Union::Char(value) => Some(Expr::CharConstant(value, pos)),
|
||||||
} else if value.is::<String>() {
|
Union::Str(value) => Some(Expr::StringConstant(value.into(), pos)),
|
||||||
Some(Expr::StringConstant(value.cast::<String>().into(), pos))
|
Union::Bool(true) => Some(Expr::True(pos)),
|
||||||
} else if value.is::<bool>() {
|
Union::Bool(false) => Some(Expr::False(pos)),
|
||||||
Some(if value.cast::<bool>() {
|
|
||||||
Expr::True(pos)
|
|
||||||
} else {
|
|
||||||
Expr::False(pos)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
Union::Array(array) => {
|
||||||
if value.is::<Array>() {
|
let items: Vec<_> = array
|
||||||
let array = value.cast::<Array>();
|
.into_iter()
|
||||||
let items: Vec<_> = array
|
.map(|x| map_dynamic_to_expr(x, pos))
|
||||||
.into_iter()
|
.collect();
|
||||||
.map(|x| map_dynamic_to_expr(x, pos))
|
|
||||||
.collect();
|
if items.iter().all(Option::is_some) {
|
||||||
if items.iter().all(Option::is_some) {
|
Some(Expr::Array(
|
||||||
return Some(Expr::Array(
|
items.into_iter().map(Option::unwrap).collect(),
|
||||||
items.into_iter().map(Option::unwrap).collect(),
|
pos,
|
||||||
pos,
|
))
|
||||||
));
|
} else {
|
||||||
} else {
|
None
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
Union::Map(map) => {
|
||||||
if value.is::<Map>() {
|
let items: Vec<_> = map
|
||||||
let map = value.cast::<Map>();
|
.into_iter()
|
||||||
let items: Vec<_> = map
|
.map(|(k, v)| (k, map_dynamic_to_expr(v, pos), pos))
|
||||||
.into_iter()
|
.collect();
|
||||||
.map(|(k, v)| (k, map_dynamic_to_expr(v, pos), pos))
|
if items.iter().all(|(_, expr, _)| expr.is_some()) {
|
||||||
.collect();
|
Some(Expr::Map(
|
||||||
if items.iter().all(|(_, expr, _)| expr.is_some()) {
|
items
|
||||||
return Some(Expr::Map(
|
.into_iter()
|
||||||
items
|
.map(|(k, expr, pos)| (k, expr.unwrap(), pos))
|
||||||
.into_iter()
|
.collect(),
|
||||||
.map(|(k, expr, pos)| (k, expr.unwrap(), pos))
|
pos,
|
||||||
.collect(),
|
))
|
||||||
pos,
|
} else {
|
||||||
));
|
None
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
{
|
Union::Float(value) => Some(Expr::FloatConstant(value, pos)),
|
||||||
if value.is::<FLOAT>() {
|
|
||||||
return Some(Expr::FloatConstant(value.cast(), pos));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
35
src/scope.rs
35
src/scope.rs
@ -1,6 +1,6 @@
|
|||||||
//! 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::{Any, Dynamic};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::parser::{map_dynamic_to_expr, Expr, Position};
|
use crate::parser::{map_dynamic_to_expr, Expr, Position};
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
@ -20,7 +20,7 @@ pub enum EntryType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An entry in the Scope.
|
/// An entry in the Scope.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub struct Entry<'a> {
|
pub struct Entry<'a> {
|
||||||
/// Name of the entry.
|
/// Name of the entry.
|
||||||
pub name: Cow<'a, str>,
|
pub name: Cow<'a, str>,
|
||||||
@ -68,7 +68,7 @@ pub(crate) struct EntryRef<'a> {
|
|||||||
/// allowing for automatic _shadowing_.
|
/// allowing for automatic _shadowing_.
|
||||||
///
|
///
|
||||||
/// Currently, `Scope` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
|
/// Currently, `Scope` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub struct Scope<'a>(Vec<Entry<'a>>);
|
pub struct Scope<'a>(Vec<Entry<'a>>);
|
||||||
|
|
||||||
impl<'a> Scope<'a> {
|
impl<'a> Scope<'a> {
|
||||||
@ -157,8 +157,8 @@ impl<'a> Scope<'a> {
|
|||||||
/// my_scope.push("x", 42_i64);
|
/// my_scope.push("x", 42_i64);
|
||||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn push<K: Into<Cow<'a, str>>, T: Any + Clone>(&mut self, name: K, value: T) {
|
pub fn push<K: Into<Cow<'a, str>>, T: Variant + Clone>(&mut self, name: K, value: T) {
|
||||||
self.push_dynamic_value(name, EntryType::Normal, value.into_dynamic(), false);
|
self.push_dynamic_value(name, EntryType::Normal, Dynamic::from(value), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add (push) a new `Dynamic` entry to the Scope.
|
/// Add (push) a new `Dynamic` entry to the Scope.
|
||||||
@ -166,11 +166,11 @@ impl<'a> Scope<'a> {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use rhai::{Any, Scope};
|
/// use rhai::{Dynamic, Scope};
|
||||||
///
|
///
|
||||||
/// let mut my_scope = Scope::new();
|
/// let mut my_scope = Scope::new();
|
||||||
///
|
///
|
||||||
/// my_scope.push_dynamic("x", (42_i64).into_dynamic());
|
/// my_scope.push_dynamic("x", Dynamic::from(42_i64));
|
||||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn push_dynamic<K: Into<Cow<'a, str>>>(&mut self, name: K, value: Dynamic) {
|
pub fn push_dynamic<K: Into<Cow<'a, str>>>(&mut self, name: K, value: Dynamic) {
|
||||||
@ -195,8 +195,8 @@ impl<'a> Scope<'a> {
|
|||||||
/// my_scope.push_constant("x", 42_i64);
|
/// my_scope.push_constant("x", 42_i64);
|
||||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn push_constant<K: Into<Cow<'a, str>>, T: Any + Clone>(&mut self, name: K, value: T) {
|
pub fn push_constant<K: Into<Cow<'a, str>>, T: Variant + Clone>(&mut self, name: K, value: T) {
|
||||||
self.push_dynamic_value(name, EntryType::Constant, value.into_dynamic(), true);
|
self.push_dynamic_value(name, EntryType::Constant, Dynamic::from(value), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add (push) a new constant with a `Dynamic` value to the Scope.
|
/// Add (push) a new constant with a `Dynamic` value to the Scope.
|
||||||
@ -211,11 +211,11 @@ impl<'a> Scope<'a> {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use rhai::{Any, Scope};
|
/// use rhai::{Dynamic, Scope};
|
||||||
///
|
///
|
||||||
/// let mut my_scope = Scope::new();
|
/// let mut my_scope = Scope::new();
|
||||||
///
|
///
|
||||||
/// my_scope.push_constant_dynamic("x", (42_i64).into_dynamic());
|
/// my_scope.push_constant_dynamic("x", Dynamic::from(42_i64));
|
||||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn push_constant_dynamic<K: Into<Cow<'a, str>>>(&mut self, name: K, value: Dynamic) {
|
pub fn push_constant_dynamic<K: Into<Cow<'a, str>>>(&mut self, name: K, value: Dynamic) {
|
||||||
@ -336,13 +336,12 @@ impl<'a> Scope<'a> {
|
|||||||
/// my_scope.push("x", 42_i64);
|
/// my_scope.push("x", 42_i64);
|
||||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_value<T: Any + Clone>(&self, name: &str) -> Option<T> {
|
pub fn get_value<T: Variant + Clone>(&self, name: &str) -> Option<T> {
|
||||||
self.0
|
self.0
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.find(|Entry { name: key, .. }| name == key)
|
.find(|Entry { name: key, .. }| name == key)
|
||||||
.and_then(|Entry { value, .. }| value.downcast_ref::<T>())
|
.and_then(|Entry { value, .. }| value.downcast_ref::<T>().cloned())
|
||||||
.map(T::clone)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the value of the named entry.
|
/// Update the value of the named entry.
|
||||||
@ -366,7 +365,7 @@ impl<'a> Scope<'a> {
|
|||||||
/// my_scope.set_value("x", 0_i64);
|
/// my_scope.set_value("x", 0_i64);
|
||||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 0);
|
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 0);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn set_value<T: Any + Clone>(&mut self, name: &'a str, value: T) {
|
pub fn set_value<T: Variant + Clone>(&mut self, name: &'a str, value: T) {
|
||||||
match self.get(name) {
|
match self.get(name) {
|
||||||
Some((
|
Some((
|
||||||
EntryRef {
|
EntryRef {
|
||||||
@ -382,8 +381,8 @@ impl<'a> Scope<'a> {
|
|||||||
..
|
..
|
||||||
},
|
},
|
||||||
_,
|
_,
|
||||||
)) => self.0.get_mut(index).unwrap().value = value.into_dynamic(),
|
)) => self.0.get_mut(index).unwrap().value = Dynamic::from(value),
|
||||||
None => self.push(name, value.into_dynamic()),
|
None => self.push(name, value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +402,7 @@ impl<'a> Scope<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a mutable reference to an entry in the Scope and downcast it to a specific type
|
/// Get a mutable reference to an entry in the Scope and downcast it to a specific type
|
||||||
pub(crate) fn get_mut_by_type<T: Any + Clone>(&mut self, key: EntryRef) -> &mut T {
|
pub(crate) fn get_mut_by_type<T: Variant + Clone>(&mut self, key: EntryRef) -> &mut T {
|
||||||
self.get_mut(key)
|
self.get_mut(key)
|
||||||
.downcast_mut::<T>()
|
.downcast_mut::<T>()
|
||||||
.expect("wrong type cast")
|
.expect("wrong type cast")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#![cfg(not(feature = "no_object"))]
|
#![cfg(not(feature = "no_object"))]
|
||||||
|
|
||||||
use rhai::{AnyExt, Engine, EvalAltResult, Map, Scope, INT};
|
use rhai::{Engine, EvalAltResult, Map, Scope, INT};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_map_indexing() -> Result<(), EvalAltResult> {
|
fn test_map_indexing() -> Result<(), EvalAltResult> {
|
||||||
|
Loading…
Reference in New Issue
Block a user