Streamline switch case AST structure.
This commit is contained in:
parent
281e94fc62
commit
5149c56256
@ -22,8 +22,8 @@ pub use script_fn::EncapsulatedEnviron;
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub use script_fn::{ScriptFnDef, ScriptFnMetadata};
|
pub use script_fn::{ScriptFnDef, ScriptFnMetadata};
|
||||||
pub use stmt::{
|
pub use stmt::{
|
||||||
CaseBlocksList, ConditionalStmtBlock, OpAssignment, RangeCase, Stmt, StmtBlock,
|
CaseBlocksList, ConditionalExpr, OpAssignment, RangeCase, Stmt, StmtBlock, StmtBlockContainer,
|
||||||
StmtBlockContainer, SwitchCasesCollection, TryCatchBlock,
|
SwitchCasesCollection, TryCatchBlock,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
@ -122,39 +122,39 @@ impl fmt::Debug for OpAssignment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A statements block with a condition.
|
/// An expression with a condition.
|
||||||
///
|
///
|
||||||
/// The condition may simply be [`Expr::BoolConstant`] with `true` if there is actually no condition.
|
/// The condition may simply be [`Expr::BoolConstant`] with `true` if there is actually no condition.
|
||||||
#[derive(Debug, Clone, Default, Hash)]
|
#[derive(Debug, Clone, Default, Hash)]
|
||||||
pub struct ConditionalStmtBlock {
|
pub struct ConditionalExpr {
|
||||||
/// Condition.
|
/// Condition.
|
||||||
pub condition: Expr,
|
pub condition: Expr,
|
||||||
/// Statements block.
|
/// Expression.
|
||||||
pub statements: StmtBlock,
|
pub expr: Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Into<StmtBlock>> From<B> for ConditionalStmtBlock {
|
impl<E: Into<Expr>> From<E> for ConditionalExpr {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: B) -> Self {
|
fn from(value: E) -> Self {
|
||||||
Self {
|
Self {
|
||||||
condition: Expr::BoolConstant(true, Position::NONE),
|
condition: Expr::BoolConstant(true, Position::NONE),
|
||||||
statements: value.into(),
|
expr: value.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Into<StmtBlock>> From<(Expr, B)> for ConditionalStmtBlock {
|
impl<E: Into<Expr>> From<(Expr, E)> for ConditionalExpr {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: (Expr, B)) -> Self {
|
fn from(value: (Expr, E)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
condition: value.0,
|
condition: value.0,
|
||||||
statements: value.1.into(),
|
expr: value.1.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConditionalStmtBlock {
|
impl ConditionalExpr {
|
||||||
/// Is this conditional statements block always `true`?
|
/// Is the condition always `true`?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_always_true(&self) -> bool {
|
pub fn is_always_true(&self) -> bool {
|
||||||
@ -163,7 +163,7 @@ impl ConditionalStmtBlock {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this conditional statements block always `false`?
|
/// Is the condition always `false`?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_always_false(&self) -> bool {
|
pub fn is_always_false(&self) -> bool {
|
||||||
@ -283,9 +283,9 @@ pub type CaseBlocksList = smallvec::SmallVec<[usize; 1]>;
|
|||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub struct SwitchCasesCollection {
|
pub struct SwitchCasesCollection {
|
||||||
/// List of [`ConditionalStmtBlock`]'s.
|
/// List of [`ConditionalExpr`]'s.
|
||||||
pub case_blocks: StaticVec<ConditionalStmtBlock>,
|
pub expressions: StaticVec<ConditionalExpr>,
|
||||||
/// Dictionary mapping value hashes to [`ConditionalStmtBlock`]'s.
|
/// Dictionary mapping value hashes to [`ConditionalExpr`]'s.
|
||||||
pub cases: BTreeMap<u64, CaseBlocksList>,
|
pub cases: BTreeMap<u64, CaseBlocksList>,
|
||||||
/// List of range cases.
|
/// List of range cases.
|
||||||
pub ranges: StaticVec<RangeCase>,
|
pub ranges: StaticVec<RangeCase>,
|
||||||
@ -779,18 +779,15 @@ impl Stmt {
|
|||||||
let (expr, sw) = &**x;
|
let (expr, sw) = &**x;
|
||||||
expr.is_pure()
|
expr.is_pure()
|
||||||
&& sw.cases.values().flat_map(|cases| cases.iter()).all(|&c| {
|
&& sw.cases.values().flat_map(|cases| cases.iter()).all(|&c| {
|
||||||
let block = &sw.case_blocks[c];
|
let block = &sw.expressions[c];
|
||||||
block.condition.is_pure() && block.statements.iter().all(Stmt::is_pure)
|
block.condition.is_pure() && block.expr.is_pure()
|
||||||
})
|
})
|
||||||
&& sw.ranges.iter().all(|r| {
|
&& sw.ranges.iter().all(|r| {
|
||||||
let block = &sw.case_blocks[r.index()];
|
let block = &sw.expressions[r.index()];
|
||||||
block.condition.is_pure() && block.statements.iter().all(Stmt::is_pure)
|
block.condition.is_pure() && block.expr.is_pure()
|
||||||
})
|
})
|
||||||
&& sw.def_case.is_some()
|
&& sw.def_case.is_some()
|
||||||
&& sw.case_blocks[sw.def_case.unwrap()]
|
&& sw.expressions[sw.def_case.unwrap()].expr.is_pure()
|
||||||
.statements
|
|
||||||
.iter()
|
|
||||||
.all(Stmt::is_pure)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loops that exit can be pure because it can never be infinite.
|
// Loops that exit can be pure because it can never be infinite.
|
||||||
@ -933,35 +930,29 @@ impl Stmt {
|
|||||||
}
|
}
|
||||||
for (.., blocks) in &sw.cases {
|
for (.., blocks) in &sw.cases {
|
||||||
for &b in blocks {
|
for &b in blocks {
|
||||||
let block = &sw.case_blocks[b];
|
let block = &sw.expressions[b];
|
||||||
|
|
||||||
if !block.condition.walk(path, on_node) {
|
if !block.condition.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for s in &block.statements {
|
if !block.expr.walk(path, on_node) {
|
||||||
if !s.walk(path, on_node) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for r in &sw.ranges {
|
for r in &sw.ranges {
|
||||||
let block = &sw.case_blocks[r.index()];
|
let block = &sw.expressions[r.index()];
|
||||||
|
|
||||||
if !block.condition.walk(path, on_node) {
|
if !block.condition.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for s in &block.statements {
|
if !block.expr.walk(path, on_node) {
|
||||||
if !s.walk(path, on_node) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(index) = sw.def_case {
|
if let Some(index) = sw.def_case {
|
||||||
for s in &sw.case_blocks[index].statements {
|
if !sw.expressions[index].expr.walk(path, on_node) {
|
||||||
if !s.walk(path, on_node) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -394,7 +394,7 @@ impl Engine {
|
|||||||
let (
|
let (
|
||||||
expr,
|
expr,
|
||||||
SwitchCasesCollection {
|
SwitchCasesCollection {
|
||||||
case_blocks,
|
expressions,
|
||||||
cases,
|
cases,
|
||||||
def_case,
|
def_case,
|
||||||
ranges,
|
ranges,
|
||||||
@ -405,7 +405,7 @@ impl Engine {
|
|||||||
self.eval_expr(scope, global, caches, lib, this_ptr, expr, level);
|
self.eval_expr(scope, global, caches, lib, this_ptr, expr, level);
|
||||||
|
|
||||||
if let Ok(value) = value_result {
|
if let Ok(value) = value_result {
|
||||||
let stmt_block_result = if value.is_hashable() {
|
let expr_result = if value.is_hashable() {
|
||||||
let hasher = &mut get_hasher();
|
let hasher = &mut get_hasher();
|
||||||
value.hash(hasher);
|
value.hash(hasher);
|
||||||
let hash = hasher.finish();
|
let hash = hasher.finish();
|
||||||
@ -417,7 +417,7 @@ impl Engine {
|
|||||||
let mut result = Ok(None);
|
let mut result = Ok(None);
|
||||||
|
|
||||||
for &index in case_blocks_list {
|
for &index in case_blocks_list {
|
||||||
let block = &case_blocks[index];
|
let block = &expressions[index];
|
||||||
|
|
||||||
let cond_result = match block.condition {
|
let cond_result = match block.condition {
|
||||||
Expr::BoolConstant(b, ..) => Ok(b),
|
Expr::BoolConstant(b, ..) => Ok(b),
|
||||||
@ -435,7 +435,7 @@ impl Engine {
|
|||||||
|
|
||||||
match cond_result {
|
match cond_result {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
result = Ok(Some(&block.statements));
|
result = Ok(Some(&block.expr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ok(false) => (),
|
Ok(false) => (),
|
||||||
@ -453,7 +453,7 @@ impl Engine {
|
|||||||
let mut result = Ok(None);
|
let mut result = Ok(None);
|
||||||
|
|
||||||
for r in ranges.iter().filter(|r| r.contains(value)) {
|
for r in ranges.iter().filter(|r| r.contains(value)) {
|
||||||
let block = &case_blocks[r.index()];
|
let block = &expressions[r.index()];
|
||||||
|
|
||||||
let cond_result = match block.condition {
|
let cond_result = match block.condition {
|
||||||
Expr::BoolConstant(b, ..) => Ok(b),
|
Expr::BoolConstant(b, ..) => Ok(b),
|
||||||
@ -470,7 +470,7 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match cond_result {
|
match cond_result {
|
||||||
Ok(true) => result = Ok(Some(&block.statements)),
|
Ok(true) => result = Ok(Some(&block.expr)),
|
||||||
Ok(false) => continue,
|
Ok(false) => continue,
|
||||||
_ => result = cond_result.map(|_| None),
|
_ => result = cond_result.map(|_| None),
|
||||||
}
|
}
|
||||||
@ -488,31 +488,18 @@ impl Engine {
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(Some(statements)) = stmt_block_result {
|
if let Ok(Some(expr)) = expr_result {
|
||||||
if !statements.is_empty() {
|
self.eval_expr(scope, global, caches, lib, this_ptr, expr, level)
|
||||||
self.eval_stmt_block(
|
} else if let Ok(None) = expr_result {
|
||||||
scope, global, caches, lib, this_ptr, statements, true, level,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Ok(Dynamic::UNIT)
|
|
||||||
}
|
|
||||||
} else if let Ok(None) = stmt_block_result {
|
|
||||||
// Default match clause
|
// Default match clause
|
||||||
if let Some(index) = def_case {
|
if let Some(index) = def_case {
|
||||||
let def_case = &case_blocks[*index].statements;
|
let def_expr = &expressions[*index].expr;
|
||||||
|
self.eval_expr(scope, global, caches, lib, this_ptr, def_expr, level)
|
||||||
if !def_case.is_empty() {
|
|
||||||
self.eval_stmt_block(
|
|
||||||
scope, global, caches, lib, this_ptr, def_case, true, level,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Ok(Dynamic::UNIT)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::UNIT)
|
Ok(Dynamic::UNIT)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
stmt_block_result.map(|_| Dynamic::UNIT)
|
expr_result.map(|_| Dynamic::UNIT)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
value_result
|
value_result
|
||||||
|
@ -284,7 +284,7 @@ pub use parser::ParseState;
|
|||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
pub use ast::{
|
pub use ast::{
|
||||||
ASTFlags, ASTNode, BinaryExpr, ConditionalStmtBlock, Expr, FnCallExpr, FnCallHashes, Ident,
|
ASTFlags, ASTNode, BinaryExpr, ConditionalExpr, Expr, FnCallExpr, FnCallHashes, Ident,
|
||||||
OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlock, SwitchCasesCollection, TryCatchBlock,
|
OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlock, SwitchCasesCollection, TryCatchBlock,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
108
src/optimizer.rs
108
src/optimizer.rs
@ -527,7 +527,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
let (
|
let (
|
||||||
match_expr,
|
match_expr,
|
||||||
SwitchCasesCollection {
|
SwitchCasesCollection {
|
||||||
case_blocks,
|
expressions,
|
||||||
cases,
|
cases,
|
||||||
ranges,
|
ranges,
|
||||||
def_case,
|
def_case,
|
||||||
@ -544,26 +544,23 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
match &case_blocks_list[..] {
|
match &case_blocks_list[..] {
|
||||||
[] => (),
|
[] => (),
|
||||||
[index] => {
|
[index] => {
|
||||||
let mut b = mem::take(&mut case_blocks[*index]);
|
let mut b = mem::take(&mut expressions[*index]);
|
||||||
cases.clear();
|
cases.clear();
|
||||||
|
|
||||||
if b.is_always_true() {
|
if b.is_always_true() {
|
||||||
// Promote the matched case
|
// Promote the matched case
|
||||||
let statements: StmtBlockContainer = mem::take(&mut b.statements);
|
let mut statements = Stmt::Expr(mem::take(&mut b.expr).into());
|
||||||
let statements =
|
optimize_stmt(&mut statements, state, true);
|
||||||
optimize_stmt_block(statements, state, true, true, false);
|
*stmt = statements;
|
||||||
*stmt = (statements, b.statements.span()).into();
|
|
||||||
} else {
|
} else {
|
||||||
// switch const { case if condition => stmt, _ => def } => if condition { stmt } else { def }
|
// switch const { case if condition => stmt, _ => def } => if condition { stmt } else { def }
|
||||||
optimize_expr(&mut b.condition, state, false);
|
optimize_expr(&mut b.condition, state, false);
|
||||||
|
|
||||||
let else_stmt = if let Some(index) = def_case {
|
let else_stmt = if let Some(index) = def_case {
|
||||||
let def_case = &mut case_blocks[*index].statements;
|
let mut def_stmt =
|
||||||
let def_span = def_case.span_or_else(*pos, Position::NONE);
|
Stmt::Expr(mem::take(&mut expressions[*index].expr).into());
|
||||||
let def_case: StmtBlockContainer = mem::take(def_case);
|
optimize_stmt(&mut def_stmt, state, true);
|
||||||
let def_stmt =
|
def_stmt.into()
|
||||||
optimize_stmt_block(def_case, state, true, true, false);
|
|
||||||
StmtBlock::new_with_span(def_stmt, def_span)
|
|
||||||
} else {
|
} else {
|
||||||
StmtBlock::NONE
|
StmtBlock::NONE
|
||||||
};
|
};
|
||||||
@ -571,7 +568,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
*stmt = Stmt::If(
|
*stmt = Stmt::If(
|
||||||
(
|
(
|
||||||
mem::take(&mut b.condition),
|
mem::take(&mut b.condition),
|
||||||
mem::take(&mut b.statements),
|
Stmt::Expr(mem::take(&mut b.expr).into()).into(),
|
||||||
else_stmt,
|
else_stmt,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
@ -584,14 +581,13 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
for &index in case_blocks_list {
|
for &index in case_blocks_list {
|
||||||
let mut b = mem::take(&mut case_blocks[index]);
|
let mut b = mem::take(&mut expressions[index]);
|
||||||
|
|
||||||
if b.is_always_true() {
|
if b.is_always_true() {
|
||||||
// Promote the matched case
|
// Promote the matched case
|
||||||
let statements: StmtBlockContainer = mem::take(&mut b.statements);
|
let mut statements = Stmt::Expr(mem::take(&mut b.expr).into());
|
||||||
let statements =
|
optimize_stmt(&mut statements, state, true);
|
||||||
optimize_stmt_block(statements, state, true, true, false);
|
*stmt = statements;
|
||||||
*stmt = (statements, b.statements.span()).into();
|
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -608,18 +604,17 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
if ranges.len() == 1
|
if ranges.len() == 1
|
||||||
|| ranges
|
|| ranges
|
||||||
.iter()
|
.iter()
|
||||||
.all(|r| case_blocks[r.index()].is_always_true())
|
.all(|r| expressions[r.index()].is_always_true())
|
||||||
{
|
{
|
||||||
for r in ranges.iter().filter(|r| r.contains(value)) {
|
for r in ranges.iter().filter(|r| r.contains(value)) {
|
||||||
let range_block = &mut case_blocks[r.index()];
|
let range_block = &mut expressions[r.index()];
|
||||||
|
|
||||||
if range_block.is_always_true() {
|
if range_block.is_always_true() {
|
||||||
// Promote the matched case
|
// Promote the matched case
|
||||||
let block = &mut case_blocks[r.index()];
|
let block = &mut expressions[r.index()];
|
||||||
let statements = mem::take(&mut *block.statements);
|
let mut statements = Stmt::Expr(mem::take(&mut block.expr).into());
|
||||||
let statements =
|
optimize_stmt(&mut statements, state, true);
|
||||||
optimize_stmt_block(statements, state, true, true, false);
|
*stmt = statements;
|
||||||
*stmt = (statements, block.statements.span()).into();
|
|
||||||
} else {
|
} else {
|
||||||
let mut condition = mem::take(&mut range_block.condition);
|
let mut condition = mem::take(&mut range_block.condition);
|
||||||
|
|
||||||
@ -627,20 +622,20 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
optimize_expr(&mut condition, state, false);
|
optimize_expr(&mut condition, state, false);
|
||||||
|
|
||||||
let else_stmt = if let Some(index) = def_case {
|
let else_stmt = if let Some(index) = def_case {
|
||||||
let def_case = &mut case_blocks[*index].statements;
|
let mut def_stmt =
|
||||||
let def_span = def_case.span_or_else(*pos, Position::NONE);
|
Stmt::Expr(mem::take(&mut expressions[*index].expr).into());
|
||||||
let def_case: StmtBlockContainer = mem::take(def_case);
|
optimize_stmt(&mut def_stmt, state, true);
|
||||||
let def_stmt =
|
def_stmt.into()
|
||||||
optimize_stmt_block(def_case, state, true, true, false);
|
|
||||||
StmtBlock::new_with_span(def_stmt, def_span)
|
|
||||||
} else {
|
} else {
|
||||||
StmtBlock::NONE
|
StmtBlock::NONE
|
||||||
};
|
};
|
||||||
|
|
||||||
let statements = mem::take(&mut case_blocks[r.index()].statements);
|
let if_stmt =
|
||||||
|
Stmt::Expr(mem::take(&mut expressions[r.index()].expr).into())
|
||||||
|
.into();
|
||||||
|
|
||||||
*stmt = Stmt::If(
|
*stmt = Stmt::If(
|
||||||
(condition, statements, else_stmt).into(),
|
(condition, if_stmt, else_stmt).into(),
|
||||||
match_expr.start_position(),
|
match_expr.start_position(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -664,12 +659,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
|
|
||||||
for r in &*ranges {
|
for r in &*ranges {
|
||||||
let b = &mut case_blocks[r.index()];
|
let b = &mut expressions[r.index()];
|
||||||
let statements = mem::take(&mut *b.statements);
|
|
||||||
*b.statements =
|
|
||||||
optimize_stmt_block(statements, state, preserve_result, true, false);
|
|
||||||
|
|
||||||
optimize_expr(&mut b.condition, state, false);
|
optimize_expr(&mut b.condition, state, false);
|
||||||
|
optimize_expr(&mut b.expr, state, false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -679,11 +671,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
|
|
||||||
if let Some(index) = def_case {
|
if let Some(index) = def_case {
|
||||||
let def_case = &mut case_blocks[*index].statements;
|
let mut def_stmt = Stmt::Expr(mem::take(&mut expressions[*index].expr).into());
|
||||||
let def_span = def_case.span_or_else(*pos, Position::NONE);
|
optimize_stmt(&mut def_stmt, state, true);
|
||||||
let def_case: StmtBlockContainer = mem::take(def_case);
|
*stmt = def_stmt;
|
||||||
let def_stmt = optimize_stmt_block(def_case, state, true, true, false);
|
|
||||||
*stmt = (def_stmt, def_span).into();
|
|
||||||
} else {
|
} else {
|
||||||
*stmt = StmtBlock::empty(*pos).into();
|
*stmt = StmtBlock::empty(*pos).into();
|
||||||
}
|
}
|
||||||
@ -693,7 +683,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
let (
|
let (
|
||||||
match_expr,
|
match_expr,
|
||||||
SwitchCasesCollection {
|
SwitchCasesCollection {
|
||||||
case_blocks,
|
expressions,
|
||||||
cases,
|
cases,
|
||||||
ranges,
|
ranges,
|
||||||
def_case,
|
def_case,
|
||||||
@ -704,16 +694,13 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
optimize_expr(match_expr, state, false);
|
optimize_expr(match_expr, state, false);
|
||||||
|
|
||||||
// Optimize blocks
|
// Optimize blocks
|
||||||
for b in case_blocks.iter_mut() {
|
for b in expressions.iter_mut() {
|
||||||
let statements = mem::take(&mut *b.statements);
|
|
||||||
*b.statements =
|
|
||||||
optimize_stmt_block(statements, state, preserve_result, true, false);
|
|
||||||
|
|
||||||
optimize_expr(&mut b.condition, state, false);
|
optimize_expr(&mut b.condition, state, false);
|
||||||
|
optimize_expr(&mut b.expr, state, false);
|
||||||
|
|
||||||
if b.is_always_false() {
|
if b.is_always_false() {
|
||||||
if !b.statements.is_empty() {
|
if !b.expr.is_unit() {
|
||||||
b.statements = StmtBlock::NONE;
|
b.expr = Expr::Unit(b.expr.position());
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -723,7 +710,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
cases.retain(|_, list| {
|
cases.retain(|_, list| {
|
||||||
// Remove all entries that have false conditions
|
// Remove all entries that have false conditions
|
||||||
list.retain(|index| {
|
list.retain(|index| {
|
||||||
if case_blocks[*index].is_always_false() {
|
if expressions[*index].is_always_false() {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
@ -733,7 +720,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
// Remove all entries after a `true` condition
|
// Remove all entries after a `true` condition
|
||||||
if let Some(n) = list
|
if let Some(n) = list
|
||||||
.iter()
|
.iter()
|
||||||
.find(|&&index| case_blocks[index].is_always_true())
|
.find(|&&index| expressions[index].is_always_true())
|
||||||
{
|
{
|
||||||
if n + 1 < list.len() {
|
if n + 1 < list.len() {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -752,7 +739,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
|
|
||||||
// Remove false ranges
|
// Remove false ranges
|
||||||
ranges.retain(|r| {
|
ranges.retain(|r| {
|
||||||
if case_blocks[r.index()].is_always_false() {
|
if expressions[r.index()].is_always_false() {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
@ -761,14 +748,11 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
});
|
});
|
||||||
|
|
||||||
if let Some(index) = def_case {
|
if let Some(index) = def_case {
|
||||||
let def_stmt_block = &mut case_blocks[*index].statements;
|
optimize_expr(&mut expressions[*index].expr, state, false);
|
||||||
let def_block = mem::take(&mut **def_stmt_block);
|
|
||||||
**def_stmt_block =
|
|
||||||
optimize_stmt_block(def_block, state, preserve_result, true, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove unused block statements
|
// Remove unused block statements
|
||||||
for index in 0..case_blocks.len() {
|
for index in 0..expressions.len() {
|
||||||
if *def_case == Some(index)
|
if *def_case == Some(index)
|
||||||
|| cases.values().flat_map(|c| c.iter()).any(|&n| n == index)
|
|| cases.values().flat_map(|c| c.iter()).any(|&n| n == index)
|
||||||
|| ranges.iter().any(|r| r.index() == index)
|
|| ranges.iter().any(|r| r.index() == index)
|
||||||
@ -776,10 +760,10 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let b = &mut case_blocks[index];
|
let b = &mut expressions[index];
|
||||||
|
|
||||||
if !b.statements.is_empty() {
|
if !b.expr.is_unit() {
|
||||||
b.statements = StmtBlock::NONE;
|
b.expr = Expr::Unit(b.expr.position());
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
use crate::api::events::VarDefInfo;
|
use crate::api::events::VarDefInfo;
|
||||||
use crate::api::options::LangOptions;
|
use crate::api::options::LangOptions;
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
ASTFlags, BinaryExpr, CaseBlocksList, ConditionalStmtBlock, Expr, FnCallExpr, FnCallHashes,
|
ASTFlags, BinaryExpr, CaseBlocksList, ConditionalExpr, Expr, FnCallExpr, FnCallHashes, Ident,
|
||||||
Ident, OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlockContainer, SwitchCasesCollection,
|
OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlock, StmtBlockContainer,
|
||||||
TryCatchBlock,
|
SwitchCasesCollection, TryCatchBlock,
|
||||||
};
|
};
|
||||||
use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS};
|
use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS};
|
||||||
use crate::eval::GlobalRuntimeState;
|
use crate::eval::GlobalRuntimeState;
|
||||||
@ -1055,7 +1055,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut case_blocks = StaticVec::<ConditionalStmtBlock>::new();
|
let mut expressions = StaticVec::<ConditionalExpr>::new();
|
||||||
let mut cases = BTreeMap::<u64, CaseBlocksList>::new();
|
let mut cases = BTreeMap::<u64, CaseBlocksList>::new();
|
||||||
let mut ranges = StaticVec::<RangeCase>::new();
|
let mut ranges = StaticVec::<RangeCase>::new();
|
||||||
let mut def_case = None;
|
let mut def_case = None;
|
||||||
@ -1142,8 +1142,9 @@ impl Engine {
|
|||||||
let need_comma = !stmt.is_self_terminated();
|
let need_comma = !stmt.is_self_terminated();
|
||||||
let has_condition = !matches!(condition, Expr::BoolConstant(true, ..));
|
let has_condition = !matches!(condition, Expr::BoolConstant(true, ..));
|
||||||
|
|
||||||
case_blocks.push((condition, stmt).into());
|
let stmt_block: StmtBlock = stmt.into();
|
||||||
let index = case_blocks.len() - 1;
|
expressions.push((condition, Expr::Stmt(stmt_block.into())).into());
|
||||||
|
let index = expressions.len() - 1;
|
||||||
|
|
||||||
if !case_expr_list.is_empty() {
|
if !case_expr_list.is_empty() {
|
||||||
for expr in case_expr_list {
|
for expr in case_expr_list {
|
||||||
@ -1224,7 +1225,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let cases = SwitchCasesCollection {
|
let cases = SwitchCasesCollection {
|
||||||
case_blocks,
|
expressions,
|
||||||
cases,
|
cases,
|
||||||
def_case,
|
def_case,
|
||||||
ranges,
|
ranges,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user