aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CodeGen.cc
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-17 15:06:44 +0000
committer_ov4 <ov4@ov4.org>2026-10-17 15:06:44 +0000
commitdc33cd2faf6fa52486c02e86038c8f8c07c0fe27 (patch)
treed474619d75743399e7a324c8ae5ba04056333e0b /lib/CodeGen/CodeGen.cc
parenta29cb23c5517fd4f8f5524fdf38b67ff5fe4a902 (diff)
feat(codegen): declare and call EXTERN C functions
Variadic arguments must be C values and receive C default argument promotions; narrow integer parameters carry sign/zero extension. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/CodeGen.cc')
-rw-r--r--lib/CodeGen/CodeGen.cc30
1 files changed, 29 insertions, 1 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index 92a52e8..7abdad7 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -215,6 +215,9 @@ void CodeGen::compile(const std::vector<SourceUnit> &Sources) {
!sameIdentifier(F->getProto()->getReturnType(), "INTEGER"))
reportError("MAIN must be a FUNCTION with no parameters returning INTEGER");
}
+ } else if (auto *X = dynamic_cast<ExternDeclAST*>(S.get())) {
+ Reserve(X->getProto()->getName(), true);
+ } else if (dynamic_cast<IncludeObjStmtAST*>(S.get())) {
} else if (auto *E = dynamic_cast<EnumTypeDeclAST*>(S.get())) {
TypeName = E->getName();
for (const auto &V : E->getValueNames()) Reserve(V);
@@ -285,6 +288,8 @@ void CodeGen::compile(const std::vector<SourceUnit> &Sources) {
SaveAndRestore<int> Location(DiagnosticLine, Stmt->getLine());
if (auto *FuncDef = dynamic_cast<FunctionDefAST*>(Stmt.get()))
FuncGen->emitPrototype(FuncDef->getProto());
+ if (auto *Extern = dynamic_cast<ExternDeclAST*>(Stmt.get()))
+ FuncGen->emitExternPrototype(Extern->getProto());
if (auto *Class = dynamic_cast<ClassTypeDeclAST*>(Stmt.get())) {
for (const auto &Method : Class->getMethods()) {
SaveAndRestore<int> MethodLocation(DiagnosticLine, Method->getLine());
@@ -365,12 +370,18 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature,
SaveAndRestore<int> Location(DiagnosticLine, Line ? Line : DiagnosticLine);
const FuncSig *Sig = &Signature;
const std::string &Callee = Sig->Name;
- if (ArgExprs.size() != Sig->Params.size()) {
+ if (Sig->IsVariadic ? ArgExprs.size() < Sig->Params.size() : ArgExprs.size() != Sig->Params.size()) {
reportError("Incorrect # arguments passed to %s", Callee.c_str());
return false;
}
for (size_t i = 0; i < ArgExprs.size(); ++i) {
+ if (i >= Sig->Params.size()) {
+ Value *V = emitVariadicArgument(ArgExprs[i].get(), Callee, i + 1);
+ if (!V) return false;
+ Out.push_back(V);
+ continue;
+ }
const ParamSig &P = Sig->Params[i];
const std::string &TypeName = P.TypeName;
bool IsByRef = P.IsByRef;
@@ -424,6 +435,23 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature,
return true;
}
+// C default argument promotions for the variadic part of an EXTERN call; only
+// C values are accepted, matching the explicit-cast rule for C/pseudocode.
+Value *CodeGen::emitVariadicArgument(ExprAST *Expr, const std::string &Callee, size_t Position) {
+ const TypeInfo *Info = isWholeArrayVar(Expr) ? nullptr : getExprTypeInfo(Expr);
+ if (!Info || !Info->isC() || Info->isVoid()) {
+ reportError("Variadic argument %zu to %s must be a C value; cast it to a C type", Position, Callee.c_str());
+ return nullptr;
+ }
+ Value *V = emitExpr(Expr);
+ if (!V || Info->Kind != TypeKind::CScalar) return V;
+ if (Info->isReal()) {
+ const TypeInfo *Double = resolveType("C_DOUBLE");
+ return Info->CRank < Double->CRank ? convertNumericValue(V, Info, Double) : V;
+ }
+ return convertNumericValue(V, Info, Types->promoteCScalar(Info));
+}
+
// Resolve using static source types only; argument evaluation belongs to marshalling.
const FuncSig *CodeGen::resolveCall(const std::string &Name,
const std::vector<std::unique_ptr<ExprAST>> &Args) {