aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/StringValueGen.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/StringValueGen.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/StringValueGen.cc')
-rw-r--r--lib/CodeGen/StringValueGen.cc75
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;
+}