diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-18 06:09:01 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-18 06:09:01 +0000 |
| commit | b17f101cfc75565f9991c856ec62f1e17b0ab104 (patch) | |
| tree | 6c925f06c45dbaa557a0451cfca33f17be71ec67 /lib/CodeGen/OperatorGen.cc | |
| parent | 16231050058131860f710073c17d3bca7c6637eb (diff) | |
feat(operators): add member and unary overloads with explicit calls
Select member and global candidates together, enforce private access, and
reuse argument marshalling. Materialize temporary receivers for chaining
and register them for the existing object cleanup mechanism.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/OperatorGen.cc')
| -rw-r--r-- | lib/CodeGen/OperatorGen.cc | 71 |
1 files changed, 67 insertions, 4 deletions
diff --git a/lib/CodeGen/OperatorGen.cc b/lib/CodeGen/OperatorGen.cc index 83c515b..d340ed7 100644 --- a/lib/CodeGen/OperatorGen.cc +++ b/lib/CodeGen/OperatorGen.cc @@ -1,7 +1,9 @@ #include "cps/CodeGen.h" #include "cps/Operator.h" +#include "cps/TypeAST.h" using namespace cps; +using namespace llvm; // Probing candidates must not evaluate operands or diagnose absent overloads: // both static typing and emission use this same selection. @@ -9,12 +11,73 @@ CodeGen::OperatorResolution CodeGen::resolveOperator( int Op, const TypeInfo *Left, const TypeInfo *Right) { OperatorResolution Result; if (!Left) return Result; - for (const FuncSig *Sig : FuncGen->getOverloads(operatorName(Op))) { - if (Sig->Prototype->getOperator() != Op || Sig->Params.size() != (Right ? 2u : 1u)) continue; - if (!Left->sameType(resolveType(Sig->Params[0].TypeName))) continue; - if (Right && !Right->sameType(resolveType(Sig->Params[1].TypeName))) continue; + auto Candidates = FuncGen->getOverloads(operatorName(Op)); + if (Left->IsClass) { + auto Members = FuncGen->getOverloads(Left->Name + "." + operatorName(Op)); + Candidates.insert(Candidates.end(), Members.begin(), Members.end()); + } + for (const FuncSig *Sig : Candidates) { + bool Member = !Sig->Prototype->getOwnerClass().empty(); + if (Sig->Prototype->getOperator() != Op || Sig->Params.size() != (Right ? 2u : 1u) - Member) continue; + if (!Member && !Left->sameType(resolveType(Sig->Params[0].TypeName))) continue; + if (Right && !Right->sameType(resolveType(Sig->Params[Member ? 0 : 1].TypeName))) continue; if (Result.Signature) Result.Ambiguous = true; else Result.Signature = Sig; } return Result; } + +bool CodeGen::checkOperatorAccess(const FuncSig &Signature) { + const PrototypeAST *Proto = Signature.Prototype; + if (!Proto->getOwnerClass().empty() && !Proto->isPublic() && + !sameIdentifier(CurrentClass, Proto->getOwnerClass())) { + reportError("Cannot access private method %s of type %s", + Proto->getName().c_str(), Proto->getOwnerClass().c_str()); + return false; + } + return true; +} + +Value *CodeGen::materializeOperatorReceiver(Value *Val, const TypeInfo *Type) { + if (!Val || !Type) return nullptr; + auto *Storage = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), + Type->LLVMType, "operator_receiver"); + size_t Object = registerStackObject(Storage, Type->Name, DiagnosticLine, false, true); + Builder->CreateStore(Val, Storage); + activateStackObject(Object); + return Storage; +} + +Value *CodeGen::emitOperatorCall(const FuncSig &Signature, ExprAST *Left, ExprAST *Right) { + if (!checkOperatorAccess(Signature)) return nullptr; + std::vector<Value*> Args; + std::vector<ExprAST*> Explicit; + if (Signature.Prototype->getOwnerClass().empty()) { + Explicit.push_back(Left); + } else { + Value *Receiver = nullptr; + if (dynamic_cast<VariableExprAST*>(Left) || dynamic_cast<ArrayAccessExprAST*>(Left) || + dynamic_cast<DesignatorExprAST*>(Left)) { + LValueInfo LV; + if (!emitLValue(Left, LV)) return nullptr; + Receiver = LV.Addr; + } else { + Receiver = materializeOperatorReceiver(emitExpr(Left), getExprTypeInfo(Left)); + } + if (!Receiver) return nullptr; + Args.push_back(Receiver); + } + if (Right) Explicit.push_back(Right); + if (!marshalCallArgs(Signature, Explicit, DiagnosticLine, Args)) return nullptr; + return FuncGen->emitCall(Signature, Args); +} + +// CASE has already evaluated and captured its selector and label values. +Value *CodeGen::emitOperatorValues(const FuncSig &Signature, Value *Left, + const TypeInfo *LeftType, Value *Right) { + if (!checkOperatorAccess(Signature)) return nullptr; + if (!Signature.Prototype->getOwnerClass().empty()) + Left = materializeOperatorReceiver(Left, LeftType); + if (!Left) return nullptr; + return FuncGen->emitCall(Signature, {Left, Right}); +} |
