diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-16 10:04:27 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-16 10:04:27 +0000 |
| commit | 45c9d37eb27d204a6202b33cb37e890af0171357 (patch) | |
| tree | dba23170b16053c5e1ec4bf78efc2a533cb94a4e /lib/CodeGen/ControlFlowGen.cc | |
| parent | 522742e9df7fc5ac596ce4aa53d41b31e4f6a030 (diff) | |
feat(control-flow): implement ordered CASE OF matching
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/ControlFlowGen.cc')
| -rw-r--r-- | lib/CodeGen/ControlFlowGen.cc | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/lib/CodeGen/ControlFlowGen.cc b/lib/CodeGen/ControlFlowGen.cc index ebd5d3c..f9300dd 100644 --- a/lib/CodeGen/ControlFlowGen.cc +++ b/lib/CodeGen/ControlFlowGen.cc @@ -173,3 +173,61 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) { Builder->SetInsertPoint(AfterBB); } + +void CodeGen::emitCaseStmt(CaseStmtAST *Stmt) { + VariableExprAST Selector(Stmt->getSelector()); + if (isWholeArrayVar(&Selector)) { + reportError("CASE selector cannot be a whole array"); + return; + } + const TypeInfo *SelectorType = getExprTypeInfo(&Selector); + Value *Selected = emitExpr(&Selector); + if (!Selected || !SelectorType) return; + + auto *F = Builder->GetInsertBlock()->getParent(); + F->addFnAttr("no-jump-tables", "true"); + auto *After = BasicBlock::Create(*TheContext, "case_cont", F); + auto SavedArrays = Arrays->snapshotTable(); + for (const auto &Branch : Stmt->getBranches()) { + auto *Body = BasicBlock::Create(*TheContext, "case_body", F); + auto *Next = BasicBlock::Create(*TheContext, "case_next", F); + auto Compare = [&](int Op, ExprAST *Label) -> Value * { + if (isWholeArrayVar(Label)) { + reportError("CASE label cannot be a whole array"); + return nullptr; + } + const TypeInfo *LabelType = getExprTypeInfo(Label); + if (!LabelType) { + reportError("Cannot determine CASE label type at line %d", Branch.Line); + return nullptr; + } + Value *LabelValue = emitExpr(Label); + return emitBinaryOp(Op, Selected, SelectorType, LabelValue, LabelType, Branch.Line); + }; + if (!Branch.Lower) { + Builder->CreateBr(Body); + } else { + Value *Match = Compare(Branch.Upper ? tok_ge : tok_eq, Branch.Lower.get()); + if (!Match) { + // Finish the CFG even after a diagnostic; the driver discards it. + Builder->CreateBr(Next); + } else if (Branch.Upper) { + auto *Upper = BasicBlock::Create(*TheContext, "case_upper", F); + Builder->CreateCondBr(Match, Upper, Next); + Builder->SetInsertPoint(Upper); + Match = Compare(tok_le, Branch.Upper.get()); + if (Match) Builder->CreateCondBr(Match, Body, Next); + else Builder->CreateBr(Next); + } else { + Builder->CreateCondBr(Match, Body, Next); + } + } + Builder->SetInsertPoint(Body); + for (const auto &S : Branch.Body) emitStmt(S.get()); + if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(After); + Arrays->exchangeTable(SavedArrays); + Builder->SetInsertPoint(Next); + } + Builder->CreateBr(After); + Builder->SetInsertPoint(After); +} |
