Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/interpreter/exec_stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -114,6 +114,7 @@ pub fn exec_stmt(stmt: &CheckedStmt, env: &mut Environment<Value>) -> 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)?;

Expand Down Expand Up @@ -295,3 +296,18 @@ fn extract_ident_name(expr: &CheckedExpr) -> Result<String, RuntimeError> {
)),
}
}

fn ensure_unique_switch_labels(
cases: &[(Literal, Vec<CheckedStmt>)],
) -> 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(())
}
5 changes: 5 additions & 0 deletions src/semantic/type_checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
108 changes: 108 additions & 0 deletions tests/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
// ---------------------------------------------------------------------------
Expand Down