aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-18 06:09:01 +0000
committer_ov4 <ov4@ov4.org>2026-10-18 06:09:01 +0000
commitb17f101cfc75565f9991c856ec62f1e17b0ab104 (patch)
tree6c925f06c45dbaa557a0451cfca33f17be71ec67 /lib/CodeGen
parent16231050058131860f710073c17d3bca7c6637eb (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')
-rw-r--r--lib/CodeGen/CodeGen.cc12
-rw-r--r--lib/CodeGen/ExpressionGen.cc22
-rw-r--r--lib/CodeGen/OperatorGen.cc71
-rw-r--r--lib/CodeGen/ValueTypeGen.cc6
4 files changed, 103 insertions, 8 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index 61fd837..f7c4de6 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -369,6 +369,14 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature,
const std::vector<std::unique_ptr<ExprAST>> &ArgExprs,
int Line,
std::vector<Value*> &Out) {
+ std::vector<ExprAST*> Args;
+ for (const auto &Arg : ArgExprs) Args.push_back(Arg.get());
+ return marshalCallArgs(Signature, Args, Line, Out);
+}
+
+bool CodeGen::marshalCallArgs(const FuncSig &Signature,
+ const std::vector<ExprAST*> &ArgExprs,
+ int Line, std::vector<Value*> &Out) {
SaveAndRestore<int> Location(DiagnosticLine, Line ? Line : DiagnosticLine);
const FuncSig *Sig = &Signature;
const std::string &Callee = Sig->Name;
@@ -379,7 +387,7 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature,
for (size_t i = 0; i < ArgExprs.size(); ++i) {
if (i >= Sig->Params.size()) {
- Value *V = emitVariadicArgument(ArgExprs[i].get(), Callee, i + 1);
+ Value *V = emitVariadicArgument(ArgExprs[i], Callee, i + 1);
if (!V) return false;
Out.push_back(V);
continue;
@@ -387,7 +395,7 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature,
const ParamSig &P = Sig->Params[i];
const std::string &TypeName = P.TypeName;
bool IsByRef = P.IsByRef;
- ExprAST *ArgExpr = ArgExprs[i].get();
+ ExprAST *ArgExpr = ArgExprs[i];
if (P.IsArray) {
if (!Arrays->emitArrayArgument(ArgExpr, P.TypeName, P.Rank, P.DeclaredBounds,
diff --git a/lib/CodeGen/ExpressionGen.cc b/lib/CodeGen/ExpressionGen.cc
index 8fb13c9..a01cab2 100644
--- a/lib/CodeGen/ExpressionGen.cc
+++ b/lib/CodeGen/ExpressionGen.cc
@@ -73,6 +73,16 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
}
if (auto *Unary = dynamic_cast<UnaryExprAST*>(Expr)) {
+ if (isWholeArrayVar(Unary->getOperand())) {
+ reportError("A whole array cannot be used as an operand; index it");
+ return nullptr;
+ }
+ auto Overload = resolveOperator(Unary->getOp(), getExprTypeInfo(Unary->getOperand()));
+ if (Overload.Ambiguous) {
+ reportError("Ambiguous overload for %s", operatorName(Unary->getOp()).c_str());
+ return nullptr;
+ }
+ if (Overload.Signature) return emitOperatorCall(*Overload.Signature, Unary->getOperand());
if (Unary->getOp() == tok_not) {
const TypeInfo *Info = getExprTypeInfo(Unary->getOperand());
Value *Operand = Info && Info->isC()
@@ -123,6 +133,16 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
// '&' path: their admissible operations are decided by name here.
const TypeInfo *LT = getExprTypeInfo(Bin->getLHS());
const TypeInfo *RT = getExprTypeInfo(Bin->getRHS());
+ if (LT && RT) {
+ auto Overload = resolveOperator(Bin->getOp(), LT, RT);
+ if (Overload.Ambiguous) {
+ reportError("Ambiguous overload for %s(%s, %s)", operatorName(Bin->getOp()).c_str(),
+ LT->Name.c_str(), RT->Name.c_str());
+ return nullptr;
+ }
+ if (Overload.Signature)
+ return emitOperatorCall(*Overload.Signature, Bin->getLHS(), Bin->getRHS());
+ }
Value *L = emitExpr(Bin->getLHS());
Value *R = emitExpr(Bin->getRHS());
return emitBinaryOp(Bin->getOp(), L, LT, R, RT, Bin->getLine());
@@ -165,7 +185,7 @@ Value *CodeGen::emitBinaryOp(int Op, Value *L, const TypeInfo *LT,
reportError("Ambiguous overload for %s(%s, %s)", operatorName(Op).c_str(), LT->Name.c_str(), RT->Name.c_str());
return nullptr;
}
- if (Overload.Signature) return FuncGen->emitCall(*Overload.Signature, {L, R});
+ if (Overload.Signature) return emitOperatorValues(*Overload.Signature, L, LT, R);
if ((LT && LT->isC()) || (RT && RT->isC()))
return emitCBinaryOp(Op, L, LT, R, RT, Line);
if ((LT && LT->isUserKind()) || (RT && RT->isUserKind()))
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});
+}
diff --git a/lib/CodeGen/ValueTypeGen.cc b/lib/CodeGen/ValueTypeGen.cc
index b09a5d9..e7a3f77 100644
--- a/lib/CodeGen/ValueTypeGen.cc
+++ b/lib/CodeGen/ValueTypeGen.cc
@@ -70,10 +70,14 @@ const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) {
if (dynamic_cast<AddrOfExprAST*>(Expr)) return nullptr;
if (auto *Unary = dynamic_cast<UnaryExprAST*>(Expr)) {
+ if (isWholeArrayVar(Unary->getOperand())) return nullptr;
+ const TypeInfo *Operand = getExprTypeInfo(Unary->getOperand());
+ auto Overload = resolveOperator(Unary->getOp(), Operand);
+ if (Overload.Ambiguous) return nullptr;
+ if (Overload.Signature) return resolveType(Overload.Signature->ReturnTypeName);
if (Unary->getOp() == tok_not) {
return resolveType("BOOLEAN");
}
- const TypeInfo *Operand = getExprTypeInfo(Unary->getOperand());
if (Operand && Operand->isC()) return Types->promoteCScalar(Operand);
if (Operand && !Operand->isC() && !Operand->isUserKind())
return Operand->isReal() ? resolveType("REAL") : resolveType("INTEGER");