Optimize property access for object maps.
This commit is contained in:
parent
ff8eca8a5e
commit
4b2cff715e
@ -385,25 +385,51 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
// id = expr
|
// id = expr
|
||||||
expr => Expr::Assignment(id, Box::new(optimize_expr(expr, state)), pos),
|
expr => Expr::Assignment(id, Box::new(optimize_expr(expr, state)), pos),
|
||||||
},
|
},
|
||||||
|
|
||||||
// lhs.rhs
|
// lhs.rhs
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(lhs, rhs, pos) => Expr::Dot(
|
Expr::Dot(lhs, rhs, pos) => match (*lhs, *rhs) {
|
||||||
Box::new(optimize_expr(*lhs, state)),
|
// map.string
|
||||||
Box::new(optimize_expr(*rhs, state)),
|
(Expr::Map(items, pos), Expr::Property(s, _))
|
||||||
|
if items.iter().all(|(_, x, _)| x.is_pure()) =>
|
||||||
|
{
|
||||||
|
// Map literal where everything is pure - promote the indexed item.
|
||||||
|
// All other items can be thrown away.
|
||||||
|
state.set_dirty();
|
||||||
|
items.into_iter().find(|(name, _, _)| name == s.as_ref())
|
||||||
|
.map(|(_, expr, _)| expr.set_position(pos))
|
||||||
|
.unwrap_or_else(|| Expr::Unit(pos))
|
||||||
|
}
|
||||||
|
// lhs.rhs
|
||||||
|
(lhs, rhs) => Expr::Dot(
|
||||||
|
Box::new(optimize_expr(lhs, state)),
|
||||||
|
Box::new(optimize_expr(rhs, state)),
|
||||||
pos,
|
pos,
|
||||||
),
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// lhs[rhs]
|
// lhs[rhs]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(lhs, rhs, pos) => match (*lhs, *rhs) {
|
Expr::Index(lhs, rhs, pos) => match (*lhs, *rhs) {
|
||||||
// array[int]
|
// array[int]
|
||||||
(Expr::Array(mut items, _), Expr::IntegerConstant(i, _))
|
(Expr::Array(mut items, pos), Expr::IntegerConstant(i, _))
|
||||||
if i >= 0 && (i as usize) < items.len() && items.iter().all(|x| x.is_pure()) =>
|
if i >= 0 && (i as usize) < items.len() && items.iter().all(Expr::is_pure) =>
|
||||||
{
|
{
|
||||||
// Array literal where everything is pure - promote the indexed item.
|
// Array literal where everything is pure - promote the indexed item.
|
||||||
// All other items can be thrown away.
|
// All other items can be thrown away.
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
items.remove(i as usize)
|
items.remove(i as usize).set_position(pos)
|
||||||
|
}
|
||||||
|
// map[string]
|
||||||
|
(Expr::Map(items, pos), Expr::StringConstant(s, _))
|
||||||
|
if items.iter().all(|(_, x, _)| x.is_pure()) =>
|
||||||
|
{
|
||||||
|
// Map literal where everything is pure - promote the indexed item.
|
||||||
|
// All other items can be thrown away.
|
||||||
|
state.set_dirty();
|
||||||
|
items.into_iter().find(|(name, _, _)| name == s.as_ref())
|
||||||
|
.map(|(_, expr, _)| expr.set_position(pos))
|
||||||
|
.unwrap_or_else(|| Expr::Unit(pos))
|
||||||
}
|
}
|
||||||
// string[int]
|
// string[int]
|
||||||
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _))
|
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _))
|
||||||
@ -580,11 +606,11 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
Expr::FunctionCall(id, args.into_iter().map(|a| optimize_expr(a, state)).collect(), def_value, pos),
|
Expr::FunctionCall(id, args.into_iter().map(|a| optimize_expr(a, state)).collect(), def_value, pos),
|
||||||
|
|
||||||
// constant-name
|
// constant-name
|
||||||
Expr::Variable(name, _) if state.contains_constant(&name) => {
|
Expr::Variable(name, pos) if state.contains_constant(&name) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
|
|
||||||
// Replace constant with value
|
// Replace constant with value
|
||||||
state.find_constant(&name).expect("should find constant in scope!").clone()
|
state.find_constant(&name).expect("should find constant in scope!").clone().set_position(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
// All other expressions - skip
|
// All other expressions - skip
|
||||||
|
@ -511,6 +511,33 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the `Position` of the expression.
|
||||||
|
pub(crate) fn set_position(mut self, new_pos: Position) -> Self {
|
||||||
|
match &mut self {
|
||||||
|
Self::IntegerConstant(_, pos)
|
||||||
|
| Self::FloatConstant(_, pos)
|
||||||
|
| Self::CharConstant(_, pos)
|
||||||
|
| Self::StringConstant(_, pos)
|
||||||
|
| Self::Array(_, pos)
|
||||||
|
| Self::Map(_, pos)
|
||||||
|
| Self::Variable(_, pos)
|
||||||
|
| Self::Property(_, pos)
|
||||||
|
| Self::Stmt(_, pos)
|
||||||
|
| Self::FunctionCall(_, _, _, pos)
|
||||||
|
| Self::And(_, _, pos)
|
||||||
|
| Self::Or(_, _, pos)
|
||||||
|
| Self::In(_, _, pos)
|
||||||
|
| Self::True(pos)
|
||||||
|
| Self::False(pos)
|
||||||
|
| Self::Unit(pos)
|
||||||
|
| Self::Assignment(_, _, pos)
|
||||||
|
| Self::Dot(_, _, pos)
|
||||||
|
| Self::Index(_, _, pos) => *pos = new_pos,
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Is the expression pure?
|
/// Is the expression pure?
|
||||||
///
|
///
|
||||||
/// A pure expression has no side effects.
|
/// A pure expression has no side effects.
|
||||||
|
@ -107,15 +107,15 @@ impl EvalAltResult {
|
|||||||
Self::ErrorArrayBounds(_, index, _) if *index < 0 => {
|
Self::ErrorArrayBounds(_, index, _) if *index < 0 => {
|
||||||
"Array access expects non-negative index"
|
"Array access expects non-negative index"
|
||||||
}
|
}
|
||||||
Self::ErrorArrayBounds(0, _, _) => "Access of empty array",
|
Self::ErrorArrayBounds(0, _, _) => "Empty array has nothing to access",
|
||||||
Self::ErrorArrayBounds(_, _, _) => "Array index out of bounds",
|
Self::ErrorArrayBounds(_, _, _) => "Array index out of bounds",
|
||||||
Self::ErrorStringBounds(_, index, _) if *index < 0 => {
|
Self::ErrorStringBounds(_, index, _) if *index < 0 => {
|
||||||
"Indexing a string expects a non-negative index"
|
"Indexing a string expects a non-negative index"
|
||||||
}
|
}
|
||||||
Self::ErrorStringBounds(0, _, _) => "Indexing of empty string",
|
Self::ErrorStringBounds(0, _, _) => "Empty string has nothing to index",
|
||||||
Self::ErrorStringBounds(_, _, _) => "String index out of bounds",
|
Self::ErrorStringBounds(_, _, _) => "String index out of bounds",
|
||||||
Self::ErrorLogicGuard(_) => "Boolean expression expected",
|
Self::ErrorLogicGuard(_) => "Boolean value expected",
|
||||||
Self::ErrorFor(_) => "For loop expects array or range",
|
Self::ErrorFor(_) => "For loop expects an array, object map, or range",
|
||||||
Self::ErrorVariableNotFound(_, _) => "Variable not found",
|
Self::ErrorVariableNotFound(_, _) => "Variable not found",
|
||||||
Self::ErrorAssignmentToUnknownLHS(_) => {
|
Self::ErrorAssignmentToUnknownLHS(_) => {
|
||||||
"Assignment to an unsupported left-hand side expression"
|
"Assignment to an unsupported left-hand side expression"
|
||||||
|
Loading…
Reference in New Issue
Block a user