diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-20 11:57:16 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-20 11:57:16 +0000 |
| commit | 62b605c6c0ea13e9763c0a0115464007b13a8831 (patch) | |
| tree | 53c27965f5a365682e0d79fd96e25b228ecb9dca /lib/CodeGen/StringValueGen.cc | |
| parent | bfe2e75d7e3b372e55369677028429990c49bc54 (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/StringValueGen.cc')
| -rw-r--r-- | lib/CodeGen/StringValueGen.cc | 75 |
1 files changed, 75 insertions, 0 deletions
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; +} |
