aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-17 08:32:43 +0000
committer_ov4 <ov4@ov4.org>2026-10-17 08:32:43 +0000
commit59e3c50bcd58130e81e1f57b21d6e57b4d4aba6d (patch)
treec5f6c5b1bd367feadca0c2e7d0f47c8dedb91b20 /lib/CodeGen
parente847e4c53cf21fcb96f7ed7765e305a7ec8e6c19 (diff)
feat(classes): destroy and release heap objects with DELETE
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/ConstructorGen.cc27
-rw-r--r--lib/CodeGen/MemoryHandler.cc5
-rw-r--r--lib/CodeGen/StatementGen.cc14
3 files changed, 46 insertions, 0 deletions
diff --git a/lib/CodeGen/ConstructorGen.cc b/lib/CodeGen/ConstructorGen.cc
index 99f21df..9e6b0b3 100644
--- a/lib/CodeGen/ConstructorGen.cc
+++ b/lib/CodeGen/ConstructorGen.cc
@@ -80,3 +80,30 @@ void CodeGen::emitAssignment(const LValueInfo &Target, ExprAST *Expr, const Symb
Value *Val = emitCoercedExpr(Expr, Info);
if (Val) Builder->CreateStore(Val, Target.Addr);
}
+
+bool CodeGen::typeNeedsDestruction(const std::string &TypeName) const {
+ if (findMethod(TypeName, "DELETE")) return true;
+ const TypeInfo *Info = resolveType(TypeName);
+ if (Info && Info->asRecord()) {
+ for (const auto &[Name, Field] : Info->Record.Fields)
+ if (typeNeedsDestruction(Field.TypeName)) return true;
+ }
+ return false;
+}
+
+bool CodeGen::emitDestroy(const std::string &TypeName, Value *Addr, int Line) {
+ SaveAndRestore<int> Location(DiagnosticLine, Line);
+ const TypeInfo *Info = resolveType(TypeName);
+ if (!Info) return false;
+ if (findMethod(TypeName, "DELETE") &&
+ !emitMethodCall(TypeName, Addr, "DELETE", {}, Line)) return false;
+ if (Info->asRecord()) {
+ for (auto It = Info->Record.Fields.rbegin(); It != Info->Record.Fields.rend(); ++It) {
+ const auto &Field = It->second;
+ if (!typeNeedsDestruction(Field.TypeName)) continue;
+ Value *FieldAddr = Builder->CreateStructGEP(Info->LLVMType, Addr, Field.Index);
+ if (!emitDestroy(Field.TypeName, FieldAddr, Line)) return false;
+ }
+ }
+ return true;
+}
diff --git a/lib/CodeGen/MemoryHandler.cc b/lib/CodeGen/MemoryHandler.cc
index 07fe6f6..fa25eb9 100644
--- a/lib/CodeGen/MemoryHandler.cc
+++ b/lib/CodeGen/MemoryHandler.cc
@@ -152,3 +152,8 @@ Value *MemoryHandler::emitResize(Value *Address, Value *Size, int Line) {
ensureRuntime();
return Exceptions.emitCall(ResizeFn, {Address, Size, Builder.getInt32(Line)}, "resized");
}
+
+void MemoryHandler::emitValidate(Value *Address, int Line) {
+ ensureRuntime();
+ Exceptions.emitCall(FindFn, {Address, Builder.getInt32(Line)});
+}
diff --git a/lib/CodeGen/StatementGen.cc b/lib/CodeGen/StatementGen.cc
index bd1f7c5..a7c8eda 100644
--- a/lib/CodeGen/StatementGen.cc
+++ b/lib/CodeGen/StatementGen.cc
@@ -2,6 +2,7 @@
#include "cps/ArrayHandler.h"
#include "cps/FileAST.h"
#include "cps/FileHandler.h"
+#include "cps/MemoryHandler.h"
#include "cps/ExceptionHandler.h"
#include "cps/TypeAST.h"
@@ -49,6 +50,19 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
Builder->SetInsertPoint(BasicBlock::Create(*TheContext, "unreachable_code", F));
}
+ if (auto *Delete = dynamic_cast<DeleteStmtAST*>(Stmt)) {
+ LValueInfo Object;
+ if (!emitLValue(Delete->getTarget(), Object)) return;
+ const TypeInfo *Info = resolveType(Object.TypeName);
+ if (!Info || !Info->IsClass) {
+ reportError("DELETE requires a class object");
+ return;
+ }
+ Memory->emitValidate(Object.Addr, Stmt->getLine());
+ if (emitDestroy(Object.TypeName, Object.Addr, Stmt->getLine()))
+ Memory->emitRelease(Object.Addr, Stmt->getLine());
+ return;
+ }
if (auto *Try = dynamic_cast<TryStmtAST*>(Stmt)) {
emitTryStmt(Try);
return;