aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/StringHandler.cc
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-20 11:57:16 +0000
committer_ov4 <ov4@ov4.org>2026-10-20 11:57:16 +0000
commit62b605c6c0ea13e9763c0a0115464007b13a8831 (patch)
tree53c27965f5a365682e0d79fd96e25b228ecb9dca /lib/CodeGen/StringHandler.cc
parentbfe2e75d7e3b372e55369677028429990c49bc54 (diff)
refactor(strings): replace compiler builtins with the STRING library
Construct literals as STRING values and route string operations through ordinary library functions and operators. Preserve value ownership in records, arrays, constants and file I/O. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/StringHandler.cc')
-rw-r--r--lib/CodeGen/StringHandler.cc206
1 files changed, 0 insertions, 206 deletions
diff --git a/lib/CodeGen/StringHandler.cc b/lib/CodeGen/StringHandler.cc
deleted file mode 100644
index f91539c..0000000
--- a/lib/CodeGen/StringHandler.cc
+++ /dev/null
@@ -1,206 +0,0 @@
-#include "cps/StringHandler.h"
-#include "cps/Lexer.h"
-#include "llvm/IR/Type.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/Constants.h"
-
-using namespace llvm;
-using namespace cps;
-
-StringHandler::StringHandler(LLVMContext &Ctx, IRBuilder<> &B, llvm::Module &M)
- : Context(Ctx), Builder(B), Module(M) {
- setupExternalFunctions();
-}
-
-void StringHandler::setupExternalFunctions() {
- FunctionType *MallocType = FunctionType::get(PointerType::getUnqual(Context), {Type::getInt64Ty(Context)}, false);
- MallocFunc = Module.getOrInsertFunction("malloc", MallocType);
-
- FunctionType *StrLenType = FunctionType::get(Type::getInt64Ty(Context), {PointerType::getUnqual(Context)}, false);
- StrLenFunc = Module.getOrInsertFunction("strlen", StrLenType);
-
- std::vector<Type*> MemCpyArgs = {PointerType::getUnqual(Context), PointerType::getUnqual(Context), Type::getInt64Ty(Context)};
- FunctionType *MemCpyType = FunctionType::get(PointerType::getUnqual(Context), MemCpyArgs, false);
- MemCpyFunc = Module.getOrInsertFunction("memcpy", MemCpyType);
-
- FunctionType *StrCpyType = FunctionType::get(PointerType::getUnqual(Context),
- {PointerType::getUnqual(Context), PointerType::getUnqual(Context)},
- false);
- StrCpyFunc = Module.getOrInsertFunction("strcpy", StrCpyType);
- StrCatFunc = Module.getOrInsertFunction("strcat", StrCpyType);
- StrCmpFunc = Module.getOrInsertFunction("strcmp",
- FunctionType::get(Type::getInt32Ty(Context),
- {PointerType::getUnqual(Context), PointerType::getUnqual(Context)}, false));
-
- FunctionType *CharCaseType = FunctionType::get(Type::getInt32Ty(Context), {Type::getInt32Ty(Context)}, false);
- ToUpperFunc = Module.getOrInsertFunction("toupper", CharCaseType);
- ToLowerFunc = Module.getOrInsertFunction("tolower", CharCaseType);
-}
-
-Value *StringHandler::createLiteral(const std::string &Val) {
- return Builder.CreateGlobalString(Val);
-}
-
-Value *StringHandler::emitLength(Value *Str) {
- if (!Str) return nullptr;
- return Builder.CreateCall(StrLenFunc, Str, "len");
-}
-
-Value *StringHandler::emitConcat(Value *LHS, Value *RHS) {
- if (!LHS || !RHS) return nullptr;
-
- Value *LLen = Builder.CreateCall(StrLenFunc, {LHS}, "llen");
- Value *RLen = Builder.CreateCall(StrLenFunc, {RHS}, "rlen");
- Value *TotalLen = Builder.CreateAdd(LLen, RLen, "totallen");
- Value *AllocSize = Builder.CreateAdd(TotalLen, ConstantInt::get(Type::getInt64Ty(Context), 1), "allocsize");
-
- Value *NewStr = Builder.CreateCall(MallocFunc, {AllocSize}, "concat_str");
-
- Builder.CreateCall(StrCpyFunc, {NewStr, LHS});
- Builder.CreateCall(StrCatFunc, {NewStr, RHS});
-
- return NewStr;
-}
-
-Value *StringHandler::emitCompare(int Op, Value *LHS, Value *RHS) {
- if (!LHS || !RHS) return nullptr;
-
- CmpInst::Predicate Pred;
- switch (Op) {
- case tok_eq: Pred = CmpInst::ICMP_EQ; break;
- case tok_ne: Pred = CmpInst::ICMP_NE; break;
- case '<': Pred = CmpInst::ICMP_SLT; break;
- case '>': Pred = CmpInst::ICMP_SGT; break;
- case tok_le: Pred = CmpInst::ICMP_SLE; break;
- case tok_ge: Pred = CmpInst::ICMP_SGE; break;
- default: return nullptr;
- }
-
- Value *Cmp = Builder.CreateCall(StrCmpFunc, {LHS, RHS}, "strcmp_result");
- return Builder.CreateICmp(Pred, Cmp, ConstantInt::get(Type::getInt32Ty(Context), 0), "str_compare");
-}
-
-// malloc(Len + 1), copy Len bytes from Src + StartIdx, NUL-terminate.
-// Clamping is each caller's business — MID/RIGHT/LEFT clamp different things.
-Value *StringHandler::allocCopySubstring(Value *Src, Value *StartIdx, Value *Len) {
- Value *One = ConstantInt::get(Context, APInt(64, 1));
- Value *AllocSize = Builder.CreateAdd(Len, One);
- Value *NewStr = Builder.CreateCall(MallocFunc, AllocSize, "substr_mem");
-
- Value *SrcPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), Src, StartIdx);
- Builder.CreateCall(MemCpyFunc, {NewStr, SrcPtr, Len});
-
- Value *NullTermPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), NewStr, Len);
- Builder.CreateStore(ConstantInt::get(Type::getInt8Ty(Context), 0), NullTermPtr);
-
- return NewStr;
-}
-
-Value *StringHandler::emitMid(Value *Str, Value *Start, Value *Len) {
- Value *FullLen = emitLength(Str);
-
- Value *One = ConstantInt::get(Context, APInt(64, 1));
- Value *Zero = ConstantInt::get(Context, APInt(64, 0));
- Value *StartZeroBased = Builder.CreateSub(Start, One, "start_idx");
-
- Value *IsNeg = Builder.CreateICmpSLT(StartZeroBased, Zero);
- StartZeroBased = Builder.CreateSelect(IsNeg, Zero, StartZeroBased);
-
- Value *IsTooBig = Builder.CreateICmpSGT(StartZeroBased, FullLen);
- StartZeroBased = Builder.CreateSelect(IsTooBig, FullLen, StartZeroBased);
-
- Value *RemLen = Builder.CreateSub(FullLen, StartZeroBased);
-
- Value *IsLenTooBig = Builder.CreateICmpSGT(Len, RemLen);
- Value *ActualLen = Builder.CreateSelect(IsLenTooBig, RemLen, Len);
-
- Value *IsLenNeg = Builder.CreateICmpSLT(ActualLen, Zero);
- ActualLen = Builder.CreateSelect(IsLenNeg, Zero, ActualLen);
-
- return allocCopySubstring(Str, StartZeroBased, ActualLen);
-}
-
-Value *StringHandler::emitRight(Value *Str, Value *Len) {
- Value *FullLen = emitLength(Str);
-
- Value *StartIdx = Builder.CreateSub(FullLen, Len, "right_start");
-
- Value *Zero = ConstantInt::get(Context, APInt(64, 0));
- Value *IsNeg = Builder.CreateICmpSLT(StartIdx, Zero);
- StartIdx = Builder.CreateSelect(IsNeg, Zero, StartIdx);
-
- Value *ActualLen = Builder.CreateSub(FullLen, StartIdx);
-
- return allocCopySubstring(Str, StartIdx, ActualLen);
-}
-
-Value *StringHandler::emitLeft(Value *Str, Value *Len) {
- Value *FullLen = emitLength(Str);
-
- Value *Zero = ConstantInt::get(Context, APInt(64, 0));
- Value *IsNeg = Builder.CreateICmpSLT(Len, Zero);
- Value *SafeLen = Builder.CreateSelect(IsNeg, Zero, Len);
-
- Value *IsTooBig = Builder.CreateICmpSGT(SafeLen, FullLen);
- Value *ActualLen = Builder.CreateSelect(IsTooBig, FullLen, SafeLen);
-
- return allocCopySubstring(Str, Zero, ActualLen);
-}
-
-// Shared loop for LCASE/UCASE: malloc a copy of Str with every byte run
-// through CaseFn (tolower/toupper).
-Value *StringHandler::emitCaseConvert(Value *Str, FunctionCallee CaseFn) {
- if (!Str) return nullptr;
- Value *Len = emitLength(Str);
- Value *One = ConstantInt::get(Context, APInt(64, 1));
- Value *AllocSize = Builder.CreateAdd(Len, One);
- Value *NewStr = Builder.CreateCall(MallocFunc, AllocSize, "case_str");
-
- Function *TheFunction = Builder.GetInsertBlock()->getParent();
- BasicBlock *LoopBB = BasicBlock::Create(Context, "loop", TheFunction);
- BasicBlock *AfterBB = BasicBlock::Create(Context, "afterloop", TheFunction);
-
- IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin());
- AllocaInst *IdxVar = TmpB.CreateAlloca(Type::getInt64Ty(Context), nullptr, "idx");
- Builder.CreateStore(ConstantInt::get(Context, APInt(64, 0)), IdxVar);
-
- Builder.CreateBr(LoopBB);
- Builder.SetInsertPoint(LoopBB);
-
- Value *CurIdx = Builder.CreateLoad(Type::getInt64Ty(Context), IdxVar);
- Value *Cond = Builder.CreateICmpSLT(CurIdx, Len);
-
- BasicBlock *BodyBB = BasicBlock::Create(Context, "body", TheFunction);
- Builder.CreateCondBr(Cond, BodyBB, AfterBB);
-
- Builder.SetInsertPoint(BodyBB);
-
- Value *SrcPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), Str, CurIdx);
- Value *CharVal = Builder.CreateLoad(Type::getInt8Ty(Context), SrcPtr);
-
- Value *ExtChar = Builder.CreateSExt(CharVal, Type::getInt32Ty(Context));
- Value *ConvChar = Builder.CreateCall(CaseFn, ExtChar);
- Value *TruncChar = Builder.CreateTrunc(ConvChar, Type::getInt8Ty(Context));
-
- Value *DestPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), NewStr, CurIdx);
- Builder.CreateStore(TruncChar, DestPtr);
-
- Value *NextIdx = Builder.CreateAdd(CurIdx, One);
- Builder.CreateStore(NextIdx, IdxVar);
- Builder.CreateBr(LoopBB);
-
- Builder.SetInsertPoint(AfterBB);
-
- Value *NullPtr = Builder.CreateInBoundsGEP(Type::getInt8Ty(Context), NewStr, Len);
- Builder.CreateStore(ConstantInt::get(Type::getInt8Ty(Context), 0), NullPtr);
-
- return NewStr;
-}
-
-Value *StringHandler::emitLCase(Value *Str) {
- return emitCaseConvert(Str, ToLowerFunc);
-}
-
-Value *StringHandler::emitUCase(Value *Str) {
- return emitCaseConvert(Str, ToUpperFunc);
-}