Flatten nested block scopes.
This commit is contained in:
parent
be4ae6e763
commit
1fd242ed2c
@ -1,6 +1,7 @@
|
|||||||
//! Module defining script statements.
|
//! Module defining script statements.
|
||||||
|
|
||||||
use super::{ASTNode, Expr, FnCallExpr, Ident, OptionFlags, AST_OPTION_FLAGS};
|
use super::{ASTNode, Expr, FnCallExpr, Ident, OptionFlags, AST_OPTION_FLAGS};
|
||||||
|
use crate::engine::KEYWORD_EVAL;
|
||||||
use crate::tokenizer::Token;
|
use crate::tokenizer::Token;
|
||||||
use crate::{calc_fn_hash, Position, StaticVec, INT};
|
use crate::{calc_fn_hash, Position, StaticVec, INT};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
@ -466,12 +467,33 @@ impl Stmt {
|
|||||||
Self::Share(_) => false,
|
Self::Share(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Does this statement's behavior depend on its containing block?
|
||||||
|
///
|
||||||
|
/// A statement that depends on its containing block behaves differently when promoted
|
||||||
|
/// to an upper block.
|
||||||
|
///
|
||||||
|
/// Currently only variable definitions (i.e. `let` and `const`), `import`/`export` statements,
|
||||||
|
/// and `eval` calls (which may in turn call define variables) fall under this category.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_block_dependent(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Var(_, _, _, _) => true,
|
||||||
|
|
||||||
|
Self::FnCall(x, _) if x.name == KEYWORD_EVAL => true,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Self::Import(_, _, _) | Self::Export(_, _) => true,
|
||||||
|
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Is this statement _pure_ within the containing block?
|
/// Is this statement _pure_ within the containing block?
|
||||||
///
|
///
|
||||||
/// An internally pure statement only has side effects that disappear outside the block.
|
/// An internally pure statement only has side effects that disappear outside the block.
|
||||||
///
|
///
|
||||||
/// Currently only variable definitions (i.e. `let` and `const`) and `import`/`export`
|
/// Currently only variable definitions (i.e. `let` and `const`) and `import`/`export`
|
||||||
/// statements are internally pure.
|
/// statements are internally pure, other than pure expressions.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_internally_pure(&self) -> bool {
|
pub fn is_internally_pure(&self) -> bool {
|
||||||
|
@ -189,6 +189,32 @@ fn optimize_stmt_block(
|
|||||||
Stmt::is_pure
|
Stmt::is_pure
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Flatten blocks
|
||||||
|
loop {
|
||||||
|
if let Some(n) = statements.iter().enumerate().find_map(|(i, s)| match s {
|
||||||
|
Stmt::Block(block, _) if !block.iter().any(Stmt::is_block_dependent) => Some(i),
|
||||||
|
_ => None,
|
||||||
|
}) {
|
||||||
|
let (first, second) = statements.split_at_mut(n);
|
||||||
|
let stmt = mem::take(&mut second[0]);
|
||||||
|
let mut stmts = match stmt {
|
||||||
|
Stmt::Block(block, _) => block,
|
||||||
|
_ => unreachable!("Stmt::Block expected but gets {:?}", stmt),
|
||||||
|
};
|
||||||
|
statements = first
|
||||||
|
.iter_mut()
|
||||||
|
.map(mem::take)
|
||||||
|
.chain(stmts.iter_mut().map(mem::take))
|
||||||
|
.chain(second.iter_mut().skip(1).map(mem::take))
|
||||||
|
.collect();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optimize
|
||||||
loop {
|
loop {
|
||||||
state.clear_dirty();
|
state.clear_dirty();
|
||||||
|
|
||||||
@ -411,7 +437,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
x.2 = value;
|
x.2 = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
ref expr => unreachable!("Expr::FnCall expected but gets {:?}", expr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -695,8 +721,8 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*stmt = Stmt::Noop(*pos);
|
*stmt = Stmt::Noop(*pos);
|
||||||
}
|
}
|
||||||
// Only one statement - promote
|
// Only one statement which is not block-dependent - promote
|
||||||
[s] => {
|
[s] if !s.is_block_dependent() => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*stmt = mem::take(s);
|
*stmt = mem::take(s);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user