aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-17 06:52:23 +0000
committer_ov4 <ov4@ov4.org>2026-10-17 06:52:23 +0000
commit39661855c0816ac248be437704c76f58359cb5f0 (patch)
tree202b014805e40208e3adb861f4a97d31770f13e6 /lib/CodeGen
parentc89477d615fb0ce4d89786ef848ffe6aca1da088 (diff)
feat(classes): construct declared objects and nested fields and arrays
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/ArrayHandler.cc18
-rw-r--r--lib/CodeGen/ConstructorGen.cc39
-rw-r--r--lib/CodeGen/Designator.cc21
-rw-r--r--lib/CodeGen/ValueTypeGen.cc5
4 files changed, 76 insertions, 7 deletions
diff --git a/lib/CodeGen/ArrayHandler.cc b/lib/CodeGen/ArrayHandler.cc
index 5eb8a52..337e5f4 100644
--- a/lib/CodeGen/ArrayHandler.cc
+++ b/lib/CodeGen/ArrayHandler.cc
@@ -139,6 +139,24 @@ void ArrayHandler::emitArrayDeclare(ArrayDeclareStmtAST *Stmt, CodeGen &CG) {
Builder->CreateStore(Ptr, Alloca);
CG.registerSymbol(Name, Alloca, ElemInfo->Name, true);
+ if (CG.typeNeedsConstruction(ElemInfo->Name)) {
+ BasicBlock *Preheader = Builder->GetInsertBlock();
+ BasicBlock *Loop = BasicBlock::Create(*TheContext, "construct_elements", TheFunction);
+ BasicBlock *Body = BasicBlock::Create(*TheContext, "construct_element", TheFunction);
+ BasicBlock *Done = BasicBlock::Create(*TheContext, "constructed_array", TheFunction);
+ Builder->CreateBr(Loop);
+ Builder->SetInsertPoint(Loop);
+ auto *Index = Builder->CreatePHI(Type::getInt64Ty(*TheContext), 2, "construct_index");
+ Index->addIncoming(ConstantInt::get(Type::getInt64Ty(*TheContext), 0), Preheader);
+ Builder->CreateCondBr(Builder->CreateICmpULT(Index, TotalElements), Body, Done);
+ Builder->SetInsertPoint(Body);
+ Value *Element = Builder->CreateGEP(ElemInfo->LLVMType, Ptr, Index);
+ CG.emitDefaultConstruct(ElemInfo->Name, Element, Stmt->getLine());
+ Value *Next = Builder->CreateAdd(Index, ConstantInt::get(Type::getInt64Ty(*TheContext), 1));
+ Index->addIncoming(Next, Builder->GetInsertBlock());
+ Builder->CreateBr(Loop);
+ Builder->SetInsertPoint(Done);
+ }
}
void ArrayHandler::computeDimsAndMultipliers(const std::string &Name,
diff --git a/lib/CodeGen/ConstructorGen.cc b/lib/CodeGen/ConstructorGen.cc
new file mode 100644
index 0000000..0d4d732
--- /dev/null
+++ b/lib/CodeGen/ConstructorGen.cc
@@ -0,0 +1,39 @@
+#include "cps/CodeGen.h"
+
+using namespace llvm;
+using namespace cps;
+
+bool CodeGen::typeNeedsConstruction(const std::string &TypeName) const {
+ if (findMethod(TypeName, "NEW")) return true;
+ const TypeInfo *Info = resolveType(TypeName);
+ if (Info && Info->asRecord()) {
+ for (const auto &[Name, Field] : Info->Record.Fields)
+ if (typeNeedsConstruction(Field.TypeName)) return true;
+ }
+ return false;
+}
+
+bool CodeGen::emitConstruct(const std::string &TypeName, Value *Addr,
+ const std::vector<std::unique_ptr<ExprAST>> &Args, int Line) {
+ SaveAndRestore<int> Location(DiagnosticLine, Line);
+ const TypeInfo *Info = resolveType(TypeName);
+ if (!Info) return false;
+ if (Info->asRecord()) {
+ for (const auto &[Name, Field] : Info->Record.Fields) {
+ if (!typeNeedsConstruction(Field.TypeName)) continue;
+ Value *FieldAddr = Builder->CreateStructGEP(Info->LLVMType, Addr, Field.Index);
+ if (!emitDefaultConstruct(Field.TypeName, FieldAddr, Line)) return false;
+ }
+ }
+ if (findMethod(TypeName, "NEW"))
+ return emitMethodCall(TypeName, Addr, "NEW", Args, Line) != nullptr;
+ if (!Args.empty()) {
+ reportError("Type %s has no constructor NEW but arguments were supplied", TypeName.c_str());
+ return false;
+ }
+ return true;
+}
+
+bool CodeGen::emitDefaultConstruct(const std::string &TypeName, Value *Addr, int Line) {
+ return emitConstruct(TypeName, Addr, {}, Line);
+}
diff --git a/lib/CodeGen/Designator.cc b/lib/CodeGen/Designator.cc
index 13eb25f..1ebd158 100644
--- a/lib/CodeGen/Designator.cc
+++ b/lib/CodeGen/Designator.cc
@@ -78,18 +78,25 @@ Value *CodeGen::emitMemberCall(MemberCallExprAST *Call) {
SaveAndRestore<int> Location(DiagnosticLine, Call->getLine());
LValueInfo Receiver;
if (!emitLValue(Call->getReceiver(), Receiver)) return nullptr;
- const PrototypeAST *Method = findMethod(Receiver.TypeName, Call->getMethod());
+ return emitMethodCall(Receiver.TypeName, Receiver.Addr, Call->getMethod(),
+ Call->getArgs(), Call->getLine());
+}
+
+Value *CodeGen::emitMethodCall(const std::string &Class, Value *Receiver,
+ const std::string &Name,
+ const std::vector<std::unique_ptr<ExprAST>> &ArgExprs, int Line) {
+ SaveAndRestore<int> Location(DiagnosticLine, Line);
+ const PrototypeAST *Method = findMethod(Class, Name);
if (!Method) {
- reportError("Type %s has no method %s", Receiver.TypeName.c_str(), Call->getMethod().c_str());
+ reportError("Type %s has no method %s", Class.c_str(), Name.c_str());
return nullptr;
}
- if (!Method->isPublic() && !sameIdentifier(CurrentClass, Receiver.TypeName)) {
- reportError("Cannot access private method %s of type %s",
- Call->getMethod().c_str(), Receiver.TypeName.c_str());
+ if (!Method->isPublic() && !sameIdentifier(CurrentClass, Class)) {
+ reportError("Cannot access private method %s of type %s", Name.c_str(), Class.c_str());
return nullptr;
}
- std::vector<Value*> Args = {Receiver.Addr};
- if (!marshalCallArgs(Method->getLinkName(), Call->getArgs(), Call->getLine(), Args)) return nullptr;
+ std::vector<Value*> Args = {Receiver};
+ if (!marshalCallArgs(Method->getLinkName(), ArgExprs, Line, Args)) return nullptr;
return FuncGen->emitCall(Method->getLinkName(), Args);
}
diff --git a/lib/CodeGen/ValueTypeGen.cc b/lib/CodeGen/ValueTypeGen.cc
index 16c3e0b..baa384c 100644
--- a/lib/CodeGen/ValueTypeGen.cc
+++ b/lib/CodeGen/ValueTypeGen.cc
@@ -280,4 +280,9 @@ void CodeGen::emitDeclareStmt(DeclareStmtAST *Stmt) {
}
registerSymbol(Stmt->getName(), Alloca, Info->Name, false);
+ if (Stmt->hasParens() && !ClassMethods.count(Info->Name)) {
+ reportError("Constructor arguments require a class type");
+ return;
+ }
+ emitConstruct(Info->Name, Alloca, Stmt->getArgs(), Stmt->getLine());
}