From dc33cd2faf6fa52486c02e86038c8f8c07c0fe27 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Sat, 17 Oct 2026 15:06:44 +0000 Subject: 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 --- lib/CodeGen/CodeGen.cc | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'lib/CodeGen/CodeGen.cc') 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 &Sources) { !sameIdentifier(F->getProto()->getReturnType(), "INTEGER")) reportError("MAIN must be a FUNCTION with no parameters returning INTEGER"); } + } else if (auto *X = dynamic_cast(S.get())) { + Reserve(X->getProto()->getName(), true); + } else if (dynamic_cast(S.get())) { } else if (auto *E = dynamic_cast(S.get())) { TypeName = E->getName(); for (const auto &V : E->getValueNames()) Reserve(V); @@ -285,6 +288,8 @@ void CodeGen::compile(const std::vector &Sources) { SaveAndRestore Location(DiagnosticLine, Stmt->getLine()); if (auto *FuncDef = dynamic_cast(Stmt.get())) FuncGen->emitPrototype(FuncDef->getProto()); + if (auto *Extern = dynamic_cast(Stmt.get())) + FuncGen->emitExternPrototype(Extern->getProto()); if (auto *Class = dynamic_cast(Stmt.get())) { for (const auto &Method : Class->getMethods()) { SaveAndRestore MethodLocation(DiagnosticLine, Method->getLine()); @@ -365,12 +370,18 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature, SaveAndRestore 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> &Args) { -- cgit v1.3.1-4-g156e