Project 3 — Switch Statement - #18
Open
PauloV1 wants to merge 23 commits into
Open
Conversation
- Add scripts/minic wrapper script for convenient access to mini_c binary - Add .envrc configuration for automatic direnv activation - Allows using 'minic' command as documented in README
Introduce the variant in to represent switch-case control flow, including a target expression, literal cases with their bodies, and a default branch.
Parse switch statements in statements.rs, including the target expression, one or more case branches (integer and boolean literals), and a mandatory default block. Ensure each case and default contains at least one statement.
Add todo!() stubs for Statement::Switch in both type checking and evaluation phases to satisfy exhaustive pattern matching and keep the project compiling.
Replaced the mutable closures case_parse and default_parse with declarative nom combinators (tuple and map) inside the switch parser. This removes the need for mutable state in sub-parsers and makes the parsing logic more idiomatic and cohesive.
Implement type checker and interpreter for Switch statement
- Implement semantic check to reject duplicate cases in a switch block - fix: make literal pattern matching exhaustive by returning a TypeError for unsupported types
- Implement runtime/evaluation check for duplicate labels in switch cases - fix: import from AST module to resolve scope compilation error
tac code generation
Replace the separate cases/default fields on Statement::Switch with a single Vec<(MatchCase, Box<StatementD<Ty>>)>, where MatchCase is CaseLiteral(Literal) or CaseDefault. The parser now parses zero or more case arms followed by an optional default arm via a shared case_body helper, appending it to the case list; each arm body is wrapped in a Block so it stays a single StatementD instead of a Vec<StatementD>.
Update type_check_stmt to consume the unified MatchCase::CaseLiteral/ CaseDefault representation instead of a separate cases/default split, enforcing at most one default case.
Consume the unified MatchCase::CaseLiteral/CaseDefault cases instead of the separate cases/default fields, executing the first matching arm's Block directly rather than looping over a flat statement list. Drops the now-redundant duplicate-label check and manual scope cleanup, since the type checker already rejects duplicates and Block handles its own scope.
Consume the unified MatchCase::CaseLiteral/CaseDefault cases: only literal arms get their own label, the default arm (if present) reuses label_default, and a synthetic label_default is emitted when no default exists so the fallback jump still has a landing spot. Update TAC tests to build cases as (MatchCase, Box<CheckedStmt>) pairs.
Add interpreter_switch.minic (matched case, matched default, and no-match-with-no-default fallthrough) and cli_switch_type_mismatch.minic (non-Int/Bool target), exercised via new --check/--run scenarios in check.test and run.test. Closes the gap where switch was covered at the unit/integration level but never through the actual mini_c binary.
Add a Switch section to the language reference (01), the MatchCase AST shape (03), the type-checker's target/case/default rules (05), an exec_stmt table row (06), and the new CLI fixture scenario (08).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR implements the changes suggested by the professor during the presentation.
Statement::Switchused to carry two separate fields —cases: Vec<(Literal, Vec<StatementD<Ty>>)>anddefault: Vec<StatementD<Ty>>— which forced every downstream stage (parser, type checker, interpreter, codegen) to handle the default arm as a special, duplicated code path. This PR collapses both into a singleVec<(MatchCase, Box<StatementD<Ty>>)>, whereMatchCaseisCaseLiteral(Literal) | CaseDefault, and propagates that shape through the whole pipeline.What changed
ast/parser: introduceMatchCaseand switchStatement::Switchto a singlecasesvector. The parser parses zero or more case arms followed by an optional default arm via a sharedcase_bodyhelper, wrapping each arm body in aBlockso it stays a singleStatementDinstead of aVec<StatementD>.type-checker:type_check_stmtconsumes the unified representation and enforces at most onedefaultcase.interpreter: executes the first matching arm'sBlockdirectly instead of looping over a flat statement list. Drops the now-redundant duplicate-label check and manual scope cleanup, since the type checker already rejects duplicates andBlockhandles its own scope.codegen: only literal arms get their own label; the default arm (if present) reuseslabel_default, and a syntheticlabel_defaultis emitted when no default exists so the fallback jump still has a landing spot. TAC tests updated to build cases as(MatchCase, Box<CheckedStmt>)pairs.Why
The split
cases/defaultrepresentation meant "is this the default arm?" was answered differently in four places, and the default body being a bareVec<StatementD>(vs. aBlockfor cases) was an inconsistency with no real benefit. Unifying onMatchCaseremoves that duplication and lets each stage treat every arm uniformly.