aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/Designator.cc
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-17 06:02:21 +0000
committer_ov4 <ov4@ov4.org>2026-10-17 06:02:21 +0000
commit3425b95cb654f8e1adc98365a4b370aa1fff8b4d (patch)
tree4d81b91d0bd807cd6f7ced037533d6e60f5c307f /lib/CodeGen/Designator.cc
parent4e22f464387725a5a282f3d72e11cfb694a31a5a (diff)
feat(classes): support ordinary member methods and this references
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/Designator.cc')
-rw-r--r--lib/CodeGen/Designator.cc55
1 files changed, 54 insertions, 1 deletions
diff --git a/lib/CodeGen/Designator.cc b/lib/CodeGen/Designator.cc
index fcc6919..adf08f1 100644
--- a/lib/CodeGen/Designator.cc
+++ b/lib/CodeGen/Designator.cc
@@ -40,6 +40,59 @@ void CodeGen::runTypePrePass(const std::vector<std::unique_ptr<StmtAST>> &Statem
}
if (!Ok) reportError("%s", Err.c_str());
}
+
+ for (const auto &S : Statements) {
+ auto *Class = dynamic_cast<ClassTypeDeclAST*>(S.get());
+ if (!Class) continue;
+ auto &Methods = ClassMethods[Class->getName()];
+ IdentifierSet Names;
+ for (const auto &Field : Class->getFields()) {
+ Names.insert(Field.Name);
+ if (sameIdentifier(Field.Name, "this")) {
+ SaveAndRestore<int> Location(DiagnosticLine, Class->getLine());
+ reportError("A class field cannot be named this");
+ }
+ }
+ for (const auto &Method : Class->getMethods()) {
+ SaveAndRestore<int> Location(DiagnosticLine, Method->getLine());
+ const std::string &Name = Method->getProto()->getName();
+ if (sameIdentifier(Name, "NEW")) {
+ reportError("NEW constructors are not implemented");
+ } else if (sameIdentifier(Name, "this")) {
+ reportError("A method cannot be named this");
+ } else if (!Names.insert(Name).second) {
+ reportError("Duplicate member %s in class %s", Name.c_str(), Class->getName().c_str());
+ } else {
+ Methods.emplace(Name, Method.get());
+ }
+ }
+ }
+}
+
+const PrototypeAST *CodeGen::findMethod(const std::string &Class, const std::string &Name) const {
+ auto C = ClassMethods.find(Class);
+ if (C == ClassMethods.end()) return nullptr;
+ auto M = C->second.find(Name);
+ return M == C->second.end() ? nullptr : M->second->getProto();
+}
+
+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());
+ if (!Method) {
+ reportError("Type %s has no method %s", Receiver.TypeName.c_str(), Call->getMethod().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());
+ return nullptr;
+ }
+ std::vector<Value*> Args = {Receiver.Addr};
+ if (!marshalCallArgs(Method->getLinkName(), Call->getArgs(), Call->getLine(), Args)) return nullptr;
+ return FuncGen->emitCall(Method->getLinkName(), Args);
}
// Resolves a designator (or legacy variable/array-access node) to the address
@@ -126,7 +179,7 @@ bool CodeGen::emitLValue(ExprAST *E, LValueInfo &Out) {
reportError("Record type %s has no field %s", TypeName.c_str(), A.FieldName.c_str());
return false;
}
- if (!FI->IsPublic) {
+ if (!FI->IsPublic && !sameIdentifier(CurrentClass, TypeName)) {
reportError("Cannot access private field %s of type %s",
A.FieldName.c_str(), TypeName.c_str());
return false;