Change optimize_ast to take optimization level as parameter.

This commit is contained in:
Stephen Chung
2020-04-08 09:30:50 +08:00
parent b74c85f04c
commit e0bb2e5c97
5 changed files with 54 additions and 16 deletions

View File

@@ -10,7 +10,7 @@ use crate::result::EvalAltResult;
use crate::scope::Scope;
#[cfg(not(feature = "no_optimize"))]
use crate::optimize::optimize_into_ast;
use crate::optimize::{optimize_into_ast, OptimizationLevel};
use crate::stdlib::{
any::{type_name, TypeId},
@@ -902,9 +902,14 @@ impl<'e> Engine<'e> {
/// compiled just once. Before evaluation, constants are passed into the `Engine` via an external scope
/// (i.e. with `scope.push_constant(...)`). Then, the `AST is cloned and the copy re-optimized before running.
#[cfg(not(feature = "no_optimize"))]
pub fn optimize_ast(&self, scope: &Scope, ast: AST) -> AST {
pub fn optimize_ast(
&self,
scope: &Scope,
ast: AST,
optimization_level: OptimizationLevel,
) -> AST {
let fn_lib = ast.1.iter().map(|fn_def| fn_def.as_ref().clone()).collect();
optimize_into_ast(self, scope, ast.0, fn_lib)
optimize_into_ast(self, scope, ast.0, fn_lib, optimization_level)
}
/// Override default action of `print` (print to stdout using `println!`)

View File

@@ -41,16 +41,23 @@ struct State<'a> {
engine: &'a Engine<'a>,
/// Library of script-defined functions.
fn_lib: &'a [(&'a str, usize)],
/// Optimization level.
optimization_level: OptimizationLevel,
}
impl<'a> State<'a> {
/// Create a new State.
pub fn new(engine: &'a Engine<'a>, fn_lib: &'a [(&'a str, usize)]) -> Self {
pub fn new(
engine: &'a Engine<'a>,
fn_lib: &'a [(&'a str, usize)],
level: OptimizationLevel,
) -> Self {
Self {
changed: false,
constants: vec![],
engine,
fn_lib,
optimization_level: level,
}
}
/// Reset the state from dirty to clean.
@@ -501,7 +508,7 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
// Eagerly call functions
Expr::FunctionCall(id, args, def_value, pos)
if state.engine.optimization_level == OptimizationLevel::Full // full optimizations
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)
@@ -560,14 +567,15 @@ pub(crate) fn optimize<'a>(
engine: &Engine<'a>,
scope: &Scope,
fn_lib: &'a [(&'a str, usize)],
level: OptimizationLevel,
) -> Vec<Stmt> {
// If optimization level is None then skip optimizing
if engine.optimization_level == OptimizationLevel::None {
if level == OptimizationLevel::None {
return statements;
}
// Set up the state
let mut state = State::new(engine, fn_lib);
let mut state = State::new(engine, fn_lib, level);
// Add constants from the scope into the state
scope
@@ -640,6 +648,7 @@ pub fn optimize_into_ast(
scope: &Scope,
statements: Vec<Stmt>,
functions: Vec<FnDef>,
level: OptimizationLevel,
) -> AST {
let fn_lib: Vec<_> = functions
.iter()
@@ -651,11 +660,12 @@ pub fn optimize_into_ast(
.iter()
.cloned()
.map(|mut fn_def| {
if engine.optimization_level != OptimizationLevel::None {
if level != OptimizationLevel::None {
let pos = fn_def.body.position();
// Optimize the function body
let mut body = optimize(vec![fn_def.body], engine, &Scope::new(), &fn_lib);
let mut body =
optimize(vec![fn_def.body], engine, &Scope::new(), &fn_lib, level);
// {} -> Noop
fn_def.body = match body.pop().unwrap_or_else(|| Stmt::Noop(pos)) {
@@ -675,10 +685,10 @@ pub fn optimize_into_ast(
);
AST(
match engine.optimization_level {
match level {
OptimizationLevel::None => statements,
OptimizationLevel::Simple | OptimizationLevel::Full => {
optimize(statements, engine, &scope, &fn_lib)
optimize(statements, engine, &scope, &fn_lib, level)
}
},
#[cfg(feature = "sync")]

View File

@@ -2781,7 +2781,13 @@ pub fn parse_global_expr<'a, 'e>(
Ok(
// Optimize AST
#[cfg(not(feature = "no_optimize"))]
optimize_into_ast(engine, scope, vec![Stmt::Expr(Box::new(expr))], vec![]),
optimize_into_ast(
engine,
scope,
vec![Stmt::Expr(Box::new(expr))],
vec![],
engine.optimization_level,
),
//
// Do not optimize AST if `no_optimize`
#[cfg(feature = "no_optimize")]
@@ -2866,7 +2872,13 @@ pub fn parse<'a, 'e>(
Ok(
// Optimize AST
#[cfg(not(feature = "no_optimize"))]
optimize_into_ast(engine, scope, statements, functions),
optimize_into_ast(
engine,
scope,
statements,
functions,
engine.optimization_level,
),
//
// Do not optimize AST if `no_optimize`
#[cfg(feature = "no_optimize")]