Allow propagation for pushed scope constants.

This commit is contained in:
Stephen Chung 2020-10-09 13:26:32 +08:00
parent 630ec51624
commit 59b380b130

View File

@ -9,9 +9,9 @@ use crate::engine::{
use crate::fn_call::run_builtin_binary_op;
use crate::module::Module;
use crate::parser::{map_dynamic_to_expr, Expr, ScriptFnDef, Stmt, AST};
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
use crate::scope::{Entry as ScopeEntry, Scope};
use crate::utils::StaticVec;
use crate::token::is_valid_identifier;
use crate::token::{is_valid_identifier, Position};
#[cfg(not(feature = "no_function"))]
use crate::parser::ReturnType;
@ -62,6 +62,7 @@ impl OptimizationLevel {
}
/// Mutable state throughout an optimization pass.
#[derive(Debug, Clone)]
struct State<'a> {
/// Has the AST been changed during this pass?
changed: bool,
@ -406,11 +407,11 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
// These keywords are handled specially
const DONT_EVAL_KEYWORDS: &[&str] = &[
KEYWORD_PRINT,
KEYWORD_DEBUG,
KEYWORD_EVAL,
KEYWORD_IS_DEF_FN,
KEYWORD_IS_DEF_VAR,
KEYWORD_PRINT, // side effects
KEYWORD_DEBUG, // side effects
KEYWORD_EVAL, // arbitrary scripts
KEYWORD_IS_DEF_FN, // functions collection is volatile
KEYWORD_IS_DEF_VAR, // variables scope is volatile
];
match expr {
@ -572,7 +573,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
},
// Do not call some special keywords
Expr::FnCall(mut x) if DONT_EVAL_KEYWORDS.contains(&(x.0).0.as_ref())=> {
Expr::FnCall(mut x) if DONT_EVAL_KEYWORDS.contains(&(x.0).0.as_ref()) => {
x.3 = x.3.into_iter().map(|a| optimize_expr(a, state)).collect();
Expr::FnCall(x)
}
@ -700,13 +701,14 @@ fn optimize(
// Add constants from the scope into the state
scope
.to_iter()
.filter(|ScopeEntry { typ, expr, .. }| {
// Get all the constants with definite constant expressions
*typ == ScopeEntryType::Constant
&& expr.as_ref().map(|v| v.is_constant()).unwrap_or(false)
})
.for_each(|ScopeEntry { name, expr, .. }| {
state.push_constant(name.as_ref(), expr.as_ref().unwrap().as_ref().clone())
// Get all the constants that can be made into a constant literal.
.filter(|ScopeEntry { typ, .. }| typ.is_constant())
.for_each(|ScopeEntry { name, expr, value, .. }| {
if let Some(val) = expr.as_ref().map(|expr| expr.as_ref().clone()).or_else(
|| map_dynamic_to_expr(value.clone(), Position::none())
) {
state.push_constant(name.as_ref(), val);
}
});
let orig_constants_len = state.constants.len();