From 62b605c6c0ea13e9763c0a0115464007b13a8831 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Tue, 20 Oct 2026 11:57:16 +0000 Subject: 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 --- lib/CodeGen/StringValueGen.cc | 75 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 lib/CodeGen/StringValueGen.cc (limited to 'lib/CodeGen/StringValueGen.cc') diff --git a/lib/CodeGen/StringValueGen.cc b/lib/CodeGen/StringValueGen.cc new file mode 100644 index 0000000..ce9694c --- /dev/null +++ b/lib/CodeGen/StringValueGen.cc @@ -0,0 +1,75 @@ +#include "cps/CodeGen.h" +#include "cps/Operator.h" + +using namespace cps; +using namespace llvm; + +const TypeInfo *CodeGen::requireStringType() { + const TypeInfo *Type = resolveType("STRING"); + if (!Type || !Type->IsClass) { + reportError("String literals require a visible STRING class; include the string library or omit -no-std"); + return nullptr; + } + return Type; +} + +Value *CodeGen::emitStringFromCString(Value *Text) { + const TypeInfo *Type = requireStringType(); + if (!Type || !Text) return nullptr; + const FuncSig *Constructor = nullptr; + for (const FuncSig *Sig : FuncGen->getOverloads(Type->Name + ".NEW")) + if (Sig->Params.size() == 1 && !Sig->Params[0].IsArray && !Sig->Params[0].IsByRef && + resolveType("C_STRING")->sameType(resolveType(Sig->Params[0].TypeName))) + Constructor = Sig; + if (!Constructor) { + reportError("STRING requires a constructor NEW(Text : C_STRING)"); + return nullptr; + } + if (!checkOperatorAccess(*Constructor)) return nullptr; + auto *Storage = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), + Type->LLVMType, "string_value"); + Builder->CreateStore(Types->getZeroValue(Type->Name), Storage); + for (const auto &[Name, Field] : Type->Record.Fields) + if (typeNeedsConstruction(Field.TypeName) && + !emitDefaultConstruct(Field.TypeName, + Builder->CreateStructGEP(Type->LLVMType, Storage, Field.Index), DiagnosticLine)) + return nullptr; + if (!FuncGen->emitCall(*Constructor, {Storage, Text})) return nullptr; + // The consumer takes ownership, just as with an ordinary class result. + return Builder->CreateLoad(Type->LLVMType, Storage, "string"); +} + +Value *CodeGen::emitStringCString(Value *Value) { + const TypeInfo *Type = requireStringType(); + if (!Type || !Value) return nullptr; + const FuncSig *Method = resolveMethod(Type->Name, "C_STR", {}); + if (!Method || !resolveType("C_STRING")->sameType(resolveType(Method->ReturnTypeName))) { + reportError("STRING requires a method C_STR() RETURNS C_STRING"); + return nullptr; + } + auto *Receiver = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), + Type->LLVMType, "string_view"); + Builder->CreateStore(Value, Receiver); + return emitMethodCall(Type->Name, Receiver, "C_STR", {}, DiagnosticLine); +} + +Value *CodeGen::emitCStringExpr(ExprAST *Expr) { + const TypeInfo *Type = getExprTypeInfo(Expr); + if (!Type || !Type->isString() || isWholeArrayVar(Expr)) { + reportError("Expected a STRING value"); + return nullptr; + } + Value *Value = emitExpr(Expr); + if (!Value) return nullptr; + if (!isObjectLValue(Expr)) materializeOperatorReceiver(Value, Type); + return emitStringCString(Value); +} + +bool CodeGen::containsString(const TypeInfo *Type) const { + if (!Type) return false; + if (Type->isString()) return true; + if (Type->asRecord()) + for (const auto &[Name, Field] : Type->Record.Fields) + if (containsString(resolveType(Field.TypeName))) return true; + return false; +} -- cgit v1.3.1-4-g156e