Fix bug when setting character in string via a method call.
This commit is contained in:
parent
151cd1af48
commit
b6e1f652b6
@ -7,6 +7,11 @@ Version 0.15.1
|
|||||||
This is a minor release which enables updating indexers (via registered indexer setters) and supports functions
|
This is a minor release which enables updating indexers (via registered indexer setters) and supports functions
|
||||||
with `&str` parameters (maps transparently to `ImmutableString`).
|
with `&str` parameters (maps transparently to `ImmutableString`).
|
||||||
|
|
||||||
|
Buf fix
|
||||||
|
-------
|
||||||
|
|
||||||
|
* `let s="abc"; s[1].change_to('X');` now correctly sets the character '`X`' into '`s`' yielding `"aXc"`.
|
||||||
|
|
||||||
Breaking changes
|
Breaking changes
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Main module defining the script evaluation `Engine`.
|
//! Main module defining the script evaluation `Engine`.
|
||||||
|
|
||||||
use crate::any::{Dynamic, Union};
|
use crate::any::{Dynamic, Union, Variant};
|
||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::error::ParseErrorType;
|
use crate::error::ParseErrorType;
|
||||||
use crate::fn_native::{CallableFunction, Callback, FnCallArgs};
|
use crate::fn_native::{CallableFunction, Callback, FnCallArgs};
|
||||||
@ -105,6 +105,14 @@ impl Target<'_> {
|
|||||||
Self::StringChar(_, _, _) => false,
|
Self::StringChar(_, _, _) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Is the `Target` a specific type?
|
||||||
|
pub fn is<T: Variant + Clone>(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Target::Ref(r) => r.is::<T>(),
|
||||||
|
Target::Value(r) => r.is::<T>(),
|
||||||
|
Target::StringChar(_, _, _) => TypeId::of::<T>() == TypeId::of::<char>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Get the value of the `Target` as a `Dynamic`, cloning a referenced value if necessary.
|
/// Get the value of the `Target` as a `Dynamic`, cloning a referenced value if necessary.
|
||||||
pub fn clone_into_dynamic(self) -> Dynamic {
|
pub fn clone_into_dynamic(self) -> Dynamic {
|
||||||
match self {
|
match self {
|
||||||
@ -817,7 +825,7 @@ impl Engine {
|
|||||||
.map(|name| if name.is::<ImmutableString>() {
|
.map(|name| if name.is::<ImmutableString>() {
|
||||||
"&str | ImmutableString"
|
"&str | ImmutableString"
|
||||||
} else {
|
} else {
|
||||||
self.map_type_name(name.type_name())
|
self.map_type_name((*name).type_name())
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", ")
|
.join(", ")
|
||||||
@ -1006,9 +1014,7 @@ impl Engine {
|
|||||||
mut new_val: Option<Dynamic>,
|
mut new_val: Option<Dynamic>,
|
||||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||||
let is_ref = target.is_ref();
|
let is_ref = target.is_ref();
|
||||||
|
let is_value = target.is_value();
|
||||||
// Get a reference to the mutation target Dynamic
|
|
||||||
let obj = target.as_mut();
|
|
||||||
|
|
||||||
// Pop the last index value
|
// Pop the last index value
|
||||||
let mut idx_val = idx_values.pop();
|
let mut idx_val = idx_values.pop();
|
||||||
@ -1090,24 +1096,38 @@ impl Engine {
|
|||||||
let ((name, native, pos), _, hash, _, def_val) = x.as_ref();
|
let ((name, native, pos), _, hash, _, def_val) = x.as_ref();
|
||||||
let def_val = def_val.as_ref();
|
let def_val = def_val.as_ref();
|
||||||
|
|
||||||
let mut arg_values: StaticVec<_> = once(obj)
|
// Get a reference to the mutation target Dynamic
|
||||||
.chain(
|
let (result, updated) = {
|
||||||
idx_val
|
let obj = target.as_mut();
|
||||||
.downcast_mut::<StaticVec<Dynamic>>()
|
let mut arg_values: StaticVec<_> = once(obj)
|
||||||
.unwrap()
|
.chain(
|
||||||
.iter_mut(),
|
idx_val
|
||||||
)
|
.downcast_mut::<StaticVec<Dynamic>>()
|
||||||
.collect();
|
.unwrap()
|
||||||
let args = arg_values.as_mut();
|
.iter_mut(),
|
||||||
|
)
|
||||||
|
.collect();
|
||||||
|
let args = arg_values.as_mut();
|
||||||
|
|
||||||
self.exec_fn_call(state, lib, name, *native, *hash, args, is_ref, def_val, 0)
|
self.exec_fn_call(
|
||||||
.map_err(|err| EvalAltResult::new_position(err, *pos))
|
state, lib, name, *native, *hash, args, is_ref, def_val, 0,
|
||||||
|
)
|
||||||
|
.map_err(|err| EvalAltResult::new_position(err, *pos))?
|
||||||
|
};
|
||||||
|
|
||||||
|
// Feed the changed temp value back
|
||||||
|
if updated && !is_ref && !is_value {
|
||||||
|
let new_val = target.as_mut().clone();
|
||||||
|
target.set_value(new_val)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((result, updated))
|
||||||
}
|
}
|
||||||
// xxx.module::fn_name(...) - syntax error
|
// xxx.module::fn_name(...) - syntax error
|
||||||
Expr::FnCall(_) => unreachable!(),
|
Expr::FnCall(_) => unreachable!(),
|
||||||
// {xxx:map}.id = ???
|
// {xxx:map}.id = ???
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Property(x) if obj.is::<Map>() && new_val.is_some() => {
|
Expr::Property(x) if target.is::<Map>() && new_val.is_some() => {
|
||||||
let ((prop, _, _), pos) = x.as_ref();
|
let ((prop, _, _), pos) = x.as_ref();
|
||||||
let index = prop.clone().into();
|
let index = prop.clone().into();
|
||||||
let mut val = self.get_indexed_mut(state, lib, target, index, *pos, true)?;
|
let mut val = self.get_indexed_mut(state, lib, target, index, *pos, true)?;
|
||||||
@ -1118,7 +1138,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// {xxx:map}.id
|
// {xxx:map}.id
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Property(x) if obj.is::<Map>() => {
|
Expr::Property(x) if target.is::<Map>() => {
|
||||||
let ((prop, _, _), pos) = x.as_ref();
|
let ((prop, _, _), pos) = x.as_ref();
|
||||||
let index = prop.clone().into();
|
let index = prop.clone().into();
|
||||||
let val = self.get_indexed_mut(state, lib, target, index, *pos, false)?;
|
let val = self.get_indexed_mut(state, lib, target, index, *pos, false)?;
|
||||||
@ -1128,7 +1148,7 @@ impl Engine {
|
|||||||
// xxx.id = ???
|
// xxx.id = ???
|
||||||
Expr::Property(x) if new_val.is_some() => {
|
Expr::Property(x) if new_val.is_some() => {
|
||||||
let ((_, _, setter), pos) = x.as_ref();
|
let ((_, _, setter), pos) = x.as_ref();
|
||||||
let mut args = [obj, new_val.as_mut().unwrap()];
|
let mut args = [target.as_mut(), new_val.as_mut().unwrap()];
|
||||||
self.exec_fn_call(state, lib, setter, true, 0, &mut args, is_ref, None, 0)
|
self.exec_fn_call(state, lib, setter, true, 0, &mut args, is_ref, None, 0)
|
||||||
.map(|(v, _)| (v, true))
|
.map(|(v, _)| (v, true))
|
||||||
.map_err(|err| EvalAltResult::new_position(err, *pos))
|
.map_err(|err| EvalAltResult::new_position(err, *pos))
|
||||||
@ -1136,14 +1156,14 @@ impl Engine {
|
|||||||
// xxx.id
|
// xxx.id
|
||||||
Expr::Property(x) => {
|
Expr::Property(x) => {
|
||||||
let ((_, getter, _), pos) = x.as_ref();
|
let ((_, getter, _), pos) = x.as_ref();
|
||||||
let mut args = [obj];
|
let mut args = [target.as_mut()];
|
||||||
self.exec_fn_call(state, lib, getter, true, 0, &mut args, is_ref, None, 0)
|
self.exec_fn_call(state, lib, getter, true, 0, &mut args, is_ref, None, 0)
|
||||||
.map(|(v, _)| (v, false))
|
.map(|(v, _)| (v, false))
|
||||||
.map_err(|err| EvalAltResult::new_position(err, *pos))
|
.map_err(|err| EvalAltResult::new_position(err, *pos))
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
// {xxx:map}.prop[expr] | {xxx:map}.prop.expr
|
// {xxx:map}.prop[expr] | {xxx:map}.prop.expr
|
||||||
Expr::Index(x) | Expr::Dot(x) if obj.is::<Map>() => {
|
Expr::Index(x) | Expr::Dot(x) if target.is::<Map>() => {
|
||||||
let (prop, expr, pos) = x.as_ref();
|
let (prop, expr, pos) = x.as_ref();
|
||||||
let is_idx = matches!(rhs, Expr::Index(_));
|
let is_idx = matches!(rhs, Expr::Index(_));
|
||||||
|
|
||||||
@ -1164,7 +1184,7 @@ impl Engine {
|
|||||||
Expr::Index(x) | Expr::Dot(x) => {
|
Expr::Index(x) | Expr::Dot(x) => {
|
||||||
let (prop, expr, pos) = x.as_ref();
|
let (prop, expr, pos) = x.as_ref();
|
||||||
let is_idx = matches!(rhs, Expr::Index(_));
|
let is_idx = matches!(rhs, Expr::Index(_));
|
||||||
let args = &mut [obj, &mut Default::default()];
|
let args = &mut [target.as_mut(), &mut Default::default()];
|
||||||
|
|
||||||
let (mut val, updated) = if let Expr::Property(p) = prop {
|
let (mut val, updated) = if let Expr::Property(p) = prop {
|
||||||
let ((_, getter, _), _) = p.as_ref();
|
let ((_, getter, _), _) = p.as_ref();
|
||||||
|
Loading…
Reference in New Issue
Block a user