From a7b63b8f909f0c17894a9da25c6b274f46dcd0c7 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Thu, 22 Oct 2026 03:55:56 +0000 Subject: refactor(codegen): split large emitStmtImpl arms into methods Move the self-contained FunctionDef, INPUT, OUTPUT and READFILE branches of emitStmtImpl into private emitFunctionDefStmt, emitInputStmt, emitOutputStmt and emitReadFileStmt methods. The dispatch order and the branch bodies are unchanged. Co-Authored-By: Claude Opus 5.5 --- lib/CodeGen/StatementGen.cc | 240 +++++++++++++++++++++++--------------------- 1 file changed, 128 insertions(+), 112 deletions(-) (limited to 'lib/CodeGen') diff --git a/lib/CodeGen/StatementGen.cc b/lib/CodeGen/StatementGen.cc index c1a9490..0b14cf2 100644 --- a/lib/CodeGen/StatementGen.cc +++ b/lib/CodeGen/StatementGen.cc @@ -35,27 +35,7 @@ void CodeGen::emitStmtImpl(StmtAST *Stmt) { } if (auto *FuncDef = dynamic_cast(Stmt)) { - SaveAndRestore ClassContext(CurrentClass, FuncDef->getProto()->getOwnerClass()); - for (const auto &Param : FuncDef->getProto()->getParams()) - warnMemberShadow(Param.Name, Param.Line ? Param.Line : DiagnosticLine); - BasicBlock *SavedBlock = Builder->GetInsertBlock(); - // Function bodies get a fresh array scope (metadata SSA values belong - // to the emitting function), mirroring FunctionGen's Symbols handling. - auto SavedArrays = Arrays->exchangeTable({}); - - auto SavedObjects = std::move(StackObjects); - StackObjects.clear(); - auto SavedScopes = std::move(ConstantScopes); - ConstantScopes = {{NextScopeID++, {}}}; - Function *Emitted = FuncGen->emitFunctionDef(FuncDef, [this](StmtAST *S) { - this->emitStmt(S); - }, ConstantScopes.back().ID); - if (Emitted) finishStackObjects(Emitted); - StackObjects = std::move(SavedObjects); - ConstantScopes = std::move(SavedScopes); - - Arrays->exchangeTable(std::move(SavedArrays)); - if (SavedBlock) Builder->SetInsertPoint(SavedBlock); + emitFunctionDefStmt(FuncDef); return; } @@ -164,69 +144,12 @@ void CodeGen::emitStmtImpl(StmtAST *Stmt) { } if (auto *In = dynamic_cast(Stmt)) { - LValueInfo Target; - if (!emitLValue(In->getTarget(), Target)) return; - const TypeInfo *TypeInfo = resolveType(Target.TypeName); - if (!TypeInfo) { - reportError("Unknown type for INPUT %s", Target.TypeName.c_str()); - return; - } - - std::vector Args; - if (TypeInfo->isC()) { - emitCInput(Target.Addr, TypeInfo); - } else if (TypeInfo->isReal()) { - Args.push_back(ScanfFloatFormatStr); - Args.push_back(Target.Addr); - Builder->CreateCall(ScanfFunc, Args); - } else if (TypeInfo->isBoolean()) { - AllocaInst *TempInt = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), "tmp_bool_input"); - Args.push_back(ScanfFormatStr); - Args.push_back(TempInt); - Builder->CreateCall(ScanfFunc, Args); - - Value *Val = Builder->CreateLoad(Type::getInt64Ty(*TheContext), TempInt); - Value *BoolVal = Builder->CreateICmpNE(Val, ConstantInt::get(*TheContext, APInt(64, 0)), "bool_cast"); - Builder->CreateStore(BoolVal, Target.Addr); - } else if (TypeInfo->isString()) { - emitMethodCall(TypeInfo->Name, Target.Addr, "READ_INPUT", {}, Stmt->getLine()); - } else if (TypeInfo->isChar()) { - Value *CharFmt = Builder->CreateGlobalString(" %c", "fmt_in_char", 0, TheModule.get()); - Args.push_back(CharFmt); - Args.push_back(Target.Addr); - Builder->CreateCall(ScanfFunc, Args); - } else if (TypeInfo->Kind == TypeKind::Integer) { - Args.push_back(ScanfFormatStr); - Args.push_back(Target.Addr); - Builder->CreateCall(ScanfFunc, Args); - } else { - // Enum/Record/Pointer and any future kind: scanf'ing raw bytes - // into typed storage would corrupt it — reject explicitly. - reportError("INPUT is not supported for a value of type %s", TypeInfo->Name.c_str()); - } + emitInputStmt(In); return; } if (auto *Out = dynamic_cast(Stmt)) { - const auto &Exprs = Out->getExprs(); - for (size_t I = 0; I < Exprs.size(); ++I) { - ExprAST *Expr = Exprs[I].get(); - if (Arrays->tryEmitArrayOutput(Expr, *this)) continue; - - Value *Val = emitExpr(Expr); - const TypeInfo *TypeInfo = getExprTypeInfo(Expr); - if (!TypeInfo) { - reportError("Cannot infer the type of the OUTPUT expression"); - continue; - } - if (TypeInfo->isVoid()) { - reportError("Cannot OUTPUT the result of a PROCEDURE call"); - continue; - } - if (TypeInfo->IsClass && !isObjectLValue(Expr)) - materializeOperatorReceiver(Val, TypeInfo); - emitOutputValue(Val, TypeInfo, I + 1 == Exprs.size()); - } + emitOutputStmt(Out); return; } @@ -238,38 +161,7 @@ void CodeGen::emitStmtImpl(StmtAST *Stmt) { } if (auto *Read = dynamic_cast(Stmt)) { - const SymbolInfo *Info = getSymbolInfo(Read->getVarName()); - if (!Info) { - reportError("Unknown variable name %s", Read->getVarName().c_str()); - return; - } - if (!requireWritable(*Info, Read->getVarName())) return; - if (Info->IsArray) { - reportError("READFILE into entire array %s is not supported", Read->getVarName().c_str()); - return; - } - if (!sameIdentifier(Info->TypeName, "STRING")) { - reportError("READFILE variable %s must be of type STRING (got %s)", - Read->getVarName().c_str(), Info->TypeName.c_str()); - return; - } - Value *Name = emitFileNameOperand(Read->getFileName(), "READFILE"); - if (!Name) return; - Value *LineStr = Files->emitRead(Name, Read->getLine()); - if (!LineStr) return; - const auto *Type = resolveType(Info->TypeName); - for (const FuncSig *Sig : FuncGen->getOverloads(Type->Name + ".OPERATOR <-")) { - if (Sig->Params.size() == 1 && !Sig->Params[0].IsByRef && - resolveType("C_STRING")->sameType(resolveType(Sig->Params[0].TypeName)) && - checkOperatorAccess(*Sig)) { - FuncGen->emitCall(*Sig, {symbolAddress(*Info), LineStr}); - auto Free = TheModule->getOrInsertFunction("free", FunctionType::get( - Type::getVoidTy(*TheContext), {PointerType::getUnqual(*TheContext)}, false)); - Builder->CreateCall(Free, {LineStr}); - return; - } - } - reportError("READFILE requires STRING.OPERATOR<-(Text : C_STRING)"); + emitReadFileStmt(Read); return; } @@ -327,6 +219,130 @@ void CodeGen::emitStmtImpl(StmtAST *Stmt) { } } +void CodeGen::emitFunctionDefStmt(FunctionDefAST *FuncDef) { + SaveAndRestore ClassContext(CurrentClass, FuncDef->getProto()->getOwnerClass()); + for (const auto &Param : FuncDef->getProto()->getParams()) + warnMemberShadow(Param.Name, Param.Line ? Param.Line : DiagnosticLine); + BasicBlock *SavedBlock = Builder->GetInsertBlock(); + // Function bodies get a fresh array scope (metadata SSA values belong + // to the emitting function), mirroring FunctionGen's Symbols handling. + auto SavedArrays = Arrays->exchangeTable({}); + + auto SavedObjects = std::move(StackObjects); + StackObjects.clear(); + auto SavedScopes = std::move(ConstantScopes); + ConstantScopes = {{NextScopeID++, {}}}; + Function *Emitted = FuncGen->emitFunctionDef(FuncDef, [this](StmtAST *S) { + this->emitStmt(S); + }, ConstantScopes.back().ID); + if (Emitted) finishStackObjects(Emitted); + StackObjects = std::move(SavedObjects); + ConstantScopes = std::move(SavedScopes); + + Arrays->exchangeTable(std::move(SavedArrays)); + if (SavedBlock) Builder->SetInsertPoint(SavedBlock); +} + +void CodeGen::emitInputStmt(InputStmtAST *In) { + LValueInfo Target; + if (!emitLValue(In->getTarget(), Target)) return; + const TypeInfo *TypeInfo = resolveType(Target.TypeName); + if (!TypeInfo) { + reportError("Unknown type for INPUT %s", Target.TypeName.c_str()); + return; + } + + std::vector Args; + if (TypeInfo->isC()) { + emitCInput(Target.Addr, TypeInfo); + } else if (TypeInfo->isReal()) { + Args.push_back(ScanfFloatFormatStr); + Args.push_back(Target.Addr); + Builder->CreateCall(ScanfFunc, Args); + } else if (TypeInfo->isBoolean()) { + AllocaInst *TempInt = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), "tmp_bool_input"); + Args.push_back(ScanfFormatStr); + Args.push_back(TempInt); + Builder->CreateCall(ScanfFunc, Args); + + Value *Val = Builder->CreateLoad(Type::getInt64Ty(*TheContext), TempInt); + Value *BoolVal = Builder->CreateICmpNE(Val, ConstantInt::get(*TheContext, APInt(64, 0)), "bool_cast"); + Builder->CreateStore(BoolVal, Target.Addr); + } else if (TypeInfo->isString()) { + emitMethodCall(TypeInfo->Name, Target.Addr, "READ_INPUT", {}, In->getLine()); + } else if (TypeInfo->isChar()) { + Value *CharFmt = Builder->CreateGlobalString(" %c", "fmt_in_char", 0, TheModule.get()); + Args.push_back(CharFmt); + Args.push_back(Target.Addr); + Builder->CreateCall(ScanfFunc, Args); + } else if (TypeInfo->Kind == TypeKind::Integer) { + Args.push_back(ScanfFormatStr); + Args.push_back(Target.Addr); + Builder->CreateCall(ScanfFunc, Args); + } else { + // Enum/Record/Pointer and any future kind: scanf'ing raw bytes + // into typed storage would corrupt it — reject explicitly. + reportError("INPUT is not supported for a value of type %s", TypeInfo->Name.c_str()); + } +} + +void CodeGen::emitOutputStmt(OutputStmtAST *Out) { + const auto &Exprs = Out->getExprs(); + for (size_t I = 0; I < Exprs.size(); ++I) { + ExprAST *Expr = Exprs[I].get(); + if (Arrays->tryEmitArrayOutput(Expr, *this)) continue; + + Value *Val = emitExpr(Expr); + const TypeInfo *TypeInfo = getExprTypeInfo(Expr); + if (!TypeInfo) { + reportError("Cannot infer the type of the OUTPUT expression"); + continue; + } + if (TypeInfo->isVoid()) { + reportError("Cannot OUTPUT the result of a PROCEDURE call"); + continue; + } + if (TypeInfo->IsClass && !isObjectLValue(Expr)) + materializeOperatorReceiver(Val, TypeInfo); + emitOutputValue(Val, TypeInfo, I + 1 == Exprs.size()); + } +} + +void CodeGen::emitReadFileStmt(ReadFileStmtAST *Read) { + const SymbolInfo *Info = getSymbolInfo(Read->getVarName()); + if (!Info) { + reportError("Unknown variable name %s", Read->getVarName().c_str()); + return; + } + if (!requireWritable(*Info, Read->getVarName())) return; + if (Info->IsArray) { + reportError("READFILE into entire array %s is not supported", Read->getVarName().c_str()); + return; + } + if (!sameIdentifier(Info->TypeName, "STRING")) { + reportError("READFILE variable %s must be of type STRING (got %s)", + Read->getVarName().c_str(), Info->TypeName.c_str()); + return; + } + Value *Name = emitFileNameOperand(Read->getFileName(), "READFILE"); + if (!Name) return; + Value *LineStr = Files->emitRead(Name, Read->getLine()); + if (!LineStr) return; + const auto *Type = resolveType(Info->TypeName); + for (const FuncSig *Sig : FuncGen->getOverloads(Type->Name + ".OPERATOR <-")) { + if (Sig->Params.size() == 1 && !Sig->Params[0].IsByRef && + resolveType("C_STRING")->sameType(resolveType(Sig->Params[0].TypeName)) && + checkOperatorAccess(*Sig)) { + FuncGen->emitCall(*Sig, {symbolAddress(*Info), LineStr}); + auto Free = TheModule->getOrInsertFunction("free", FunctionType::get( + Type::getVoidTy(*TheContext), {PointerType::getUnqual(*TheContext)}, false)); + Builder->CreateCall(Free, {LineStr}); + return; + } + } + reportError("READFILE requires STRING.OPERATOR<-(Text : C_STRING)"); +} + // File keywords take their filename as a STRING-valued expression; a whole // array is rejected before evaluation. Value *CodeGen::emitFileNameOperand(ExprAST *E, const char *Keyword) { -- cgit v1.3.1-4-g156e