From 3425b95cb654f8e1adc98365a4b370aa1fff8b4d Mon Sep 17 00:00:00 2001 From: _ov4 Date: Sat, 17 Oct 2026 06:02:21 +0000 Subject: feat(classes): support ordinary member methods and this references Co-Authored-By: Claude Fable 5.1 --- lib/CodeGen/Designator.cc | 55 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) (limited to 'lib/CodeGen/Designator.cc') 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> &Statem } if (!Ok) reportError("%s", Err.c_str()); } + + for (const auto &S : Statements) { + auto *Class = dynamic_cast(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 Location(DiagnosticLine, Class->getLine()); + reportError("A class field cannot be named this"); + } + } + for (const auto &Method : Class->getMethods()) { + SaveAndRestore 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 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 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; -- cgit v1.3.1-4-g156e