Optimize type_of.
This commit is contained in:
parent
705fbd0c1b
commit
ad2601972a
@ -1,7 +1,9 @@
|
|||||||
#![cfg(not(feature = "no_optimize"))]
|
#![cfg(not(feature = "no_optimize"))]
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::any::{Any, Dynamic};
|
||||||
use crate::engine::{Engine, FnCallArgs, KEYWORD_DEBUG, KEYWORD_DUMP_AST, KEYWORD_PRINT};
|
use crate::engine::{
|
||||||
|
Engine, FnCallArgs, KEYWORD_DEBUG, KEYWORD_DUMP_AST, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||||
|
};
|
||||||
use crate::parser::{map_dynamic_to_expr, Expr, FnDef, Stmt, AST};
|
use crate::parser::{map_dynamic_to_expr, Expr, FnDef, Stmt, AST};
|
||||||
use crate::scope::{Scope, ScopeEntry, VariableType};
|
use crate::scope::{Scope, ScopeEntry, VariableType};
|
||||||
|
|
||||||
@ -223,6 +225,8 @@ fn optimize_stmt<'a>(stmt: Stmt, state: &mut State<'a>, preserve_result: bool) -
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
||||||
|
const SKIP_FUNC_KEYWORDS: [&str; 3] = [KEYWORD_PRINT, KEYWORD_DEBUG, KEYWORD_DUMP_AST];
|
||||||
|
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Stmt(stmt, pos) => match optimize_stmt(*stmt, state, true) {
|
Expr::Stmt(stmt, pos) => match optimize_stmt(*stmt, state, true) {
|
||||||
Stmt::Noop(_) => {
|
Stmt::Noop(_) => {
|
||||||
@ -343,41 +347,46 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
||||||
// Do not optimize anything within `dump_ast`
|
// Do not optimize anything within built-in function keywords
|
||||||
Expr::FunctionCall(id, args, def_value, pos) if id == KEYWORD_DUMP_AST => {
|
Expr::FunctionCall(id, args, def_value, pos) if SKIP_FUNC_KEYWORDS.contains(&id.as_str())=>
|
||||||
Expr::FunctionCall(id, args, def_value, pos)
|
Expr::FunctionCall(id, args, def_value, pos),
|
||||||
}
|
|
||||||
// Actually call function to optimize it
|
// Actually call function to optimize it
|
||||||
Expr::FunctionCall(id, args, def_value, pos)
|
Expr::FunctionCall(id, args, def_value, pos)
|
||||||
if id != KEYWORD_DEBUG // not debug
|
if state.engine.map(|eng| eng.optimization_level == OptimizationLevel::Full).unwrap_or(false) // full optimizations
|
||||||
&& id != KEYWORD_PRINT // not print
|
|
||||||
&& state.engine.map(|eng| eng.optimization_level == OptimizationLevel::Full).unwrap_or(false) // full optimizations
|
|
||||||
&& args.iter().all(|expr| expr.is_constant()) // all arguments are constants
|
&& args.iter().all(|expr| expr.is_constant()) // all arguments are constants
|
||||||
=>
|
=> {
|
||||||
{
|
|
||||||
let engine = state.engine.expect("engine should be Some");
|
let engine = state.engine.expect("engine should be Some");
|
||||||
let mut arg_values: Vec<_> = args.iter().map(Expr::get_constant_value).collect();
|
let mut arg_values: Vec<_> = args.iter().map(Expr::get_constant_value).collect();
|
||||||
let call_args: FnCallArgs = arg_values.iter_mut().map(Dynamic::as_mut).collect();
|
let call_args: FnCallArgs = arg_values.iter_mut().map(Dynamic::as_mut).collect();
|
||||||
|
|
||||||
|
// Save the typename of the first argument if it is `type_of()`
|
||||||
|
// This is to avoid `call_args` being passed into the closure
|
||||||
|
let arg_for_type_of = if id == KEYWORD_TYPE_OF && call_args.len() == 1 {
|
||||||
|
engine.map_type_name(call_args[0].type_name())
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
|
||||||
engine.call_ext_fn_raw(&id, call_args, pos).ok().map(|r|
|
engine.call_ext_fn_raw(&id, call_args, pos).ok().map(|r|
|
||||||
r.or(def_value.clone()).and_then(|result| map_dynamic_to_expr(result, pos).0)
|
r.or_else(|| {
|
||||||
|
if !arg_for_type_of.is_empty() {
|
||||||
|
// Handle `type_of()`
|
||||||
|
Some(arg_for_type_of.to_string().into_dynamic())
|
||||||
|
} else {
|
||||||
|
// Otherwise use the default value, if any
|
||||||
|
def_value.clone()
|
||||||
|
}
|
||||||
|
}).and_then(|result| map_dynamic_to_expr(result, pos).0)
|
||||||
.map(|expr| {
|
.map(|expr| {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
expr
|
expr
|
||||||
})).flatten()
|
})
|
||||||
.unwrap_or_else(|| Expr::FunctionCall(id, args, def_value, pos))
|
).flatten().unwrap_or_else(|| Expr::FunctionCall(id, args, def_value, pos))
|
||||||
}
|
}
|
||||||
// Optimize the function call arguments
|
// Optimize the function call arguments
|
||||||
Expr::FunctionCall(id, args, def_value, pos) => {
|
Expr::FunctionCall(id, args, def_value, pos) =>
|
||||||
let orig_len = args.len();
|
Expr::FunctionCall(id, args.into_iter().map(|a| optimize_expr(a, state)).collect(), def_value, pos),
|
||||||
|
|
||||||
let args: Vec<_> = args.into_iter().map(|a| optimize_expr(a, state)).collect();
|
|
||||||
|
|
||||||
if orig_len != args.len() {
|
|
||||||
state.set_dirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
Expr::FunctionCall(id, args, def_value, pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
Expr::Variable(ref name, _) if state.contains_constant(name) => {
|
Expr::Variable(ref name, _) if state.contains_constant(name) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
|
Loading…
Reference in New Issue
Block a user