Add comments and minor refactor.

This commit is contained in:
Stephen Chung 2020-04-26 21:48:49 +08:00
parent f5c7d7cd0d
commit ce121ed6af

View File

@ -703,6 +703,8 @@ impl Engine {
} }
/// Chain-evaluate a dot/index chain. /// Chain-evaluate a dot/index chain.
/// Index values are pre-calculated and stored in `idx_list`.
/// Any spill-overs are stored in `idx_more`.
fn eval_dot_index_chain_helper( fn eval_dot_index_chain_helper(
&self, &self,
fn_lib: Option<&FunctionsLib>, fn_lib: Option<&FunctionsLib>,
@ -730,18 +732,18 @@ impl Engine {
// Pop the last index value // Pop the last index value
let mut idx_val; let mut idx_val;
let mut idx_fixed = idx_list; let mut idx_list = idx_list;
if let Some(val) = idx_more.pop() { if let Some(val) = idx_more.pop() {
// Values in variable list // Values in variable list
idx_val = val; idx_val = val;
} else { } else {
// No more value in variable list, pop from fixed list // No more value in variable list, pop from fixed list
let len = idx_fixed.len(); let len = idx_list.len();
let splits = idx_fixed.split_at_mut(len - 1); let splits = idx_list.split_at_mut(len - 1);
idx_val = mem::replace(splits.1.get_mut(0).unwrap(), ().into()); idx_val = mem::replace(splits.1.get_mut(0).unwrap(), ().into());
idx_fixed = splits.0; idx_list = splits.0;
} }
if is_index { if is_index {
@ -754,7 +756,7 @@ impl Engine {
let indexed_val = self.get_indexed_mut(obj, idx_val, idx.position(), op_pos, false)?; let indexed_val = self.get_indexed_mut(obj, idx_val, idx.position(), op_pos, false)?;
self.eval_dot_index_chain_helper( self.eval_dot_index_chain_helper(
fn_lib, indexed_val, idx_rhs.as_ref(), idx_fixed, idx_more, is_index, *pos, level, new_val fn_lib, indexed_val, idx_rhs.as_ref(), idx_list, idx_more, is_index, *pos, level, new_val
) )
} }
// xxx[rhs] = new_val // xxx[rhs] = new_val
@ -780,17 +782,19 @@ impl Engine {
// TODO - Remove assumption of side effects by checking whether the first parameter is &mut // TODO - Remove assumption of side effects by checking whether the first parameter is &mut
self.exec_fn_call(fn_lib, fn_name, &mut args, def_val, *pos, 0).map(|v| (v, true)) self.exec_fn_call(fn_lib, fn_name, &mut args, def_val, *pos, 0).map(|v| (v, true))
} }
// {xxx:map}.id = ???
Expr::Property(id, pos) if obj.is::<Map>() && new_val.is_some() => {
let mut indexed_val =
self.get_indexed_mut(obj, id.to_string().into(), *pos, op_pos, true)?;
indexed_val.set_value(new_val.unwrap(), rhs.position())?;
Ok((().into(), true))
}
// {xxx:map}.id // {xxx:map}.id
Expr::Property(id, pos) if obj.is::<Map>() => { Expr::Property(id, pos) if obj.is::<Map>() => {
let mut indexed_val = let indexed_val =
self.get_indexed_mut(obj, id.to_string().into(), *pos, op_pos, new_val.is_some())?; self.get_indexed_mut(obj, id.to_string().into(), *pos, op_pos, false)?;
if let Some(new_val) = new_val {
indexed_val.set_value(new_val, rhs.position())?;
Ok((().into(), true))
} else {
Ok((indexed_val.into_dynamic(), false)) Ok((indexed_val.into_dynamic(), false))
} }
}
// xxx.id = ??? // xxx.id = ???
Expr::Property(id, pos) if new_val.is_some() => { Expr::Property(id, pos) if new_val.is_some() => {
let fn_name = make_setter(id); let fn_name = make_setter(id);
@ -819,7 +823,7 @@ impl Engine {
))); )));
}; };
self.eval_dot_index_chain_helper( self.eval_dot_index_chain_helper(
fn_lib, indexed_val, dot_rhs, idx_fixed, idx_more, is_index, *pos, level, new_val fn_lib, indexed_val, dot_rhs, idx_list, idx_more, is_index, *pos, level, new_val
) )
} }
// xxx.idx_lhs[idx_expr] // xxx.idx_lhs[idx_expr]
@ -830,7 +834,7 @@ impl Engine {
let mut buf: Dynamic = ().into(); let mut buf: Dynamic = ().into();
let mut args = [obj, &mut buf]; let mut args = [obj, &mut buf];
let mut indexed_val = if let Expr::Property(id, pos) = dot_lhs.as_ref() { let indexed_val = &mut (if let Expr::Property(id, pos) = dot_lhs.as_ref() {
let fn_name = make_getter(id); let fn_name = make_getter(id);
self.exec_fn_call(fn_lib, &fn_name, &mut args[..1], None, *pos, 0)? self.exec_fn_call(fn_lib, &fn_name, &mut args[..1], None, *pos, 0)?
} else { } else {
@ -839,16 +843,16 @@ impl Engine {
"".to_string(), "".to_string(),
rhs.position(), rhs.position(),
))); )));
}; });
let (result, changed) = self.eval_dot_index_chain_helper( let (result, changed) = self.eval_dot_index_chain_helper(
fn_lib, (&mut indexed_val).into(), dot_rhs, idx_fixed, idx_more, is_index, *pos, level, new_val fn_lib, indexed_val.into(), dot_rhs, idx_list, idx_more, is_index, *pos, level, new_val
)?; )?;
// Feed the value back via a setter just in case it has been updated // Feed the value back via a setter just in case it has been updated
if changed { if changed {
if let Expr::Property(id, pos) = dot_lhs.as_ref() { if let Expr::Property(id, pos) = dot_lhs.as_ref() {
let fn_name = make_setter(id); let fn_name = make_setter(id);
args[1] = &mut indexed_val; args[1] = indexed_val;
self.exec_fn_call(fn_lib, &fn_name, &mut args, None, *pos, 0)?; self.exec_fn_call(fn_lib, &fn_name, &mut args, None, *pos, 0)?;
} }
} }
@ -864,7 +868,7 @@ impl Engine {
} }
} }
/// Evaluate a dot/index chain /// Evaluate a dot/index chain.
fn eval_dot_index_chain( fn eval_dot_index_chain(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
@ -945,6 +949,11 @@ impl Engine {
} }
} }
/// Evaluate a chain of indexes and store the results in a list.
/// The first few results are stored in the array `list` which is of fixed length.
/// Any spill-overs are stored in `more`, which is dynamic.
/// The fixed length array is used to avoid an allocation in the overwhelming cases of just a few levels of indexing.
/// The total number of values is returned.
fn eval_indexed_chain( fn eval_indexed_chain(
&self, &self,
scope: &mut Scope, scope: &mut Scope,
@ -955,7 +964,7 @@ impl Engine {
size: usize, size: usize,
level: usize, level: usize,
) -> Result<usize, Box<EvalAltResult>> { ) -> Result<usize, Box<EvalAltResult>> {
let size = match expr { match expr {
Expr::FunctionCall(_, arg_exprs, _, _) => { Expr::FunctionCall(_, arg_exprs, _, _) => {
let arg_values = arg_exprs let arg_values = arg_exprs
.iter() .iter()
@ -967,21 +976,21 @@ impl Engine {
} else { } else {
more.push(arg_values.into()); more.push(arg_values.into());
} }
size + 1 Ok(size + 1)
} }
Expr::Property(_, _) => { Expr::Property(_, _) => {
// Placeholder // Store a placeholder - no need to copy the property name
if size < list.len() { if size < list.len() {
list[size] = ().into(); list[size] = ().into();
} else { } else {
more.push(().into()); more.push(().into());
} }
size + 1 Ok(size + 1)
} }
Expr::Index(lhs, rhs, _) | Expr::Dot(lhs, rhs, _) => { Expr::Index(lhs, rhs, _) | Expr::Dot(lhs, rhs, _) => {
// Evaluate in left-to-right order // Evaluate in left-to-right order
let lhs_val = match lhs.as_ref() { let lhs_val = match lhs.as_ref() {
Expr::Property(_, _) => ().into(), // Placeholder Expr::Property(_, _) => ().into(), // Store a placeholder in case of a property
_ => self.eval_expr(scope, fn_lib, lhs, level)?, _ => self.eval_expr(scope, fn_lib, lhs, level)?,
}; };
@ -993,7 +1002,7 @@ impl Engine {
} else { } else {
more.push(lhs_val); more.push(lhs_val);
} }
size + 1 Ok(size + 1)
} }
_ => { _ => {
let val = self.eval_expr(scope, fn_lib, expr, level)?; let val = self.eval_expr(scope, fn_lib, expr, level)?;
@ -1002,10 +1011,9 @@ impl Engine {
} else { } else {
more.push(val); more.push(val);
} }
size + 1 Ok(size + 1)
}
} }
};
Ok(size)
} }
/// Get the value at the indexed position of a base type /// Get the value at the indexed position of a base type