diff --git a/src/interpreter/exec_stmt.rs b/src/interpreter/exec_stmt.rs index 0dc0dad..db88f30 100644 --- a/src/interpreter/exec_stmt.rs +++ b/src/interpreter/exec_stmt.rs @@ -34,7 +34,7 @@ //! This gives MiniC correct lexical block scoping without a scope stack. use crate::environment::Environment; -use crate::ir::ast::{CheckedExpr, CheckedStmt, Expr, Statement}; +use crate::ir::ast::{CheckedExpr, CheckedStmt, Expr, Literal, Statement}; use super::eval_expr::{eval_call, eval_expr}; use super::value::{RuntimeError, Value}; @@ -114,6 +114,7 @@ pub fn exec_stmt(stmt: &CheckedStmt, env: &mut Environment) -> ExecResult // --- Switch --- Statement::Switch { target, cases, default } => { + ensure_unique_switch_labels(cases)?; // Avalia o valor da expressão alvo let target_val = eval_expr(target, env)?; @@ -295,3 +296,18 @@ fn extract_ident_name(expr: &CheckedExpr) -> Result { )), } } + +fn ensure_unique_switch_labels( + cases: &[(Literal, Vec)], +) -> Result<(), RuntimeError> { + for (i, (label, _)) in cases.iter().enumerate() { + if cases.iter().skip(i + 1).any(|(other, _)| other == label) { + return Err(RuntimeError::new(format!( + "duplicate switch case label: {:?}", + label + ))); + } + } + + Ok(()) +} diff --git a/src/semantic/type_checker.rs b/src/semantic/type_checker.rs index 4d643c1..657df57 100644 --- a/src/semantic/type_checker.rs +++ b/src/semantic/type_checker.rs @@ -253,6 +253,11 @@ fn type_check_stmt( let lit_ty = match lit { Literal::Int(_) => Type::Int, Literal::Bool(_) => Type::Bool, + _ => { + return Err(TypeError::new( + "switch case label must be an Int or Bool literal", + )); + } }; // Garante que o tipo do literal é compatível com o tipo do target diff --git a/tests/interpreter.rs b/tests/interpreter.rs index 51696c9..6bede41 100644 --- a/tests/interpreter.rs +++ b/tests/interpreter.rs @@ -196,6 +196,114 @@ fn test_out_of_bounds() { ); } +// --------------------------------------------------------------------------- +// 7.10b Switch +// --------------------------------------------------------------------------- +#[test] +fn test_switch_int_case_executes_matching_branch() { + let src = r#" + int choose(int x) { + switch x { + case 1: return 10; + case 2: return 20; + default: return 99; + } + } + + void main() { + int result = choose(2); + if result != 20 { + int[] arr = [1]; + int fail = arr[5]; + } + } + "#; + assert!(run(src).is_ok(), "{}", run(src).unwrap_err()); +} + +#[test] +fn test_switch_int_default_executes_when_no_case_matches() { + let src = r#" + int choose(int x) { + switch x { + case 1: return 10; + case 2: return 20; + default: return 99; + } + } + + void main() { + int result = choose(3); + if result != 99 { + int[] arr = [1]; + int fail = arr[5]; + } + } + "#; + assert!(run(src).is_ok(), "{}", run(src).unwrap_err()); +} + +#[test] +fn test_switch_bool_case_executes_matching_branch() { + let src = r#" + int choose(bool flag) { + switch flag { + case true: return 1; + case false: return 0; + default: return 99; + } + } + + void main() { + int result = choose(false); + if result != 0 { + int[] arr = [1]; + int fail = arr[5]; + } + } + "#; + assert!(run(src).is_ok(), "{}", run(src).unwrap_err()); +} + +#[test] +fn test_switch_assignment_to_outer_variable_persists() { + let src = r#" + void main() { + int result = 0; + switch 1 { + case 1: result = 10; + case 2: result = 20; + default: result = 99; + } + + if result != 10 { + int[] arr = [1]; + int fail = arr[5]; + } + } + "#; + assert!(run(src).is_ok(), "{}", run(src).unwrap_err()); +} + +#[test] +fn test_switch_duplicate_case_labels_error() { + let src = r#" + void main() { + switch 1 { + case 1: print("one"); + case 1: print("again"); + default: print("other"); + } + } + "#; + let result = run(src); + assert!(result.is_err(), "expected duplicate switch case label error"); + assert!( + result.unwrap_err().contains("duplicate switch case label"), + "error should mention duplicate switch case label" + ); +} + // --------------------------------------------------------------------------- // 7.11 Undefined function (caught by type checker) // ---------------------------------------------------------------------------