Make default switch case Optional.
This commit is contained in:
parent
7dca916c45
commit
f2724444bb
@ -266,10 +266,10 @@ pub struct SwitchCasesCollection {
|
|||||||
pub case_blocks: StaticVec<ConditionalStmtBlock>,
|
pub case_blocks: StaticVec<ConditionalStmtBlock>,
|
||||||
/// Dictionary mapping value hashes to [`ConditionalStmtBlock`]'s.
|
/// Dictionary mapping value hashes to [`ConditionalStmtBlock`]'s.
|
||||||
pub cases: BTreeMap<u64, CaseBlocksList>,
|
pub cases: BTreeMap<u64, CaseBlocksList>,
|
||||||
/// Statements block for the default case (there can be no condition for the default case).
|
|
||||||
pub def_case: usize,
|
|
||||||
/// List of range cases.
|
/// List of range cases.
|
||||||
pub ranges: StaticVec<RangeCase>,
|
pub ranges: StaticVec<RangeCase>,
|
||||||
|
/// Statements block for the default case (there can be no condition for the default case).
|
||||||
|
pub def_case: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// _(internals)_ A `try-catch` block.
|
/// _(internals)_ A `try-catch` block.
|
||||||
@ -765,7 +765,8 @@ impl Stmt {
|
|||||||
let block = &sw.case_blocks[r.index()];
|
let block = &sw.case_blocks[r.index()];
|
||||||
block.condition.is_pure() && block.statements.iter().all(Stmt::is_pure)
|
block.condition.is_pure() && block.statements.iter().all(Stmt::is_pure)
|
||||||
})
|
})
|
||||||
&& sw.case_blocks[sw.def_case]
|
&& sw.def_case.is_some()
|
||||||
|
&& sw.case_blocks[sw.def_case.unwrap()]
|
||||||
.statements
|
.statements
|
||||||
.iter()
|
.iter()
|
||||||
.all(Stmt::is_pure)
|
.all(Stmt::is_pure)
|
||||||
@ -935,9 +936,11 @@ impl Stmt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for s in &sw.case_blocks[sw.def_case].statements {
|
if let Some(index) = sw.def_case {
|
||||||
if !s.walk(path, on_node) {
|
for s in &sw.case_blocks[index].statements {
|
||||||
return false;
|
if !s.walk(path, on_node) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -498,12 +498,16 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
} else if let Ok(None) = stmt_block_result {
|
} else if let Ok(None) = stmt_block_result {
|
||||||
// Default match clause
|
// Default match clause
|
||||||
let def_case = &case_blocks[*def_case].statements;
|
if let Some(index) = def_case {
|
||||||
|
let def_case = &case_blocks[*index].statements;
|
||||||
|
|
||||||
if !def_case.is_empty() {
|
if !def_case.is_empty() {
|
||||||
self.eval_stmt_block(
|
self.eval_stmt_block(
|
||||||
scope, global, caches, lib, this_ptr, def_case, true, level,
|
scope, global, caches, lib, this_ptr, def_case, true, level,
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
Ok(Dynamic::UNIT)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::UNIT)
|
Ok(Dynamic::UNIT)
|
||||||
}
|
}
|
||||||
|
@ -559,16 +559,22 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
// 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(condition, state, false);
|
optimize_expr(condition, state, false);
|
||||||
|
|
||||||
let def_case = &mut case_blocks[*def_case].statements;
|
let else_stmt = if let Some(index) = def_case {
|
||||||
let def_span = def_case.span_or_else(*pos, Position::NONE);
|
let def_case = &mut case_blocks[*index].statements;
|
||||||
let def_case: StmtBlockContainer = mem::take(def_case);
|
let def_span = def_case.span_or_else(*pos, Position::NONE);
|
||||||
let def_stmt =
|
let def_case: StmtBlockContainer = mem::take(def_case);
|
||||||
optimize_stmt_block(def_case, state, true, true, false);
|
let def_stmt =
|
||||||
|
optimize_stmt_block(def_case, state, true, true, false);
|
||||||
|
StmtBlock::new_with_span(def_stmt, def_span)
|
||||||
|
} else {
|
||||||
|
StmtBlock::NONE
|
||||||
|
};
|
||||||
|
|
||||||
*stmt = Stmt::If(
|
*stmt = Stmt::If(
|
||||||
(
|
(
|
||||||
mem::take(condition),
|
mem::take(condition),
|
||||||
mem::take(&mut b.statements),
|
mem::take(&mut b.statements),
|
||||||
StmtBlock::new_with_span(def_stmt, def_span),
|
else_stmt,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
match_expr.start_position(),
|
match_expr.start_position(),
|
||||||
@ -630,21 +636,21 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
// switch const { range if condition => stmt, _ => def } => if condition { stmt } else { def }
|
// switch const { range if condition => stmt, _ => def } => if condition { stmt } else { def }
|
||||||
optimize_expr(&mut condition, state, false);
|
optimize_expr(&mut condition, state, false);
|
||||||
|
|
||||||
let def_case = &mut case_blocks[*def_case].statements;
|
let else_stmt = if let Some(index) = def_case {
|
||||||
let def_span = def_case.span_or_else(*pos, Position::NONE);
|
let def_case = &mut case_blocks[*index].statements;
|
||||||
let def_case: StmtBlockContainer = mem::take(def_case);
|
let def_span = def_case.span_or_else(*pos, Position::NONE);
|
||||||
let def_stmt =
|
let def_case: StmtBlockContainer = mem::take(def_case);
|
||||||
optimize_stmt_block(def_case, state, true, true, false);
|
let def_stmt =
|
||||||
|
optimize_stmt_block(def_case, state, true, true, false);
|
||||||
|
StmtBlock::new_with_span(def_stmt, def_span)
|
||||||
|
} else {
|
||||||
|
StmtBlock::NONE
|
||||||
|
};
|
||||||
|
|
||||||
let statements = mem::take(&mut case_blocks[r.index()].statements);
|
let statements = mem::take(&mut case_blocks[r.index()].statements);
|
||||||
|
|
||||||
*stmt = Stmt::If(
|
*stmt = Stmt::If(
|
||||||
(
|
(condition, statements, else_stmt).into(),
|
||||||
condition,
|
|
||||||
statements,
|
|
||||||
StmtBlock::new_with_span(def_stmt, def_span),
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
match_expr.start_position(),
|
match_expr.start_position(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -690,11 +696,16 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
|
|
||||||
// Promote the default case
|
// Promote the default case
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
let def_case = &mut case_blocks[*def_case].statements;
|
|
||||||
let def_span = def_case.span_or_else(*pos, Position::NONE);
|
if let Some(index) = def_case {
|
||||||
let def_case: StmtBlockContainer = mem::take(def_case);
|
let def_case = &mut case_blocks[*index].statements;
|
||||||
let def_stmt = optimize_stmt_block(def_case, state, true, true, false);
|
let def_span = def_case.span_or_else(*pos, Position::NONE);
|
||||||
*stmt = (def_stmt, def_span).into();
|
let def_case: StmtBlockContainer = mem::take(def_case);
|
||||||
|
let def_stmt = optimize_stmt_block(def_case, state, true, true, false);
|
||||||
|
*stmt = (def_stmt, def_span).into();
|
||||||
|
} else {
|
||||||
|
*stmt = StmtBlock::empty(*pos).into();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// switch
|
// switch
|
||||||
Stmt::Switch(x, ..) => {
|
Stmt::Switch(x, ..) => {
|
||||||
@ -735,11 +746,13 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove false cases
|
// Remove false cases
|
||||||
let cases_len = cases.len();
|
|
||||||
cases.retain(|_, list| {
|
cases.retain(|_, list| {
|
||||||
// Remove all entries that have false conditions
|
// Remove all entries that have false conditions
|
||||||
list.retain(|index| match case_blocks[*index].condition {
|
list.retain(|index| match case_blocks[*index].condition {
|
||||||
Expr::BoolConstant(false, ..) => false,
|
Expr::BoolConstant(false, ..) => {
|
||||||
|
state.set_dirty();
|
||||||
|
false
|
||||||
|
}
|
||||||
_ => true,
|
_ => true,
|
||||||
});
|
});
|
||||||
// Remove all entries after a `true` condition
|
// Remove all entries after a `true` condition
|
||||||
@ -750,14 +763,21 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
list.truncate(n + 1);
|
if n + 1 < list.len() {
|
||||||
|
state.set_dirty();
|
||||||
|
list.truncate(n + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Remove if no entry left
|
// Remove if no entry left
|
||||||
!list.is_empty()
|
match list.is_empty() {
|
||||||
|
true => {
|
||||||
|
state.set_dirty();
|
||||||
|
false
|
||||||
|
}
|
||||||
|
false => true,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if cases.len() != cases_len {
|
|
||||||
state.set_dirty();
|
|
||||||
}
|
|
||||||
// Remove false ranges
|
// Remove false ranges
|
||||||
ranges.retain(|r| match case_blocks[r.index()].condition {
|
ranges.retain(|r| match case_blocks[r.index()].condition {
|
||||||
Expr::BoolConstant(false, ..) => {
|
Expr::BoolConstant(false, ..) => {
|
||||||
@ -767,13 +787,16 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
_ => true,
|
_ => true,
|
||||||
});
|
});
|
||||||
|
|
||||||
let def_stmt_block = &mut case_blocks[*def_case].statements;
|
if let Some(index) = def_case {
|
||||||
let def_block = mem::take(&mut **def_stmt_block);
|
let def_stmt_block = &mut case_blocks[*index].statements;
|
||||||
**def_stmt_block = optimize_stmt_block(def_block, state, preserve_result, true, 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..case_blocks.len() {
|
||||||
if *def_case == 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)
|
||||||
{
|
{
|
||||||
|
@ -1058,8 +1058,8 @@ impl Engine {
|
|||||||
let mut case_blocks = StaticVec::<ConditionalStmtBlock>::new();
|
let mut case_blocks = StaticVec::<ConditionalStmtBlock>::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_stmt_pos = Position::NONE;
|
let mut def_case = None;
|
||||||
let mut def_stmt_index = None;
|
let mut def_case_pos = Position::NONE;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
const MISSING_RBRACE: &str = "to end this switch block";
|
const MISSING_RBRACE: &str = "to end this switch block";
|
||||||
@ -1075,8 +1075,8 @@ impl Engine {
|
|||||||
.into_err(*pos),
|
.into_err(*pos),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
(Token::Underscore, pos) if def_stmt_index.is_none() => {
|
(Token::Underscore, pos) if def_case.is_none() => {
|
||||||
def_stmt_pos = *pos;
|
def_case_pos = *pos;
|
||||||
eat_token(input, Token::Underscore);
|
eat_token(input, Token::Underscore);
|
||||||
|
|
||||||
let (if_clause, if_pos) = match_token(input, Token::If);
|
let (if_clause, if_pos) = match_token(input, Token::If);
|
||||||
@ -1087,8 +1087,8 @@ impl Engine {
|
|||||||
|
|
||||||
(Default::default(), Expr::BoolConstant(true, Position::NONE))
|
(Default::default(), Expr::BoolConstant(true, Position::NONE))
|
||||||
}
|
}
|
||||||
_ if def_stmt_index.is_some() => {
|
_ if def_case.is_some() => {
|
||||||
return Err(PERR::WrongSwitchDefaultCase.into_err(def_stmt_pos))
|
return Err(PERR::WrongSwitchDefaultCase.into_err(def_case_pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
@ -1197,7 +1197,7 @@ impl Engine {
|
|||||||
.or_insert_with(|| [index].into());
|
.or_insert_with(|| [index].into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
def_stmt_index = Some(index);
|
def_case = Some(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
match input.peek().expect(NEVER_ENDS) {
|
match input.peek().expect(NEVER_ENDS) {
|
||||||
@ -1223,11 +1223,6 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let def_case = def_stmt_index.unwrap_or_else(|| {
|
|
||||||
case_blocks.push(Default::default());
|
|
||||||
case_blocks.len() - 1
|
|
||||||
});
|
|
||||||
|
|
||||||
let cases = SwitchCasesCollection {
|
let cases = SwitchCasesCollection {
|
||||||
case_blocks,
|
case_blocks,
|
||||||
cases,
|
cases,
|
||||||
|
Loading…
Reference in New Issue
Block a user