Allow duplicated switch cases.

This commit is contained in:
Stephen Chung
2022-07-18 13:40:41 +08:00
parent 4b760d1d0f
commit 7dca916c45
9 changed files with 235 additions and 145 deletions

View File

@@ -3,8 +3,9 @@
use crate::api::events::VarDefInfo;
use crate::api::options::LangOptions;
use crate::ast::{
ASTFlags, BinaryExpr, ConditionalStmtBlock, Expr, FnCallExpr, FnCallHashes, Ident,
OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlockContainer, SwitchCases, TryCatchBlock,
ASTFlags, BinaryExpr, CaseBlocksList, ConditionalStmtBlock, Expr, FnCallExpr, FnCallHashes,
Ident, OpAssignment, RangeCase, ScriptFnDef, Stmt, StmtBlockContainer, SwitchCasesCollection,
TryCatchBlock,
};
use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS};
use crate::eval::GlobalRuntimeState;
@@ -1054,11 +1055,11 @@ impl Engine {
}
}
let mut blocks = StaticVec::<ConditionalStmtBlock>::new();
let mut cases = BTreeMap::<u64, usize>::new();
let mut case_blocks = StaticVec::<ConditionalStmtBlock>::new();
let mut cases = BTreeMap::<u64, CaseBlocksList>::new();
let mut ranges = StaticVec::<RangeCase>::new();
let mut def_pos = Position::NONE;
let mut def_stmt = None;
let mut def_stmt_pos = Position::NONE;
let mut def_stmt_index = None;
loop {
const MISSING_RBRACE: &str = "to end this switch block";
@@ -1074,8 +1075,8 @@ impl Engine {
.into_err(*pos),
)
}
(Token::Underscore, pos) if def_stmt.is_none() => {
def_pos = *pos;
(Token::Underscore, pos) if def_stmt_index.is_none() => {
def_stmt_pos = *pos;
eat_token(input, Token::Underscore);
let (if_clause, if_pos) = match_token(input, Token::If);
@@ -1086,10 +1087,8 @@ impl Engine {
(Default::default(), Expr::BoolConstant(true, Position::NONE))
}
(Token::Underscore, pos) => return Err(PERR::DuplicatedSwitchCase.into_err(*pos)),
_ if def_stmt.is_some() => {
return Err(PERR::WrongSwitchDefaultCase.into_err(def_pos))
_ if def_stmt_index.is_some() => {
return Err(PERR::WrongSwitchDefaultCase.into_err(def_stmt_pos))
}
_ => {
@@ -1143,8 +1142,8 @@ impl Engine {
let need_comma = !stmt.is_self_terminated();
let has_condition = !matches!(condition, Expr::BoolConstant(true, ..));
blocks.push((condition, stmt).into());
let index = blocks.len() - 1;
case_blocks.push((condition, stmt).into());
let index = case_blocks.len() - 1;
if !case_expr_list.is_empty() {
for expr in case_expr_list {
@@ -1170,7 +1169,10 @@ impl Engine {
for n in r {
let hasher = &mut get_hasher();
Dynamic::from_int(n).hash(hasher);
cases.entry(hasher.finish()).or_insert(index);
cases
.entry(hasher.finish())
.and_modify(|cases| cases.push(index))
.or_insert_with(|| [index].into());
}
} else {
// Other range
@@ -1189,13 +1191,13 @@ impl Engine {
value.hash(hasher);
let hash = hasher.finish();
if cases.contains_key(&hash) {
return Err(PERR::DuplicatedSwitchCase.into_err(expr.start_position()));
}
cases.insert(hash, index);
cases
.entry(hash)
.and_modify(|cases| cases.push(index))
.or_insert_with(|| [index].into());
}
} else {
def_stmt = Some(index);
def_stmt_index = Some(index);
}
match input.peek().expect(NEVER_ENDS) {
@@ -1221,13 +1223,13 @@ impl Engine {
}
}
let def_case = def_stmt.unwrap_or_else(|| {
blocks.push(Default::default());
blocks.len() - 1
let def_case = def_stmt_index.unwrap_or_else(|| {
case_blocks.push(Default::default());
case_blocks.len() - 1
});
let cases = SwitchCases {
blocks,
let cases = SwitchCasesCollection {
case_blocks,
cases,
def_case,
ranges,