diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-16 09:42:45 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-16 09:42:45 +0000 |
| commit | 3dc3a15c86287b2788142b58e2512269cd5274c6 (patch) | |
| tree | 1610b02343fd3e8b6b733c0cbfe327be6fef4394 /lib/CodeGen/OutputGen.cc | |
| parent | db6ac29d0ac769ff780f3901ed987b97965f3f5e (diff) | |
refactor(codegen): split emission by responsibility
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/OutputGen.cc')
| -rw-r--r-- | lib/CodeGen/OutputGen.cc | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/lib/CodeGen/OutputGen.cc b/lib/CodeGen/OutputGen.cc new file mode 100644 index 0000000..c4ceb79 --- /dev/null +++ b/lib/CodeGen/OutputGen.cc @@ -0,0 +1,95 @@ +#include "cps/CodeGen.h" + +using namespace llvm; +using namespace cps; + +Value *CodeGen::emitStringNullGuard(Value *StrVal) { + if (!StrVal || !StrVal->getType()->isPointerTy()) return StrVal; + Value *IsNull = Builder->CreateICmpEQ(StrVal, + ConstantPointerNull::get(cast<PointerType>(StrVal->getType())), + "str_is_null"); + return Builder->CreateSelect(IsNull, EmptyStringStr, StrVal, "safe_str"); +} + +void CodeGen::emitOutputValue(Value *Val, const TypeInfo *Info, bool AppendNewline) { + if (!Val || !Info) return; + + std::vector<Value*> Args; + Value *Fmt = nullptr; + + // Exhaustive over TypeKind (no default): the compiler warns when a new + // kind is added without deciding its OUTPUT story. + switch (Info->Kind) { + case TypeKind::Real: + Fmt = AppendNewline + ? PrintfFloatFormatStr + : Builder->CreateGlobalString("%f", "fmt_flt_inline", 0, TheModule.get()); + Args.push_back(Fmt); + Args.push_back(Val); + break; + + case TypeKind::Boolean: { + Value *BoolVal = coerceValueToType(Val, resolveType("BOOLEAN")); + Fmt = AppendNewline + ? PrintfStringFormatStr + : Builder->CreateGlobalString("%s", "fmt_str_inline", 0, TheModule.get()); + Args.push_back(Fmt); + Args.push_back(Builder->CreateSelect(BoolVal, TrueStr, FalseStr)); + break; + } + + case TypeKind::String: { + Value *StrVal = emitStringNullGuard(Val); + Fmt = AppendNewline + ? PrintfStringFormatStr + : Builder->CreateGlobalString("%s", "fmt_str_inline", 0, TheModule.get()); + Args.push_back(Fmt); + Args.push_back(StrVal); + break; + } + + case TypeKind::Char: { + Value *CharVal = coerceValueToType(Val, resolveType("CHAR")); + Value *Promoted = Builder->CreateZExt(CharVal, Type::getInt32Ty(*TheContext), "char_for_printf"); + Fmt = AppendNewline + ? PrintfCharFormatStr + : Builder->CreateGlobalString("%c", "fmt_chr_inline", 0, TheModule.get()); + Args.push_back(Fmt); + Args.push_back(Promoted); + break; + } + + case TypeKind::Integer: + case TypeKind::Enum: { // an enum prints its ordinal (user decision) + Value *IntVal = Info->isEnum() ? Val : coerceValueToType(Val, resolveType("INTEGER")); + Fmt = AppendNewline + ? PrintfFormatStr + : Builder->CreateGlobalString("%lld", "fmt_int_inline", 0, TheModule.get()); + Args.push_back(Fmt); + Args.push_back(IntVal); + break; + } + + case TypeKind::Record: + reportError("Cannot OUTPUT a value of record type %s; output its fields individually", + Info->Name.c_str()); + return; + + case TypeKind::Pointer: + reportError("Cannot OUTPUT a value of pointer type %s", Info->Name.c_str()); + return; + + case TypeKind::CScalar: + emitCOutput(Val, Info, AppendNewline); + return; + case TypeKind::CPointer: + reportError("OUTPUT is not supported for type %s", Info->Name.c_str()); + return; + + case TypeKind::Void: + reportError("Cannot OUTPUT a VOID value"); + return; + } + + Builder->CreateCall(PrintfFunc, Args); +} |
