Optimize position in variable access.

This commit is contained in:
Stephen Chung
2021-04-05 23:59:15 +08:00
parent 94fc5af285
commit d3cfb3c605
6 changed files with 146 additions and 139 deletions

View File

@@ -959,14 +959,14 @@ impl Engine {
expr: &Expr,
) -> Result<(Target<'s>, Position), Box<EvalAltResult>> {
match expr {
Expr::Variable(Some(_), _) => {
Expr::Variable(Some(_), _, _) => {
self.search_scope_only(scope, mods, state, lib, this_ptr, expr)
}
Expr::Variable(None, v) => match v.as_ref() {
Expr::Variable(None, var_pos, v) => match v.as_ref() {
// Normal variable access
(_, None, _) => self.search_scope_only(scope, mods, state, lib, this_ptr, expr),
// Qualified variable
(_, Some((hash_var, modules)), Ident { name, pos, .. }) => {
(_, Some((hash_var, modules)), var_name) => {
let module = self.search_imports(mods, state, modules).ok_or_else(|| {
EvalAltResult::ErrorModuleNotFound(
modules[0].name.to_string(),
@@ -976,17 +976,17 @@ impl Engine {
let target = module.get_qualified_var(*hash_var).map_err(|mut err| {
match *err {
EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => {
*err_name = format!("{}{}", modules, name);
*err_name = format!("{}{}", modules, var_name);
}
_ => (),
}
err.fill_position(*pos)
err.fill_position(*var_pos)
})?;
// Module variables are constant
let mut target = target.clone();
target.set_access_mode(AccessMode::ReadOnly);
Ok((target.into(), *pos))
Ok((target.into(), *var_pos))
}
},
_ => unreachable!("Expr::Variable expected, but gets {:?}", expr),
@@ -1003,30 +1003,23 @@ impl Engine {
this_ptr: &'s mut Option<&mut Dynamic>,
expr: &Expr,
) -> Result<(Target<'s>, Position), Box<EvalAltResult>> {
let (short_index, (index, _, Ident { name, pos, .. })) = match expr {
Expr::Variable(i, v) => (i, v.as_ref()),
// Make sure that the pointer indirection is taken only when absolutely necessary.
let (index, var_pos) = match expr {
// Check if the variable is `this`
Expr::Variable(None, pos, v) if v.0.is_none() && v.2 == KEYWORD_THIS => {
return if let Some(val) = this_ptr {
Ok(((*val).into(), *pos))
} else {
EvalAltResult::ErrorUnboundThis(*pos).into()
}
}
_ if state.always_search => (0, expr.position()),
Expr::Variable(Some(i), pos, _) => (i.get() as usize, *pos),
Expr::Variable(None, pos, v) => (v.0.map(NonZeroUsize::get).unwrap_or(0), *pos),
_ => unreachable!("Expr::Variable expected, but gets {:?}", expr),
};
// Check if the variable is `this`
if *name == KEYWORD_THIS {
return if let Some(val) = this_ptr {
Ok(((*val).into(), *pos))
} else {
EvalAltResult::ErrorUnboundThis(*pos).into()
};
}
// Check if it is directly indexed
let index = if state.always_search {
0
} else {
short_index.map_or_else(
|| index.map(NonZeroUsize::get).unwrap_or(0),
|x| x.get() as usize,
)
};
// Check the variable resolver, if any
if let Some(ref resolve_var) = self.resolve_var {
let context = EvalContext {
@@ -1039,10 +1032,11 @@ impl Engine {
level: 0,
};
if let Some(mut result) =
resolve_var(name, index, &context).map_err(|err| err.fill_position(*pos))?
resolve_var(expr.get_variable_name(true).unwrap(), index, &context)
.map_err(|err| err.fill_position(var_pos))?
{
result.set_access_mode(AccessMode::ReadOnly);
return Ok((result.into(), *pos));
return Ok((result.into(), var_pos));
}
}
@@ -1050,15 +1044,16 @@ impl Engine {
scope.len() - index
} else {
// Find the variable in the scope
let var_name = expr.get_variable_name(true).unwrap();
scope
.get_index(name)
.ok_or_else(|| EvalAltResult::ErrorVariableNotFound(name.to_string(), *pos))?
.get_index(var_name)
.ok_or_else(|| EvalAltResult::ErrorVariableNotFound(var_name.to_string(), var_pos))?
.0
};
let val = scope.get_mut_by_index(index);
Ok((val.into(), *pos))
Ok((val.into(), var_pos))
}
/// Chain-evaluate a dot/index chain.
@@ -1410,13 +1405,7 @@ impl Engine {
match lhs {
// id.??? or id[???]
Expr::Variable(_, x) => {
let Ident {
name: var_name,
pos: var_pos,
..
} = &x.2;
Expr::Variable(_, var_pos, x) => {
self.inc_operations(state, *var_pos)?;
let (target, pos) =
@@ -1424,8 +1413,7 @@ impl Engine {
// Constants cannot be modified
if target.as_ref().is_read_only() && new_val.is_some() {
return EvalAltResult::ErrorAssignmentToConstant(var_name.to_string(), pos)
.into();
return EvalAltResult::ErrorAssignmentToConstant(x.2.to_string(), pos).into();
}
let obj_ptr = &mut target.into();
@@ -1688,11 +1676,11 @@ impl Engine {
Expr::CharConstant(x, _) => Ok((*x).into()),
Expr::FnPointer(x, _) => Ok(FnPtr::new_unchecked(x.clone(), Default::default()).into()),
Expr::Variable(None, x) if x.0.is_none() && (x.2).name == KEYWORD_THIS => this_ptr
Expr::Variable(None, var_pos, x) if x.0.is_none() && x.2 == KEYWORD_THIS => this_ptr
.as_deref()
.cloned()
.ok_or_else(|| EvalAltResult::ErrorUnboundThis((x.2).pos).into()),
Expr::Variable(_, _) => self
.ok_or_else(|| EvalAltResult::ErrorUnboundThis(*var_pos).into()),
Expr::Variable(_, _, _) => self
.search_namespace(scope, mods, state, lib, this_ptr, expr)
.map(|(val, _)| val.take_or_clone()),
@@ -2019,7 +2007,7 @@ impl Engine {
.flatten()),
// var op= rhs
Stmt::Assignment(x, op_pos) if x.0.get_variable_access(false).is_some() => {
Stmt::Assignment(x, op_pos) if x.0.is_variable_access(false) => {
let (lhs_expr, op_info, rhs_expr) = x.as_ref();
let rhs_val = self
.eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)?
@@ -2029,7 +2017,7 @@ impl Engine {
if !lhs_ptr.is_ref() {
return EvalAltResult::ErrorAssignmentToConstant(
lhs_expr.get_variable_access(false).unwrap().to_string(),
lhs_expr.get_variable_name(false).unwrap().to_string(),
pos,
)
.into();
@@ -2040,7 +2028,7 @@ impl Engine {
if lhs_ptr.as_ref().is_read_only() {
// Assignment to constant variable
EvalAltResult::ErrorAssignmentToConstant(
lhs_expr.get_variable_access(false).unwrap().to_string(),
lhs_expr.get_variable_name(false).unwrap().to_string(),
pos,
)
.into()
@@ -2070,7 +2058,7 @@ impl Engine {
// Must be either `var[index] op= val` or `var.prop op= val`
match lhs_expr {
// name op= rhs (handled above)
Expr::Variable(_, _) => {
Expr::Variable(_, _, _) => {
unreachable!("Expr::Variable case should already been handled")
}
// idx_lhs[idx_expr] op= rhs