Pre-calculate function call hashes.

This commit is contained in:
Stephen Chung
2020-05-09 16:15:50 +08:00
parent 0d20137d6c
commit 79f39bd702
4 changed files with 182 additions and 119 deletions

View File

@@ -367,12 +367,17 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
//id = id2 = expr2
Expr::Assignment(id2, expr2, pos2) => match (*id, *id2) {
// var = var = expr2 -> var = expr2
(Expr::Variable(var, None, sp, _), Expr::Variable(var2, None, sp2, _))
(Expr::Variable(var, None, index, sp, _), Expr::Variable(var2, None, _, sp2, _))
if var == var2 && sp == sp2 =>
{
// Assignment to the same variable - fold
state.set_dirty();
Expr::Assignment(Box::new(Expr::Variable(var, None, sp, pos)), Box::new(optimize_expr(*expr2, state)), pos)
Expr::Assignment(
Box::new(Expr::Variable(var, None, index, sp, pos)),
Box::new(optimize_expr(*expr2, state))
, pos
)
}
// id1 = id2 = expr2
(id1, id2) => Expr::Assignment(
@@ -544,18 +549,18 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
},
// Do not call some special keywords
Expr::FnCall(id, None, args, def_value, pos) if DONT_EVAL_KEYWORDS.contains(&id.as_ref().as_ref())=>
Expr::FnCall(id, None, Box::new(args.into_iter().map(|a| optimize_expr(a, state)).collect()), def_value, pos),
Expr::FnCall(id, None, index, args, def_value, pos) if DONT_EVAL_KEYWORDS.contains(&id.as_ref().as_ref())=>
Expr::FnCall(id, None, index, Box::new(args.into_iter().map(|a| optimize_expr(a, state)).collect()), def_value, pos),
// Eagerly call functions
Expr::FnCall(id, None, args, def_value, pos)
Expr::FnCall(id, None, index, args, def_value, pos)
if state.optimization_level == OptimizationLevel::Full // full optimizations
&& args.iter().all(|expr| expr.is_constant()) // all arguments are constants
=> {
// First search in script-defined functions (can override built-in)
if state.fn_lib.iter().find(|(name, len)| name == id.as_ref() && *len == args.len()).is_some() {
// A script-defined function overrides the built-in function - do not make the call
return Expr::FnCall(id, None, Box::new(args.into_iter().map(|a| optimize_expr(a, state)).collect()), def_value, pos);
return Expr::FnCall(id, None, index, Box::new(args.into_iter().map(|a| optimize_expr(a, state)).collect()), def_value, pos);
}
let mut arg_values: Vec<_> = args.iter().map(Expr::get_constant_value).collect();
@@ -586,16 +591,16 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
})
).unwrap_or_else(||
// Optimize function call arguments
Expr::FnCall(id, None, Box::new(args.into_iter().map(|a| optimize_expr(a, state)).collect()), def_value, pos)
Expr::FnCall(id, None, index, Box::new(args.into_iter().map(|a| optimize_expr(a, state)).collect()), def_value, pos)
)
}
// id(args ..) -> optimize function call arguments
Expr::FnCall(id, modules, args, def_value, pos) =>
Expr::FnCall(id, modules, Box::new(args.into_iter().map(|a| optimize_expr(a, state)).collect()), def_value, pos),
Expr::FnCall(id, modules, index, args, def_value, pos) =>
Expr::FnCall(id, modules, index, Box::new(args.into_iter().map(|a| optimize_expr(a, state)).collect()), def_value, pos),
// constant-name
Expr::Variable(name, None, _, pos) if state.contains_constant(&name) => {
Expr::Variable(name, None, _, _, pos) if state.contains_constant(&name) => {
state.set_dirty();
// Replace constant with value