diff options
| author | _ov4 <ov4@ov4.org> | 2026-07-26 12:04:56 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-07-26 12:04:56 +0000 |
| commit | efc86b5c7625cf4c7074319f42f68807a25bde9d (patch) | |
| tree | 0e2e1b5d9d336b1744602b3e47817f8a6b9c15f2 /lib/CodeGen/CodeGen.cc | |
| parent | 4df7c22b99349dcf2175d69679eafa175d49aa9f (diff) | |
refactor: single builtin registry, retire keyword route for builtins
All 11 builtins now live in one static {Name, Arity, ReturnTypeName}
table in CodeGen.cc: emitExpr checks arity against it (uniform
"Error: X expects N args" diagnostics) and getExprTypeInfo reads return
types from it, removing the duplicated hard-coded table.
LENGTH/MID/RIGHT/LEFT/LCASE/UCASE lose their lexer tokens and
ParseStringBuiltin; they parse as ordinary identifier calls exactly like
ASC/CHR/IS_NUM/NUM_TO_STR/STR_TO_NUM already did. Behavior note: these
six names are no longer reserved words.
AGENTS docs updated for the new builtin story and the batch-1 error
contract (exit codes, verifyModule, fixed descending FOR).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/CodeGen.cc')
| -rw-r--r-- | lib/CodeGen/CodeGen.cc | 60 |
1 files changed, 43 insertions, 17 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc index 439e894..581e4a9 100644 --- a/lib/CodeGen/CodeGen.cc +++ b/lib/CodeGen/CodeGen.cc @@ -9,6 +9,40 @@ using namespace llvm; using namespace cps; +namespace { + +// Single source of truth for the built-in functions: name, arity and return +// type. emitExpr checks arity against this table before dispatching, and +// getExprTypeInfo reads the return type from it. +struct BuiltinInfo { + const char *Name; + unsigned Arity; + const char *ReturnTypeName; +}; + +constexpr BuiltinInfo Builtins[] = { + {"LENGTH", 1, "INTEGER"}, + {"MID", 3, "STRING"}, + {"RIGHT", 2, "STRING"}, + {"LEFT", 2, "STRING"}, + {"LCASE", 1, "STRING"}, + {"UCASE", 1, "STRING"}, + {"ASC", 1, "INTEGER"}, + {"CHR", 1, "STRING"}, + {"IS_NUM", 1, "BOOLEAN"}, + {"NUM_TO_STR", 1, "STRING"}, + {"STR_TO_NUM", 1, "REAL"}, +}; + +const BuiltinInfo *findBuiltin(const std::string &Name) { + for (const auto &B : Builtins) { + if (Name == B.Name) return &B; + } + return nullptr; +} + +} // namespace + CodeGen::~CodeGen() = default; void CodeGen::reportError(const char *Fmt, ...) { @@ -174,12 +208,9 @@ const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) const { if (auto *Call = dynamic_cast<CallExprAST*>(Expr)) { const std::string &Name = Call->getCallee(); - if (Name == "LENGTH" || Name == "ASC") return resolveType("INTEGER"); - if (Name == "MID" || Name == "RIGHT" || Name == "LEFT" || - Name == "LCASE" || Name == "UCASE" || Name == "CHR" || - Name == "NUM_TO_STR") return resolveType("STRING"); - if (Name == "IS_NUM") return resolveType("BOOLEAN"); - if (Name == "STR_TO_NUM") return resolveType("REAL"); + if (const BuiltinInfo *B = findBuiltin(Name)) { + return resolveType(B->ReturnTypeName); + } Function *CalleeF = TheModule->getFunction(Name); if (!CalleeF) return resolveType("INTEGER"); @@ -474,12 +505,16 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { if (auto *Call = dynamic_cast<CallExprAST*>(Expr)) { std::string Name = Call->getCallee(); + if (const BuiltinInfo *B = findBuiltin(Name)) { + if (Call->getArgs().size() != B->Arity) { + reportError("%s expects %u arg%s", B->Name, B->Arity, B->Arity == 1 ? "" : "s"); + return nullptr; + } + } if (Name == "LENGTH") { - if (Call->getArgs().size() != 1) { reportError("LENGTH expects 1 arg"); return nullptr; } return StrHandler->emitLength(emitExpr(Call->getArgs()[0].get())); } if (Name == "MID") { - if (Call->getArgs().size() != 3) { reportError("MID expects 3 args"); return nullptr; } Value *Str = emitExpr(Call->getArgs()[0].get()); Value *Start = coerceValueToType(emitExpr(Call->getArgs()[1].get()), resolveType("INTEGER")); Value *Len = coerceValueToType(emitExpr(Call->getArgs()[2].get()), resolveType("INTEGER")); @@ -487,29 +522,24 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { return StrHandler->emitMid(Str, Start, Len); } if (Name == "RIGHT") { - if (Call->getArgs().size() != 2) { reportError("RIGHT expects 2 args"); return nullptr; } Value *Str = emitExpr(Call->getArgs()[0].get()); Value *Len = coerceValueToType(emitExpr(Call->getArgs()[1].get()), resolveType("INTEGER")); if (!Str || !Len) return nullptr; return StrHandler->emitRight(Str, Len); } if (Name == "LEFT") { - if (Call->getArgs().size() != 2) { reportError("LEFT expects 2 args"); return nullptr; } Value *Str = emitExpr(Call->getArgs()[0].get()); Value *Len = coerceValueToType(emitExpr(Call->getArgs()[1].get()), resolveType("INTEGER")); if (!Str || !Len) return nullptr; return StrHandler->emitLeft(Str, Len); } if (Name == "LCASE") { - if (Call->getArgs().size() != 1) { reportError("LCASE expects 1 arg"); return nullptr; } return StrHandler->emitLCase(emitExpr(Call->getArgs()[0].get())); } if (Name == "UCASE") { - if (Call->getArgs().size() != 1) { reportError("UCASE expects 1 arg"); return nullptr; } return StrHandler->emitUCase(emitExpr(Call->getArgs()[0].get())); } if (Name == "ASC") { - if (Call->getArgs().size() != 1) { reportError("ASC expects 1 arg"); return nullptr; } Value *ArgVal = emitExpr(Call->getArgs()[0].get()); const TypeInfo *ArgType = getExprTypeInfo(Call->getArgs()[0].get()); Value *CharVal = nullptr; @@ -522,7 +552,6 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { return coerceValueToType(AscVal, resolveType("INTEGER")); } if (Name == "CHR") { - if (Call->getArgs().size() != 1) { reportError("CHR expects 1 arg"); return nullptr; } Value *IntVal = coerceValueToType(emitExpr(Call->getArgs()[0].get()), resolveType("INTEGER")); Value *CharVal = ChrHandler->emitChr(IntVal); Function *MallocF = TheModule->getFunction("malloc"); @@ -535,11 +564,9 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { return Mem; } if (Name == "IS_NUM") { - if (Call->getArgs().size() != 1) { reportError("IS_NUM expects 1 arg"); return nullptr; } return StrConvHandler->emitIsNum(emitExpr(Call->getArgs()[0].get())); } if (Name == "NUM_TO_STR") { - if (Call->getArgs().size() != 1) { reportError("NUM_TO_STR expects 1 arg"); return nullptr; } Value *NumV = emitExpr(Call->getArgs()[0].get()); bool IsReal = NumV->getType()->isDoubleTy(); if (NumV->getType()->isIntegerTy(8)) { @@ -548,7 +575,6 @@ Value *CodeGen::emitExpr(ExprAST *Expr) { return StrConvHandler->emitNumToStr(NumV, IsReal); } if (Name == "STR_TO_NUM") { - if (Call->getArgs().size() != 1) { reportError("STR_TO_NUM expects 1 arg"); return nullptr; } return StrConvHandler->emitStrToNum(emitExpr(Call->getArgs()[0].get()), true); } |
