diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-17 06:54:32 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-17 06:54:32 +0000 |
| commit | 74b6d06711afd3efbbc47436f1491900994313f3 (patch) | |
| tree | b9050214b147cd2b1b54fd27e75d669bf6146e48 /lib | |
| parent | 39661855c0816ac248be437704c76f58359cb5f0 (diff) | |
feat(classes): allocate objects with NEW and rebind named class variables
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/CodeGen/ArrayHandler.cc | 5 | ||||
| -rw-r--r-- | lib/CodeGen/CodeGen.cc | 2 | ||||
| -rw-r--r-- | lib/CodeGen/ConstructorGen.cc | 39 | ||||
| -rw-r--r-- | lib/CodeGen/Designator.cc | 7 | ||||
| -rw-r--r-- | lib/CodeGen/ExpressionGen.cc | 4 | ||||
| -rw-r--r-- | lib/CodeGen/FunctionGen.cc | 9 | ||||
| -rw-r--r-- | lib/CodeGen/StatementGen.cc | 9 | ||||
| -rw-r--r-- | lib/CodeGen/TypeSystem.cc | 3 | ||||
| -rw-r--r-- | lib/CodeGen/ValueTypeGen.cc | 11 | ||||
| -rw-r--r-- | lib/Parser/Parser.cc | 2 | ||||
| -rw-r--r-- | lib/Parser/ParserExpression.cc | 19 |
11 files changed, 88 insertions, 22 deletions
diff --git a/lib/CodeGen/ArrayHandler.cc b/lib/CodeGen/ArrayHandler.cc index 337e5f4..8da6cd3 100644 --- a/lib/CodeGen/ArrayHandler.cc +++ b/lib/CodeGen/ArrayHandler.cc @@ -241,10 +241,7 @@ void ArrayHandler::emitArrayAssign(ArrayAssignStmtAST *Stmt, CodeGen &CG) { Stmt->getLine(), CG, ElemTypeName); if (!ElemPtr) return; - Value *Val = CG.emitCoercedExpr(Stmt->getExpr(), Types.resolve(ElemTypeName)); - if (!Val) return; - - Builder->CreateStore(Val, ElemPtr); + CG.emitAssignment({ElemPtr, ElemTypeName}, Stmt->getExpr()); } Value *ArrayHandler::emitElementAddress(const std::string &Name, diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index 01393a9..68dec5c 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -266,7 +266,7 @@ bool CodeGen::marshalCallArgs(const std::string &Callee, TypeName.c_str(), Info->TypeName.c_str()); return false; } - Out.push_back(Info->Storage); + Out.push_back(symbolAddress(*Info)); } else { Value *V = emitCoercedExpr(ArgExpr, resolveType(TypeName)); if (!V) return false; diff --git a/lib/CodeGen/ConstructorGen.cc b/lib/CodeGen/ConstructorGen.cc index 0d4d732..f726590 100644 --- a/lib/CodeGen/ConstructorGen.cc +++ b/lib/CodeGen/ConstructorGen.cc @@ -1,4 +1,8 @@ #include "cps/CodeGen.h" +#include "cps/MemoryHandler.h" +#include "cps/TypeAST.h" +#include <climits> +#include <cstddef> using namespace llvm; using namespace cps; @@ -37,3 +41,38 @@ bool CodeGen::emitConstruct(const std::string &TypeName, Value *Addr, bool CodeGen::emitDefaultConstruct(const std::string &TypeName, Value *Addr, int Line) { return emitConstruct(TypeName, Addr, {}, Line); } + +Value *CodeGen::symbolAddress(const SymbolInfo &Info) { + if (!Info.IsReference) return Info.Storage; + return Builder->CreateLoad(PointerType::getUnqual(*TheContext), Info.Storage, "object_address"); +} + +void CodeGen::emitAssignment(const LValueInfo &Target, ExprAST *Expr, const SymbolInfo *Symbol) { + const TypeInfo *Info = resolveType(Target.TypeName); + if (auto *New = dynamic_cast<NewExprAST*>(Expr)) { + SaveAndRestore<int> Location(DiagnosticLine, New->getLine()); + const TypeInfo *Class = resolveType(New->getClassName()); + if (!Class || !Class->IsClass) { + reportError("NEW requires a class type: %s", New->getClassName().c_str()); + return; + } + if (!Info || !Info->sameType(Class)) { + reportError("NEW target must have type %s", Class->Name.c_str()); + return; + } + Value *Size = Builder->CreateIntCast(Types->getSizeOfConstant(Class->LLVMType), + Type::getIntNTy(*TheContext, sizeof(std::size_t) * CHAR_BIT), false); + Value *Object = Memory->emitAllocate(Size, New->getLine()); + Builder->CreateStore(Types->getZeroValue(Class->Name), Object); + if (!emitConstruct(Class->Name, Object, New->getArgs(), New->getLine())) return; + if (Symbol && Symbol->IsReference) { + Builder->CreateStore(Object, Symbol->Storage); + } else { + Value *Val = Builder->CreateLoad(Class->LLVMType, Object); + Builder->CreateStore(Val, Target.Addr); + } + return; + } + Value *Val = emitCoercedExpr(Expr, Info); + if (Val) Builder->CreateStore(Val, Target.Addr); +} diff --git a/lib/CodeGen/Designator.cc b/lib/CodeGen/Designator.cc index 1ebd158..5f54a87 100644 --- a/lib/CodeGen/Designator.cc +++ b/lib/CodeGen/Designator.cc @@ -24,7 +24,8 @@ void CodeGen::runTypePrePass(const std::vector<std::unique_ptr<StmtAST>> &Statem else if (auto *P = dynamic_cast<PointerTypeDeclAST*>(S.get())) Ok = Types->declareUserType(P->getName(), TypeKind::Pointer, Err); else if (auto *R = dynamic_cast<RecordTypeDeclAST*>(S.get())) - Ok = Types->declareUserType(R->getName(), TypeKind::Record, Err); + Ok = Types->declareUserType(R->getName(), TypeKind::Record, Err, + dynamic_cast<ClassTypeDeclAST*>(R) != nullptr); if (!Ok) reportError("%s", Err.c_str()); } @@ -120,7 +121,7 @@ bool CodeGen::emitLValue(ExprAST *E, LValueInfo &Out) { reportError("Whole array %s is not an assignable location; index it", Var->getName().c_str()); return false; } - Out.Addr = Info->Storage; + Out.Addr = symbolAddress(*Info); Out.TypeName = Info->TypeName; return true; } @@ -148,7 +149,7 @@ bool CodeGen::emitLValue(ExprAST *E, LValueInfo &Out) { if (!requireWritable(*Info, D->getBaseName())) return false; const auto &Accesses = D->getAccesses(); - Value *Addr = Info->Storage; + Value *Addr = symbolAddress(*Info); std::string TypeName = Info->TypeName; size_t Start = 0; diff --git a/lib/CodeGen/ExpressionGen.cc b/lib/CodeGen/ExpressionGen.cc index fde948c..ba5e329 100644 --- a/lib/CodeGen/ExpressionGen.cc +++ b/lib/CodeGen/ExpressionGen.cc @@ -51,7 +51,7 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { } if (Info->ConstantValue) return Info->ConstantValue; if (Info->IsArray) { - return Info->Storage; + return symbolAddress(*Info); } const TypeInfo *TypeInfo = resolveType(Info->TypeName); @@ -60,7 +60,7 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { return nullptr; } - Value *Loaded = Builder->CreateLoad(TypeInfo->LLVMType, Info->Storage, Var->getName().c_str()); + Value *Loaded = Builder->CreateLoad(TypeInfo->LLVMType, symbolAddress(*Info), Var->getName().c_str()); if (TypeInfo->isString()) { Loaded = emitStringNullGuard(Loaded); } diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc index d5bc5d4..e344410 100644 --- a/lib/CodeGen/FunctionGen.cc +++ b/lib/CodeGen/FunctionGen.cc @@ -90,7 +90,14 @@ void FunctionGen::createArgumentAllocas(Function *F, const std::vector<ParamDecl AllocaInst *Alloca = TmpB.CreateAlloca(ArgType, nullptr, P.Name); Builder.CreateStore(ArgVal, Alloca); - Symbols[P.Name] = {Alloca, P.TypeName, false}; + const TypeInfo *Info = Types.resolve(P.TypeName); + if (Info && Info->IsClass) { + AllocaInst *Slot = TmpB.CreateAlloca(PointerType::getUnqual(Context), nullptr, P.Name + ".ref"); + Builder.CreateStore(Alloca, Slot); + Symbols[P.Name] = {Slot, P.TypeName, false, nullptr, 0, true}; + } else { + Symbols[P.Name] = {Alloca, P.TypeName, false}; + } } } diff --git a/lib/CodeGen/StatementGen.cc b/lib/CodeGen/StatementGen.cc index 2443877..bd1f7c5 100644 --- a/lib/CodeGen/StatementGen.cc +++ b/lib/CodeGen/StatementGen.cc @@ -128,10 +128,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) { return; } - Value *Val = emitCoercedExpr(Assign->getExpr(), resolveType(Info->TypeName)); - if (!Val) return; - - Builder->CreateStore(Val, Info->Storage); + emitAssignment({symbolAddress(*Info), Info->TypeName}, Assign->getExpr(), Info); return; } @@ -296,9 +293,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) { if (auto *DA = dynamic_cast<DesignatorAssignStmtAST*>(Stmt)) { LValueInfo LV; if (!emitLValue(DA->getTarget(), LV)) return; - Value *Val = emitCoercedExpr(DA->getExpr(), resolveType(LV.TypeName)); - if (!Val) return; - Builder->CreateStore(Val, LV.Addr); + emitAssignment(LV, DA->getExpr()); return; } } diff --git a/lib/CodeGen/TypeSystem.cc b/lib/CodeGen/TypeSystem.cc index f4620dc..27814c2 100644 --- a/lib/CodeGen/TypeSystem.cc +++ b/lib/CodeGen/TypeSystem.cc @@ -129,7 +129,7 @@ const TypeInfo *TypeSystem::registerType(const std::string &TypeName, return &Result.first->second; } -bool TypeSystem::declareUserType(const std::string &Name, TypeKind Kind, std::string &Err) { +bool TypeSystem::declareUserType(const std::string &Name, TypeKind Kind, std::string &Err, bool IsClass) { if (Types.count(Name)) { Err = "Type " + Name + " is already defined"; return false; @@ -157,6 +157,7 @@ bool TypeSystem::declareUserType(const std::string &Name, TypeKind Kind, std::st } registerType(Name, LLVMType, Kind); + Types.find(Name)->second.IsClass = IsClass; return true; } diff --git a/lib/CodeGen/ValueTypeGen.cc b/lib/CodeGen/ValueTypeGen.cc index baa384c..fbe6dd5 100644 --- a/lib/CodeGen/ValueTypeGen.cc +++ b/lib/CodeGen/ValueTypeGen.cc @@ -279,8 +279,15 @@ void CodeGen::emitDeclareStmt(DeclareStmtAST *Stmt) { Builder->CreateStore(InitVal, Alloca); } - registerSymbol(Stmt->getName(), Alloca, Info->Name, false); - if (Stmt->hasParens() && !ClassMethods.count(Info->Name)) { + Value *Storage = Alloca; + if (Info->IsClass) { + Storage = CreateEntryBlockAlloca(TheFunction, PointerType::getUnqual(*TheContext), + Stmt->getName() + ".ref"); + Builder->CreateStore(Alloca, Storage); + } + registerSymbol(Stmt->getName(), Storage, Info->Name, false); + Symbols.find(Stmt->getName())->second.IsReference = Info->IsClass; + if (Stmt->hasParens() && !Info->IsClass) { reportError("Constructor arguments require a class type"); return; } diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc index 26eeac6..d3b2daa 100644 --- a/lib/Parser/Parser.cc +++ b/lib/Parser/Parser.cc @@ -242,7 +242,7 @@ std::unique_ptr<StmtAST> Parser::ParseAssignStmt() { return nullptr; } getNextToken(); - auto Expr = ParseExpression(); + auto Expr = ParseAssignmentRHS(); if (!Expr) return nullptr; if (Accesses.empty()) diff --git a/lib/Parser/ParserExpression.cc b/lib/Parser/ParserExpression.cc index f4e074e..96132aa 100644 --- a/lib/Parser/ParserExpression.cc +++ b/lib/Parser/ParserExpression.cc @@ -168,6 +168,9 @@ std::unique_ptr<ExprAST> Parser::ParsePrimary() { std::unique_ptr<ExprAST> Parser::ParsePrimaryImpl() { switch (CurTok) { + case tok_new: + fprintf(stderr, "error: NEW is only allowed on the right of an assignment at line %d\n", Lex.getLine()); + return nullptr; case tok_identifier: return ParseIdentifierExpr(); case tok_number_int: return ParseNumberExpr(); case tok_number_real: return ParseNumberExpr(); @@ -299,3 +302,19 @@ std::optional<std::vector<std::unique_ptr<ExprAST>>> Parser::ParseExprList(char getNextToken(); return Elems; } + +std::unique_ptr<ExprAST> Parser::ParseAssignmentRHS() { + if (CurTok != tok_new) return ParseExpression(); + int Line = Lex.getLine(); + getNextToken(); + std::string ClassName = ParseTypeName(false); + if (ClassName.empty()) return nullptr; + std::vector<std::unique_ptr<ExprAST>> Args; + if (CurTok == '(') { + getNextToken(); + auto Parsed = ParseExprList(')', true); + if (!Parsed) return nullptr; + Args = std::move(*Parsed); + } + return std::make_unique<NewExprAST>(ClassName, std::move(Args), Line); +} |
