From 64aa538142148faf06b9a3c71907eacee04cd49d Mon Sep 17 00:00:00 2001 From: _ov4 Date: Sat, 17 Oct 2026 09:16:22 +0000 Subject: feat(codegen): FUNCTION MAIN entry point Invoke the internal entry function through the generated exception handler and truncate its INTEGER result to the process exit status. Co-Authored-By: Claude Opus 5.5 --- lib/CodeGen/CodeGen.cc | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'lib/CodeGen/CodeGen.cc') diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index 6aa1558..eba7d77 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -189,6 +189,8 @@ void CodeGen::compile(const std::vector &Sources) { IdentifierMap Definitions; std::optional CodeUnit; + FunctionDefAST *Entry = nullptr; + size_t EntryUnit = 0; auto Reserve = [&](const std::string &Name) { auto [It, Added] = Definitions.emplace(Name, CurrentUnit); if (!Added && It->second != CurrentUnit) @@ -202,6 +204,15 @@ void CodeGen::compile(const std::vector &Sources) { std::string TypeName; if (auto *F = dynamic_cast(S.get())) { Reserve(F->getProto()->getName()); + if (sameIdentifier(F->getProto()->getName(), "MAIN")) { + if (Entry) reportError("Multiple MAIN definitions in %s and %s", + Sources[EntryUnit].Path.c_str(), Sources[I].Path.c_str()); + Entry = F; + EntryUnit = I; + if (!F->getProto()->getParams().empty() || + !sameIdentifier(F->getProto()->getReturnType(), "INTEGER")) + reportError("MAIN must be a FUNCTION with no parameters returning INTEGER"); + } } else if (auto *E = dynamic_cast(S.get())) { TypeName = E->getName(); for (const auto &V : E->getValueNames()) Reserve(V); @@ -231,7 +242,14 @@ void CodeGen::compile(const std::vector &Sources) { } } if (HadError) return; - MainUnit = CodeUnit.value_or(0); + if (Entry && CodeUnit) { + selectUnit(EntryUnit); + SaveAndRestore Location(DiagnosticLine, Entry->getLine()); + reportError("FUNCTION MAIN in %s cannot coexist with top-level code in %s", + Sources[EntryUnit].Path.c_str(), Sources[*CodeUnit].Path.c_str()); + return; + } + MainUnit = Entry ? EntryUnit : CodeUnit.value_or(0); FunctionType *FT = FunctionType::get(Type::getInt32Ty(*TheContext), false); Function *F = Function::Create(FT, Function::ExternalLinkage, "main", TheModule.get()); BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", F); @@ -268,7 +286,8 @@ void CodeGen::compile(const std::vector &Sources) { if (auto *Class = dynamic_cast(Stmt.get())) { for (const auto &Method : Class->getMethods()) { SaveAndRestore MethodLocation(DiagnosticLine, Method->getLine()); - FuncGen->emitPrototype(Method->getProto()); + if (findMethod(Class->getName(), Method->getProto()->getName()) == Method->getProto()) + FuncGen->emitPrototype(Method->getProto()); } } } @@ -300,13 +319,18 @@ void CodeGen::compile(const std::vector &Sources) { for (const auto &Stmt : Sources[I].Statements) emitStmt(Stmt.get()); } selectUnit(MainUnit); - if (!CodeUnit && !HadError) { + if (!CodeUnit && !Entry && !HadError) { SaveAndRestore Location(DiagnosticLine, Sources.size() > 1 ? 1 : 0); reportError("no main program"); } if (!Builder->GetInsertBlock()->hasTerminator()) { - Exceptions->recordExit(Builder->CreateRet(ConstantInt::get(*TheContext, APInt(32, 0)))); + Value *Status = ConstantInt::get(*TheContext, APInt(32, 0)); + if (Entry) { + Value *Result = Exceptions->emitCall(TheModule->getFunction("__cps_main"), {}, "main_result"); + Status = Builder->CreateTrunc(Result, Type::getInt32Ty(*TheContext)); + } + Exceptions->recordExit(Builder->CreateRet(Status)); } finishStackObjects(F); -- cgit v1.3.1-4-g156e