diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-17 06:52:23 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-17 06:52:23 +0000 |
| commit | 39661855c0816ac248be437704c76f58359cb5f0 (patch) | |
| tree | 202b014805e40208e3adb861f4a97d31770f13e6 /lib/CodeGen | |
| parent | c89477d615fb0ce4d89786ef848ffe6aca1da088 (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.cc | 18 | ||||
| -rw-r--r-- | lib/CodeGen/ConstructorGen.cc | 39 | ||||
| -rw-r--r-- | lib/CodeGen/Designator.cc | 21 | ||||
| -rw-r--r-- | lib/CodeGen/ValueTypeGen.cc | 5 |
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()); } |
