Refine indexer set.

This commit is contained in:
Stephen Chung 2020-08-01 12:21:15 +08:00
parent 5873bccd50
commit af2f8acb5d
2 changed files with 58 additions and 54 deletions

View File

@ -721,8 +721,9 @@ impl Engine {
Expr::Dot(x) | Expr::Index(x) => { Expr::Dot(x) | Expr::Index(x) => {
let (idx, expr, pos) = x.as_ref(); let (idx, expr, pos) = x.as_ref();
let idx_pos = idx.position(); let idx_pos = idx.position();
let obj_ptr = &mut self let obj_ptr = &mut self.get_indexed_mut(
.get_indexed_mut(state, lib, target, idx_val, idx_pos, false, level)?; state, lib, target, idx_val, idx_pos, false, true, level,
)?;
self.eval_dot_index_chain_helper( self.eval_dot_index_chain_helper(
state, lib, this_ptr, obj_ptr, expr, idx_values, next_chain, level, state, lib, this_ptr, obj_ptr, expr, idx_values, next_chain, level,
@ -735,14 +736,9 @@ impl Engine {
let mut idx_val2 = idx_val.clone(); let mut idx_val2 = idx_val.clone();
// `call_setter` is introduced to bypass double mutable borrowing of target // `call_setter` is introduced to bypass double mutable borrowing of target
let mut call_setter = match self let _call_setter = match self
.get_indexed_mut(state, lib, target, idx_val, pos, true, level) .get_indexed_mut(state, lib, target, idx_val, pos, true, false, level)
{ {
// Indexed value is an owned value - the only possibility is a value from an indexer.
// Try to call an index setter to update it back, but no need to raise an error
// if the indexer is read-only.
#[cfg(not(feature = "no_index"))]
Ok(obj_ptr) if obj_ptr.is_value() => Some((false, _new_val.unwrap())),
// Indexed value is a reference - update directly // Indexed value is a reference - update directly
Ok(ref mut obj_ptr) => { Ok(ref mut obj_ptr) => {
obj_ptr obj_ptr
@ -753,37 +749,42 @@ impl Engine {
} }
Err(err) => match *err { Err(err) => match *err {
// No index getter - try to call an index setter // No index getter - try to call an index setter
#[cfg(not(feature = "no_index"))]
EvalAltResult::ErrorIndexingType(_, _) => { EvalAltResult::ErrorIndexingType(_, _) => {
// Raise error if there is no index getter nor setter // Raise error if there is no index getter nor setter
Some((true, _new_val.unwrap())) Some(_new_val.unwrap())
} }
// Any other error - return // Any other error - return
err => return Err(Box::new(err)), err => return Err(Box::new(err)),
}, },
}; };
if let Some((must_have_setter, ref mut new_val)) = call_setter { #[cfg(not(feature = "no_index"))]
let args = &mut [target.as_mut(), &mut idx_val2, new_val]; if let Some(mut new_val) = _call_setter {
let val = target.as_mut();
let val_type_name = val.type_name();
let args = &mut [val, &mut idx_val2, &mut new_val];
match self.exec_fn_call( self.exec_fn_call(
state, lib, FN_IDX_SET, 0, args, is_ref, true, false, None, None, state, lib, FN_IDX_SET, 0, args, is_ref, true, false, None, None,
level, level,
) { )
Ok(_) => (), .map_err(|err| match *err {
Err(err) if !must_have_setter => match *err { EvalAltResult::ErrorFunctionNotFound(_, _) => {
// If there is no index setter, no need to set it back because the indexer is read-only EvalAltResult::ErrorIndexingType(
EvalAltResult::ErrorFunctionNotFound(_, _) => (), self.map_type_name(val_type_name).into(),
_ => return Err(err), Position::none(),
}, )
err => return err, }
} err => err,
})?;
} }
Ok(Default::default()) Ok(Default::default())
} }
// xxx[rhs] // xxx[rhs]
_ => self _ => self
.get_indexed_mut(state, lib, target, idx_val, pos, false, level) .get_indexed_mut(state, lib, target, idx_val, pos, false, true, level)
.map(|v| (v.clone_into_dynamic(), false)), .map(|v| (v.clone_into_dynamic(), false)),
} }
} }
@ -806,8 +807,8 @@ impl Engine {
Expr::Property(x) if target.is::<Map>() && _new_val.is_some() => { Expr::Property(x) if target.is::<Map>() && _new_val.is_some() => {
let ((prop, _, _), pos) = x.as_ref(); let ((prop, _, _), pos) = x.as_ref();
let index = prop.clone().into(); let index = prop.clone().into();
let mut val = let mut val = self
self.get_indexed_mut(state, lib, target, index, *pos, true, level)?; .get_indexed_mut(state, lib, target, index, *pos, true, false, level)?;
val.set_value(_new_val.unwrap()) val.set_value(_new_val.unwrap())
.map_err(|err| err.new_position(rhs.position()))?; .map_err(|err| err.new_position(rhs.position()))?;
@ -817,8 +818,9 @@ impl Engine {
Expr::Property(x) if target.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 = let val = self.get_indexed_mut(
self.get_indexed_mut(state, lib, target, index, *pos, false, level)?; state, lib, target, index, *pos, false, false, level,
)?;
Ok((val.clone_into_dynamic(), false)) Ok((val.clone_into_dynamic(), false))
} }
@ -852,7 +854,9 @@ impl Engine {
Expr::Property(p) => { Expr::Property(p) => {
let ((prop, _, _), pos) = p.as_ref(); let ((prop, _, _), pos) = p.as_ref();
let index = prop.clone().into(); let index = prop.clone().into();
self.get_indexed_mut(state, lib, target, index, *pos, false, level)? self.get_indexed_mut(
state, lib, target, index, *pos, false, true, level,
)?
} }
// {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr // {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr
Expr::FnCall(x) if x.1.is_none() => { Expr::FnCall(x) if x.1.is_none() => {
@ -1125,6 +1129,7 @@ impl Engine {
mut _idx: Dynamic, mut _idx: Dynamic,
idx_pos: Position, idx_pos: Position,
_create: bool, _create: bool,
_indexers: bool,
_level: usize, _level: usize,
) -> Result<Target<'a>, Box<EvalAltResult>> { ) -> Result<Target<'a>, Box<EvalAltResult>> {
self.inc_operations(state)?; self.inc_operations(state)?;
@ -1201,7 +1206,7 @@ impl Engine {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
_ => { _ if _indexers => {
let type_name = val.type_name(); let type_name = val.type_name();
let args = &mut [val, &mut _idx]; let args = &mut [val, &mut _idx];
self.exec_fn_call( self.exec_fn_call(
@ -1216,7 +1221,6 @@ impl Engine {
}) })
} }
#[cfg(any(feature = "no_index", feature = "no_object"))]
_ => Err(Box::new(EvalAltResult::ErrorIndexingType( _ => Err(Box::new(EvalAltResult::ErrorIndexingType(
self.map_type_name(val.type_name()).into(), self.map_type_name(val.type_name()).into(),
Position::none(), Position::none(),

View File

@ -1188,30 +1188,30 @@ pub fn run_builtin_op_assignment(
let mut x = x.write_lock::<INT>().unwrap(); let mut x = x.write_lock::<INT>().unwrap();
let y = y.clone().cast::<INT>(); let y = y.clone().cast::<INT>();
#[cfg(not(feature = "unchecked"))] if cfg!(not(feature = "unchecked")) {
match op { match op {
"+=" => return Ok(Some(*x = add(*x, y)?)), "+=" => return Ok(Some(*x = add(*x, y)?)),
"-=" => return Ok(Some(*x = sub(*x, y)?)), "-=" => return Ok(Some(*x = sub(*x, y)?)),
"*=" => return Ok(Some(*x = mul(*x, y)?)), "*=" => return Ok(Some(*x = mul(*x, y)?)),
"/=" => return Ok(Some(*x = div(*x, y)?)), "/=" => return Ok(Some(*x = div(*x, y)?)),
"%=" => return Ok(Some(*x = modulo(*x, y)?)), "%=" => return Ok(Some(*x = modulo(*x, y)?)),
"~=" => return Ok(Some(*x = pow_i_i(*x, y)?)), "~=" => return Ok(Some(*x = pow_i_i(*x, y)?)),
">>=" => return Ok(Some(*x = shr(*x, y)?)), ">>=" => return Ok(Some(*x = shr(*x, y)?)),
"<<=" => return Ok(Some(*x = shl(*x, y)?)), "<<=" => return Ok(Some(*x = shl(*x, y)?)),
_ => (), _ => (),
} }
} else {
#[cfg(feature = "unchecked")] match op {
match op { "+=" => return Ok(Some(*x += y)),
"+=" => return Ok(Some(*x += y)), "-=" => return Ok(Some(*x -= y)),
"-=" => return Ok(Some(*x -= y)), "*=" => return Ok(Some(*x *= y)),
"*=" => return Ok(Some(*x *= y)), "/=" => return Ok(Some(*x /= y)),
"/=" => return Ok(Some(*x /= y)), "%=" => return Ok(Some(*x %= y)),
"%=" => return Ok(Some(*x %= y)), "~=" => return Ok(Some(*x = pow_i_i_u(*x, y)?)),
"~=" => return Ok(Some(*x = pow_i_i_u(*x, y)?)), ">>=" => return Ok(Some(*x = shr_u(*x, y)?)),
">>=" => return Ok(Some(*x = shr_u(*x, y)?)), "<<=" => return Ok(Some(*x = shl_u(*x, y)?)),
"<<=" => return Ok(Some(*x = shl_u(*x, y)?)), _ => (),
_ => (), }
} }
match op { match op {