aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
author_ov4 <hausemasterstream@gmail.com>2026-03-27 01:50:32 +0000
committer_ov4 <hausemasterstream@gmail.com>2026-03-27 01:50:32 +0000
commitf2b051ae3e28135cc02589f3f698c43743cca48e (patch)
tree91582f514eda6665c8283875dd0b3ee491cc62ea /lib/CodeGen
parent15f30a397a222e9256d41e8b8a7b6fff454b02da (diff)
feat: generalize typed array support
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/ArrayHandler.cc326
-rw-r--r--lib/CodeGen/CodeGen.cc690
-rw-r--r--lib/CodeGen/FunctionGen.cc62
-rw-r--r--lib/CodeGen/TypeSystem.cc156
4 files changed, 895 insertions, 339 deletions
diff --git a/lib/CodeGen/ArrayHandler.cc b/lib/CodeGen/ArrayHandler.cc
index 5842f77..fd55009 100644
--- a/lib/CodeGen/ArrayHandler.cc
+++ b/lib/CodeGen/ArrayHandler.cc
@@ -1,22 +1,35 @@
#include "cps/ArrayHandler.h"
#include "cps/CodeGen.h"
-#include "llvm/IR/Type.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/Type.h"
+#include <cstdio>
using namespace llvm;
using namespace cps;
-ArrayHandler::ArrayHandler(LLVMContext &C, IRBuilder<> &B, Module &M, std::map<std::string, Value*> &NV, RuntimeCheck &RC)
- : TheContext(&C), Builder(&B), TheModule(&M), NamedValues(&NV), RuntimeChecker(RC) {
+ArrayHandler::ArrayHandler(LLVMContext &C,
+ IRBuilder<> &B,
+ Module &M,
+ std::map<std::string, Value*> &NV,
+ std::map<std::string, SymbolInfo> &Sym,
+ TypeSystem &TS,
+ RuntimeCheck &RC)
+ : TheContext(&C),
+ Builder(&B),
+ TheModule(&M),
+ NamedValues(&NV),
+ Symbols(&Sym),
+ Types(TS),
+ RuntimeChecker(RC) {
setupExternalFunctions();
}
void ArrayHandler::setupExternalFunctions() {
std::vector<Type*> MallocArgs;
MallocArgs.push_back(Type::getInt64Ty(*TheContext));
-
+
FunctionType *MallocType = FunctionType::get(PointerType::getUnqual(*TheContext), MallocArgs, false);
MallocFunc = TheModule->getOrInsertFunction("malloc", MallocType);
@@ -26,89 +39,124 @@ void ArrayHandler::setupExternalFunctions() {
FreeFunc = TheModule->getOrInsertFunction("free", FreeType);
}
+const ArrayMetadata *ArrayHandler::getMetadata(const std::string &Name) const {
+ auto It = ArrayTable.find(Name);
+ if (It == ArrayTable.end()) {
+ return nullptr;
+ }
+ return &It->second;
+}
+
+Value *ArrayHandler::computeFlatIndex(const std::string &Name, const std::vector<Value*> &Indices) {
+ const ArrayMetadata *Meta = getMetadata(Name);
+ if (!Meta) return nullptr;
+
+ Value *Offset = ConstantInt::get(*TheContext, APInt(64, 0));
+ for (size_t i = 0; i < Indices.size(); ++i) {
+ Value *Idx = Indices[i];
+ Value *Lower = Meta->LowerBounds[i];
+ Value *Diff = Builder->CreateSub(Idx, Lower);
+ Value *Term = Builder->CreateMul(Diff, Meta->Multipliers[i]);
+ Offset = Builder->CreateAdd(Offset, Term);
+ }
+ return Offset;
+}
+
+Value *ArrayHandler::getArrayBasePointer(const std::string &Name) {
+ auto It = NamedValues->find(Name);
+ if (It == NamedValues->end() || !It->second) {
+ return nullptr;
+ }
+ return Builder->CreateLoad(PointerType::getUnqual(*TheContext), It->second, (Name + "_raw").c_str());
+}
+
+Value *ArrayHandler::getElementPointer(const std::string &Name, Value *Offset) {
+ const ArrayMetadata *Meta = getMetadata(Name);
+ if (!Meta || !Offset) return nullptr;
+
+ Value *RawPtr = getArrayBasePointer(Name);
+ if (!RawPtr) return nullptr;
+
+ PointerType *TypedPtrTy = PointerType::getUnqual(Meta->ElementType);
+ Value *TypedPtr = Builder->CreateBitCast(RawPtr, TypedPtrTy, Name + "_typed_ptr");
+ return Builder->CreateGEP(Meta->ElementType, TypedPtr, Offset, Name + "_elem_ptr");
+}
+
void ArrayHandler::emitArrayDeclare(ArrayDeclareStmtAST *Stmt, CodeGen &CG) {
std::string Name = Stmt->getName();
- int Rank = Stmt->getBounds().size();
-
- std::vector<Value*> Lows, Highs, Dims;
+ int Rank = static_cast<int>(Stmt->getBounds().size());
+
+ const TypeInfo *ElemInfo = Types.resolve(Stmt->getType());
+ if (!ElemInfo || !ElemInfo->LLVMType || ElemInfo->isVoid()) {
+ fprintf(stderr, "Error: Unknown array element type %s\n", Stmt->getType().c_str());
+ return;
+ }
+
+ std::vector<Value*> Lows;
+ std::vector<Value*> Highs;
+ std::vector<Value*> Dims;
Value *TotalElements = ConstantInt::get(*TheContext, APInt(64, 1));
-
+
for (const auto &Pair : Stmt->getBounds()) {
Value *L = CG.emitExpr(Pair.first.get());
Value *R = CG.emitExpr(Pair.second.get());
-
+ L = CG.coerceValueToType(L, CG.resolveType("INTEGER"));
+ R = CG.coerceValueToType(R, CG.resolveType("INTEGER"));
+
if (!L || !R) return;
-
- Value *L64 = Builder->CreateSExt(L, Type::getInt64Ty(*TheContext));
- Value *R64 = Builder->CreateSExt(R, Type::getInt64Ty(*TheContext));
-
+
Lows.push_back(L);
Highs.push_back(R);
-
- Value *Diff = Builder->CreateSub(R64, L64);
- Value *DimSize = Builder->CreateAdd(Diff, ConstantInt::get(*TheContext, APInt(64, 1)));
+
+ Value *Diff = Builder->CreateSub(R, L, Name + "_dim_diff");
+ Value *DimSize = Builder->CreateAdd(Diff, ConstantInt::get(*TheContext, APInt(64, 1)), Name + "_dim_size");
Dims.push_back(DimSize);
-
- TotalElements = Builder->CreateMul(TotalElements, DimSize);
+ TotalElements = Builder->CreateMul(TotalElements, DimSize, Name + "_total_elems");
}
-
+
std::vector<Value*> Multipliers(Rank);
Multipliers[Rank - 1] = ConstantInt::get(*TheContext, APInt(64, 1));
-
for (int i = Rank - 2; i >= 0; --i) {
- Value *NextMult = Multipliers[i+1];
- Value *NextDimSize = Dims[i+1];
- Multipliers[i] = Builder->CreateMul(NextMult, NextDimSize);
+ Multipliers[i] = Builder->CreateMul(Multipliers[i + 1], Dims[i + 1], Name + "_mult");
}
ArrayMetadata Meta;
Meta.Rank = Rank;
- Meta.ElementType = Type::getInt64Ty(*TheContext);
- Meta.LowerBounds = Lows;
- Meta.UpperBounds = Highs;
- Meta.Multipliers = Multipliers;
+ Meta.ElementTypeName = ElemInfo->Name;
+ Meta.ElementType = ElemInfo->LLVMType;
+ Meta.ElementSize = ElemInfo->ElementSize;
+ Meta.LowerBounds = std::move(Lows);
+ Meta.UpperBounds = std::move(Highs);
+ Meta.Multipliers = std::move(Multipliers);
ArrayTable[Name] = Meta;
-
- Value *ElemSize = ConstantInt::get(*TheContext, APInt(64, 8));
- Value *TotalBytes = Builder->CreateMul(TotalElements, ElemSize);
-
- CallInst *Ptr = Builder->CreateCall(MallocFunc, TotalBytes);
-
+ Value *ElemSize = ConstantInt::get(*TheContext, APInt(64, ElemInfo->ElementSize));
+ Value *TotalBytes = Builder->CreateMul(TotalElements, ElemSize, Name + "_total_bytes");
+ CallInst *Ptr = Builder->CreateCall(MallocFunc, TotalBytes, Name + "_malloc");
+
+ FunctionType *MemsetType = FunctionType::get(PointerType::getUnqual(*TheContext),
+ {PointerType::getUnqual(*TheContext), Type::getInt32Ty(*TheContext), Type::getInt64Ty(*TheContext)},
+ false);
+ FunctionCallee MemsetFunc = TheModule->getOrInsertFunction("memset", MemsetType);
+ Builder->CreateCall(MemsetFunc,
+ {Ptr, ConstantInt::get(Type::getInt32Ty(*TheContext), 0), TotalBytes});
+
Function *TheFunction = Builder->GetInsertBlock()->getParent();
- IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin());
-
- AllocaInst *Alloca = TmpB.CreateAlloca(PointerType::getUnqual(*TheContext), nullptr, Name);
-
+ AllocaInst *Alloca = CG.CreateEntryBlockAlloca(TheFunction, PointerType::getUnqual(*TheContext), Name);
Builder->CreateStore(Ptr, Alloca);
- (*NamedValues)[Name] = Alloca;
-}
-Value* ArrayHandler::computeFlatIndex(const std::string &Name, const std::vector<Value*> &Indices) {
- if (ArrayTable.find(Name) == ArrayTable.end()) return nullptr;
- const auto &Meta = ArrayTable[Name];
-
- Value *Offset = ConstantInt::get(*TheContext, APInt(64, 0));
-
- for (size_t i = 0; i < Indices.size(); ++i) {
- Value *Idx = Indices[i];
- Value *Lower = Meta.LowerBounds[i];
- Value *Diff = Builder->CreateSub(Idx, Lower);
- Value *Term = Builder->CreateMul(Diff, Meta.Multipliers[i]);
- Offset = Builder->CreateAdd(Offset, Term);
- }
- return Offset;
+ CG.registerSymbol(Name, Alloca, ElemInfo->Name, true);
}
-Value* ArrayHandler::emitArrayAccess(ArrayAccessExprAST *Expr, CodeGen &CG) {
+Value *ArrayHandler::emitArrayAccess(ArrayAccessExprAST *Expr, CodeGen &CG) {
std::string Name = Expr->getName();
- if (ArrayTable.find(Name) == ArrayTable.end()) {
+ const ArrayMetadata *Meta = getMetadata(Name);
+ if (!Meta) {
fprintf(stderr, "Error: Undeclared array %s\n", Name.c_str());
return nullptr;
}
-
- const auto &Meta = ArrayTable[Name];
- if (Expr->getIndices().size() != Meta.Rank) {
+
+ if (Expr->getIndices().size() != static_cast<size_t>(Meta->Rank)) {
fprintf(stderr, "Error: Incorrect number of indices for %s\n", Name.c_str());
return nullptr;
}
@@ -116,125 +164,147 @@ Value* ArrayHandler::emitArrayAccess(ArrayAccessExprAST *Expr, CodeGen &CG) {
std::vector<Value*> Indices;
for (size_t i = 0; i < Expr->getIndices().size(); ++i) {
Value *Idx = CG.emitExpr(Expr->getIndices()[i].get());
- Indices.push_back(Idx);
+ Idx = CG.coerceValueToType(Idx, CG.resolveType("INTEGER"));
+ if (!Idx) return nullptr;
- Value *Lower = Meta.LowerBounds[i];
- Value *Upper = Meta.UpperBounds[i];
- RuntimeChecker.emitIndexCheck(Idx, Lower, Upper, Expr->getLine());
+ Indices.push_back(Idx);
+ RuntimeChecker.emitIndexCheck(Idx, Meta->LowerBounds[i], Meta->UpperBounds[i], Expr->getLine());
}
-
+
Value *Offset = computeFlatIndex(Name, Indices);
-
- Value *Alloca = (*NamedValues)[Name];
- Value *RawPtr = Builder->CreateLoad(PointerType::getUnqual(*TheContext), Alloca);
- Value *IntPtr = Builder->CreateBitCast(RawPtr, PointerType::getUnqual(*TheContext));
- Value *ElemPtr = Builder->CreateGEP(Type::getInt64Ty(*TheContext), IntPtr, Offset);
-
- return Builder->CreateLoad(Type::getInt64Ty(*TheContext), ElemPtr);
+ Value *ElemPtr = getElementPointer(Name, Offset);
+ if (!ElemPtr) return nullptr;
+
+ Value *Val = Builder->CreateLoad(Meta->ElementType, ElemPtr, Name + "_elem");
+ if (Meta->ElementTypeName == "STRING") {
+ Value *IsNull = Builder->CreateICmpEQ(Val,
+ ConstantPointerNull::get(cast<PointerType>(Meta->ElementType)),
+ Name + "_str_is_null");
+ Val = Builder->CreateSelect(IsNull, CG.EmptyStringStr, Val, Name + "_safe_str");
+ }
+ return Val;
}
void ArrayHandler::emitArrayAssign(ArrayAssignStmtAST *Stmt, CodeGen &CG) {
std::string Name = Stmt->getName();
- if (ArrayTable.find(Name) == ArrayTable.end()) {
+ const ArrayMetadata *Meta = getMetadata(Name);
+ if (!Meta) {
fprintf(stderr, "Error: Undeclared array %s\n", Name.c_str());
return;
}
-
+
+ if (Stmt->getIndices().size() != static_cast<size_t>(Meta->Rank)) {
+ fprintf(stderr, "Error: Incorrect number of indices for %s\n", Name.c_str());
+ return;
+ }
+
std::vector<Value*> Indices;
for (size_t i = 0; i < Stmt->getIndices().size(); ++i) {
Value *Idx = CG.emitExpr(Stmt->getIndices()[i].get());
- Indices.push_back(Idx);
+ Idx = CG.coerceValueToType(Idx, CG.resolveType("INTEGER"));
+ if (!Idx) return;
- const auto &Meta = ArrayTable[Name];
- Value *Lower = Meta.LowerBounds[i];
- Value *Upper = Meta.UpperBounds[i];
- RuntimeChecker.emitIndexCheck(Idx, Lower, Upper, Stmt->getLine());
+ Indices.push_back(Idx);
+ RuntimeChecker.emitIndexCheck(Idx, Meta->LowerBounds[i], Meta->UpperBounds[i], Stmt->getLine());
}
-
+
+ const TypeInfo *ElemInfo = Types.resolve(Meta->ElementTypeName);
Value *Val = CG.emitExpr(Stmt->getExpr());
+ Val = CG.coerceValueToType(Val, ElemInfo);
+ if (!Val) return;
+
Value *Offset = computeFlatIndex(Name, Indices);
-
- Value *Alloca = (*NamedValues)[Name];
- Value *RawPtr = Builder->CreateLoad(PointerType::getUnqual(*TheContext), Alloca);
- Value *IntPtr = Builder->CreateBitCast(RawPtr, PointerType::getUnqual(*TheContext));
- Value *ElemPtr = Builder->CreateGEP(Type::getInt64Ty(*TheContext), IntPtr, Offset);
-
+ Value *ElemPtr = getElementPointer(Name, Offset);
+ if (!ElemPtr) return;
+
Builder->CreateStore(Val, ElemPtr);
}
-bool ArrayHandler::tryEmitArrayOutput(ExprAST *Expr, CodeGen &CG, llvm::FunctionCallee PrintfFunc, llvm::Value* FmtStr) {
+bool ArrayHandler::tryEmitArrayOutput(ExprAST *Expr, CodeGen &CG) {
std::string Name;
std::vector<Value*> Indices;
-
+
if (auto *Var = dynamic_cast<VariableExprAST*>(Expr)) {
Name = Var->getName();
- if (ArrayTable.find(Name) == ArrayTable.end()) return false;
- }
- else if (auto *Acc = dynamic_cast<ArrayAccessExprAST*>(Expr)) {
+ if (!getMetadata(Name)) return false;
+ } else if (auto *Acc = dynamic_cast<ArrayAccessExprAST*>(Expr)) {
Name = Acc->getName();
- if (ArrayTable.find(Name) == ArrayTable.end()) return false;
-
- for (const auto &Idx : Acc->getIndices()) {
- Indices.push_back(CG.emitExpr(Idx.get()));
+ const ArrayMetadata *Meta = getMetadata(Name);
+ if (!Meta) return false;
+
+ for (size_t i = 0; i < Acc->getIndices().size(); ++i) {
+ Value *Idx = CG.emitExpr(Acc->getIndices()[i].get());
+ Idx = CG.coerceValueToType(Idx, CG.resolveType("INTEGER"));
+ if (!Idx) return false;
+ Indices.push_back(Idx);
+ RuntimeChecker.emitIndexCheck(Idx, Meta->LowerBounds[i], Meta->UpperBounds[i], Acc->getLine());
+ }
+
+ if (Indices.size() > static_cast<size_t>(Meta->Rank)) {
+ fprintf(stderr, "Error: Incorrect number of indices for %s\n", Name.c_str());
+ return true;
}
} else {
return false;
}
-
- const auto &Meta = ArrayTable[Name];
-
- if (Indices.size() == Meta.Rank) {
+
+ const ArrayMetadata *Meta = getMetadata(Name);
+ if (!Meta) return false;
+ if (Indices.size() == static_cast<size_t>(Meta->Rank)) {
return false;
}
-
- emitPrintLoop(Name, Indices.size(), Indices, PrintfFunc, FmtStr);
+
+ emitPrintLoop(Name, static_cast<int>(Indices.size()), Indices, CG);
return true;
}
-void ArrayHandler::emitPrintLoop(const std::string &Name, int CurrentDim, std::vector<Value*> CurrentIndices, llvm::FunctionCallee PrintfFunc, llvm::Value* FmtStr) {
- const auto &Meta = ArrayTable[Name];
-
- if (CurrentDim == Meta.Rank) {
+void ArrayHandler::emitPrintLoop(const std::string &Name,
+ int CurrentDim,
+ std::vector<Value*> CurrentIndices,
+ CodeGen &CG) {
+ const ArrayMetadata *Meta = getMetadata(Name);
+ if (!Meta) return;
+
+ if (CurrentDim == Meta->Rank) {
Value *Offset = computeFlatIndex(Name, CurrentIndices);
-
- Value *Alloca = (*NamedValues)[Name];
- Value *RawPtr = Builder->CreateLoad(PointerType::getUnqual(*TheContext), Alloca);
- Value *IntPtr = Builder->CreateBitCast(RawPtr, PointerType::getUnqual(*TheContext));
- Value *ElemPtr = Builder->CreateGEP(Type::getInt64Ty(*TheContext), IntPtr, Offset);
- Value *Val = Builder->CreateLoad(Type::getInt64Ty(*TheContext), ElemPtr);
-
- std::vector<Value*> Args;
- Args.push_back(FmtStr);
- Args.push_back(Val);
- Builder->CreateCall(PrintfFunc, Args);
+ Value *ElemPtr = getElementPointer(Name, Offset);
+ if (!ElemPtr) return;
+
+ Value *Val = Builder->CreateLoad(Meta->ElementType, ElemPtr, Name + "_print_val");
+ if (Meta->ElementTypeName == "STRING") {
+ Value *IsNull = Builder->CreateICmpEQ(Val,
+ ConstantPointerNull::get(cast<PointerType>(Meta->ElementType)),
+ Name + "_print_str_is_null");
+ Val = Builder->CreateSelect(IsNull, CG.EmptyStringStr, Val, Name + "_print_safe_str");
+ }
+
+ CG.emitOutputValue(Val, Types.resolve(Meta->ElementTypeName), true);
return;
}
-
+
Function *TheFunction = Builder->GetInsertBlock()->getParent();
BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "arr_loop", TheFunction);
BasicBlock *AfterBB = BasicBlock::Create(*TheContext, "arr_after", TheFunction);
-
- IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin());
- AllocaInst *LoopVar = TmpB.CreateAlloca(Type::getInt64Ty(*TheContext), nullptr, "idx");
-
- Value *Start = Meta.LowerBounds[CurrentDim];
- Value *End = Meta.UpperBounds[CurrentDim];
-
+
+ AllocaInst *LoopVar = CG.CreateEntryBlockAlloca(TheFunction, Type::getInt64Ty(*TheContext), "idx");
+ Value *Start = Meta->LowerBounds[CurrentDim];
+ Value *End = Meta->UpperBounds[CurrentDim];
+
Builder->CreateStore(Start, LoopVar);
Builder->CreateBr(LoopBB);
-
+
Builder->SetInsertPoint(LoopBB);
Value *CurVal = Builder->CreateLoad(Type::getInt64Ty(*TheContext), LoopVar);
-
+
std::vector<Value*> NextIndices = CurrentIndices;
NextIndices.push_back(CurVal);
- emitPrintLoop(Name, CurrentDim + 1, NextIndices, PrintfFunc, FmtStr);
-
+ emitPrintLoop(Name, CurrentDim + 1, NextIndices, CG);
+
Value *NextVal = Builder->CreateAdd(CurVal, ConstantInt::get(*TheContext, APInt(64, 1)));
Builder->CreateStore(NextVal, LoopVar);
-
+
Value *Cond = Builder->CreateICmpSLE(NextVal, End);
Builder->CreateCondBr(Cond, LoopBB, AfterBB);
-
+
Builder->SetInsertPoint(AfterBB);
}
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index c5b0ff3..c77f5d8 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -1,8 +1,9 @@
#include "cps/CodeGen.h"
#include "cps/ArrayHandler.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/IR/Instructions.h"
#include "cps/Lexer.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Verifier.h"
+#include <cstdio>
using namespace llvm;
using namespace cps;
@@ -13,12 +14,24 @@ CodeGen::CodeGen() {
TheContext = std::make_unique<LLVMContext>();
TheModule = std::make_unique<Module>("cps_module", *TheContext);
Builder = std::make_unique<IRBuilder<>>(*TheContext);
-
+
+ Types = std::make_unique<TypeSystem>(*TheContext);
RuntimeChecker = std::make_unique<RuntimeCheck>(*TheModule, *TheContext, *Builder);
-
- Arrays = std::make_unique<ArrayHandler>(*TheContext, *Builder, *TheModule, NamedValues, *RuntimeChecker);
-
- FuncGen = std::make_unique<FunctionGen>(*TheContext, *TheModule, *Builder, NamedValues);
+
+ Arrays = std::make_unique<ArrayHandler>(*TheContext,
+ *Builder,
+ *TheModule,
+ NamedValues,
+ Symbols,
+ *Types,
+ *RuntimeChecker);
+
+ FuncGen = std::make_unique<FunctionGen>(*TheContext,
+ *TheModule,
+ *Builder,
+ *Types,
+ NamedValues,
+ Symbols);
IntHandler = std::make_unique<IntegerHandler>(*TheContext, *Builder, *TheModule, NamedValues);
RealHelper = std::make_unique<RealHandler>(*TheContext, *Builder, *TheModule, NamedValues);
@@ -43,20 +56,316 @@ void CodeGen::SetupExternalFunctions() {
PrintfFormatStr = Builder->CreateGlobalStringPtr("%lld\n", "fmt_nl", 0, TheModule.get());
PrintfFloatFormatStr = Builder->CreateGlobalStringPtr("%f\n", "fmt_flt", 0, TheModule.get());
PrintfStringFormatStr = Builder->CreateGlobalStringPtr("%s\n", "fmt_str", 0, TheModule.get());
+ PrintfCharFormatStr = Builder->CreateGlobalStringPtr("%c\n", "fmt_chr", 0, TheModule.get());
ScanfFormatStr = Builder->CreateGlobalStringPtr("%lld", "fmt_in", 0, TheModule.get());
ScanfFloatFormatStr = Builder->CreateGlobalStringPtr("%lf", "fmt_in_flt", 0, TheModule.get());
- ScanfStringFormatStr = Builder->CreateGlobalStringPtr("%s", "fmt_in_str", 0, TheModule.get()); // NEW
+ ScanfStringFormatStr = Builder->CreateGlobalStringPtr("%s", "fmt_in_str", 0, TheModule.get());
TrueStr = Builder->CreateGlobalStringPtr("TRUE", "str_true", 0, TheModule.get());
FalseStr = Builder->CreateGlobalStringPtr("FALSE", "str_false", 0, TheModule.get());
-
+ EmptyStringStr = Builder->CreateGlobalStringPtr("", "str_empty", 0, TheModule.get());
+
Arrays->setupExternalFunctions();
}
AllocaInst *CodeGen::CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) {
+ return CreateEntryBlockAlloca(TheFunction, Type::getInt64Ty(*TheContext), VarName);
+}
+
+AllocaInst *CodeGen::CreateEntryBlockAlloca(Function *TheFunction,
+ Type *AllocType,
+ const std::string &VarName) {
IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin());
- return TmpB.CreateAlloca(Type::getInt64Ty(*TheContext), nullptr, VarName);
+ return TmpB.CreateAlloca(AllocType, nullptr, VarName);
+}
+
+void CodeGen::registerSymbol(const std::string &Name,
+ Value *Storage,
+ const std::string &TypeName,
+ bool IsArray) {
+ NamedValues[Name] = Storage;
+ Symbols[Name] = {Storage, TypeName, IsArray};
+}
+
+const SymbolInfo *CodeGen::getSymbolInfo(const std::string &Name) const {
+ auto It = Symbols.find(Name);
+ if (It == Symbols.end()) {
+ return nullptr;
+ }
+ return &It->second;
+}
+
+const TypeInfo *CodeGen::resolveType(const std::string &TypeName) const {
+ return Types->resolve(TypeName);
+}
+
+Type *CodeGen::getLLVMType(const std::string &TypeName) const {
+ return Types->getLLVMType(TypeName);
+}
+
+Value *CodeGen::getNamedValue(const std::string &Name) const {
+ auto It = NamedValues.find(Name);
+ return It == NamedValues.end() ? nullptr : It->second;
+}
+
+const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) const {
+ if (!Expr) return nullptr;
+
+ if (dynamic_cast<IntegerExprAST*>(Expr)) return resolveType("INTEGER");
+ if (dynamic_cast<RealExprAST*>(Expr)) return resolveType("REAL");
+ if (dynamic_cast<BooleanExprAST*>(Expr)) return resolveType("BOOLEAN");
+ if (dynamic_cast<CharExprAST*>(Expr)) return resolveType("CHAR");
+ if (dynamic_cast<StringExprAST*>(Expr)) return resolveType("STRING");
+
+ if (auto *Var = dynamic_cast<VariableExprAST*>(Expr)) {
+ const SymbolInfo *Info = getSymbolInfo(Var->getName());
+ return Info ? resolveType(Info->TypeName) : nullptr;
+ }
+
+ if (auto *Arr = dynamic_cast<ArrayAccessExprAST*>(Expr)) {
+ const SymbolInfo *Info = getSymbolInfo(Arr->getName());
+ return Info ? resolveType(Info->TypeName) : nullptr;
+ }
+
+ if (auto *Unary = dynamic_cast<UnaryExprAST*>(Expr)) {
+ if (Unary->getOp() == tok_not) {
+ return resolveType("BOOLEAN");
+ }
+ return getExprTypeInfo(Unary->getOperand());
+ }
+
+ if (auto *Bin = dynamic_cast<BinaryExprAST*>(Expr)) {
+ switch (Bin->getOp()) {
+ case tok_eq:
+ case tok_ne:
+ case '<':
+ case '>':
+ case tok_le:
+ case tok_ge:
+ case tok_and:
+ case tok_or:
+ return resolveType("BOOLEAN");
+ case '&':
+ return resolveType("STRING");
+ default:
+ break;
+ }
+
+ const TypeInfo *L = getExprTypeInfo(Bin->getLHS());
+ const TypeInfo *R = getExprTypeInfo(Bin->getRHS());
+ if ((L && L->Kind == TypeKind::Real) || (R && R->Kind == TypeKind::Real)) {
+ return resolveType("REAL");
+ }
+ return resolveType("INTEGER");
+ }
+
+ 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");
+
+ Function *CalleeF = TheModule->getFunction(Name);
+ if (!CalleeF) return resolveType("INTEGER");
+
+ Type *RetTy = CalleeF->getReturnType();
+ if (RetTy->isVoidTy()) return resolveType("VOID");
+ if (RetTy->isDoubleTy()) return resolveType("REAL");
+ if (RetTy->isIntegerTy(1)) return resolveType("BOOLEAN");
+ if (RetTy->isIntegerTy(8)) return resolveType("CHAR");
+ if (RetTy->isPointerTy()) return resolveType("STRING");
+ return resolveType("INTEGER");
+ }
+
+ return nullptr;
+}
+
+Value *CodeGen::coerceValueToType(Value *Val, const TypeInfo *TargetInfo) {
+ if (!Val || !TargetInfo || !TargetInfo->LLVMType) return nullptr;
+
+ if (Val->getType() == TargetInfo->LLVMType) {
+ return Val;
+ }
+
+ switch (TargetInfo->Kind) {
+ case TypeKind::Real:
+ if (Val->getType()->isDoubleTy()) return Val;
+ if (Val->getType()->isIntegerTy(1))
+ return Builder->CreateUIToFP(Val, Type::getDoubleTy(*TheContext), "bool_to_real");
+ if (Val->getType()->isIntegerTy(8))
+ return Builder->CreateUIToFP(Val, Type::getDoubleTy(*TheContext), "char_to_real");
+ if (Val->getType()->isIntegerTy())
+ return Builder->CreateSIToFP(Val, Type::getDoubleTy(*TheContext), "int_to_real");
+ break;
+
+ case TypeKind::Integer:
+ if (Val->getType()->isIntegerTy(64)) return Val;
+ if (Val->getType()->isDoubleTy())
+ return Builder->CreateFPToSI(Val, Type::getInt64Ty(*TheContext), "real_to_int");
+ if (Val->getType()->isIntegerTy(1))
+ return Builder->CreateZExt(Val, Type::getInt64Ty(*TheContext), "bool_to_int");
+ if (Val->getType()->isIntegerTy(8))
+ return Builder->CreateZExt(Val, Type::getInt64Ty(*TheContext), "char_to_int");
+ if (Val->getType()->isIntegerTy())
+ return Builder->CreateSExtOrTrunc(Val, Type::getInt64Ty(*TheContext), "int_cast");
+ break;
+
+ case TypeKind::Boolean:
+ if (Val->getType()->isIntegerTy(1)) return Val;
+ if (Val->getType()->isIntegerTy())
+ return Builder->CreateICmpNE(Val, Constant::getNullValue(Val->getType()), "to_bool");
+ if (Val->getType()->isDoubleTy())
+ return Builder->CreateFCmpONE(Val, ConstantFP::get(*TheContext, APFloat(0.0)), "to_bool");
+ if (Val->getType()->isPointerTy())
+ return Builder->CreateICmpNE(Val,
+ ConstantPointerNull::get(cast<PointerType>(Val->getType())),
+ "ptr_to_bool");
+ break;
+
+ case TypeKind::Char:
+ if (Val->getType()->isIntegerTy(8)) return Val;
+ if (Val->getType()->isIntegerTy(1))
+ return Builder->CreateZExt(Val, Type::getInt8Ty(*TheContext), "bool_to_char");
+ if (Val->getType()->isDoubleTy())
+ return Builder->CreateFPToUI(Val, Type::getInt8Ty(*TheContext), "real_to_char");
+ if (Val->getType()->isIntegerTy())
+ return Builder->CreateTruncOrBitCast(Val, Type::getInt8Ty(*TheContext), "int_to_char");
+ break;
+
+ case TypeKind::String:
+ if (Val->getType()->isPointerTy()) return Val;
+ if (Val->getType()->isIntegerTy(1)) {
+ return Builder->CreateSelect(Val, TrueStr, FalseStr, "bool_to_str");
+ }
+ if (Val->getType()->isDoubleTy()) {
+ return StrConvHandler->emitNumToStr(Val, true);
+ }
+ if (Val->getType()->isIntegerTy(8)) {
+ Function *MallocF = TheModule->getFunction("malloc");
+ if (!MallocF) {
+ FunctionType *MallocTy = FunctionType::get(PointerType::getUnqual(*TheContext),
+ {Type::getInt64Ty(*TheContext)},
+ false);
+ MallocF = Function::Create(MallocTy,
+ Function::ExternalLinkage,
+ "malloc",
+ TheModule.get());
+ }
+ Value *Mem = Builder->CreateCall(MallocF,
+ ConstantInt::get(*TheContext, APInt(64, 2)),
+ "char_str");
+ Builder->CreateStore(Val, Mem);
+ Value *NullPtr = Builder->CreateInBoundsGEP(Type::getInt8Ty(*TheContext),
+ Mem,
+ ConstantInt::get(*TheContext, APInt(64, 1)));
+ Builder->CreateStore(ConstantInt::get(Type::getInt8Ty(*TheContext), 0), NullPtr);
+ return Mem;
+ }
+ if (Val->getType()->isIntegerTy()) {
+ Value *AsInt = coerceValueToType(Val, resolveType("INTEGER"));
+ return AsInt ? StrConvHandler->emitNumToStr(AsInt, false) : nullptr;
+ }
+ break;
+
+ case TypeKind::Void:
+ return nullptr;
+
+ case TypeKind::Custom:
+ if (Val->getType() == TargetInfo->LLVMType) return Val;
+ if (Val->getType()->isPointerTy() && TargetInfo->LLVMType->isPointerTy()) {
+ return Builder->CreateBitCast(Val, TargetInfo->LLVMType, "custom_ptr_cast");
+ }
+ break;
+ }
+
+ fprintf(stderr,
+ "Error: Cannot coerce value of LLVM type to target type %s\n",
+ TargetInfo->Name.c_str());
+ return nullptr;
+}
+
+void CodeGen::emitDeclareStmt(DeclareStmtAST *Stmt) {
+ const TypeInfo *Info = resolveType(Stmt->getType());
+ if (!Info || !Info->LLVMType || Info->isVoid()) {
+ fprintf(stderr, "Error: Unknown type %s\n", Stmt->getType().c_str());
+ return;
+ }
+
+ Function *TheFunction = Builder->GetInsertBlock()->getParent();
+ AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Info->LLVMType, Stmt->getName());
+
+ Value *InitVal = nullptr;
+ if (Info->isString()) {
+ InitVal = EmptyStringStr;
+ } else {
+ InitVal = Types->getZeroValue(Info->Name);
+ }
+
+ if (InitVal) {
+ Builder->CreateStore(InitVal, Alloca);
+ }
+
+ registerSymbol(Stmt->getName(), Alloca, Info->Name, false);
+}
+
+void CodeGen::emitOutputValue(Value *Val, const TypeInfo *Info, bool AppendNewline) {
+ if (!Val || !Info) return;
+ if (!Info->Printable && Info->Kind == TypeKind::Custom) {
+ fprintf(stderr, "Error: OUTPUT for custom type %s is not implemented yet\n", Info->Name.c_str());
+ return;
+ }
+
+ std::vector<Value*> Args;
+ Value *Fmt = nullptr;
+
+ if (Info->isReal()) {
+ Fmt = AppendNewline
+ ? PrintfFloatFormatStr
+ : Builder->CreateGlobalStringPtr("%f", "fmt_flt_inline", 0, TheModule.get());
+ Args.push_back(Fmt);
+ Args.push_back(Val);
+ } else if (Info->isBoolean()) {
+ Value *BoolVal = coerceValueToType(Val, resolveType("BOOLEAN"));
+ Fmt = AppendNewline
+ ? PrintfStringFormatStr
+ : Builder->CreateGlobalStringPtr("%s", "fmt_str_inline", 0, TheModule.get());
+ Args.push_back(Fmt);
+ Args.push_back(Builder->CreateSelect(BoolVal, TrueStr, FalseStr));
+ } else if (Info->isString()) {
+ Value *StrVal = Val;
+ if (StrVal->getType()->isPointerTy()) {
+ Value *IsNull = Builder->CreateICmpEQ(StrVal,
+ ConstantPointerNull::get(cast<PointerType>(StrVal->getType())),
+ "str_is_null");
+ StrVal = Builder->CreateSelect(IsNull, EmptyStringStr, StrVal, "safe_str");
+ }
+ Fmt = AppendNewline
+ ? PrintfStringFormatStr
+ : Builder->CreateGlobalStringPtr("%s", "fmt_str_inline", 0, TheModule.get());
+ Args.push_back(Fmt);
+ Args.push_back(StrVal);
+ } else if (Info->isChar()) {
+ Value *CharVal = coerceValueToType(Val, resolveType("CHAR"));
+ Value *Promoted = Builder->CreateZExt(CharVal, Type::getInt32Ty(*TheContext), "char_for_printf");
+ Fmt = AppendNewline
+ ? PrintfCharFormatStr
+ : Builder->CreateGlobalStringPtr("%c", "fmt_chr_inline", 0, TheModule.get());
+ Args.push_back(Fmt);
+ Args.push_back(Promoted);
+ } else {
+ Value *IntVal = coerceValueToType(Val, resolveType("INTEGER"));
+ Fmt = AppendNewline
+ ? PrintfFormatStr
+ : Builder->CreateGlobalStringPtr("%lld", "fmt_int_inline", 0, TheModule.get());
+ Args.push_back(Fmt);
+ Args.push_back(IntVal);
+ }
+
+ Builder->CreateCall(PrintfFunc, Args);
}
void CodeGen::compile(const std::vector<std::unique_ptr<StmtAST>> &Statements) {
@@ -69,9 +378,10 @@ void CodeGen::compile(const std::vector<std::unique_ptr<StmtAST>> &Statements) {
emitStmt(Stmt.get());
}
- if (!Builder->GetInsertBlock()->getTerminator())
+ if (!Builder->GetInsertBlock()->getTerminator()) {
Builder->CreateRet(ConstantInt::get(*TheContext, APInt(32, 0)));
-
+ }
+
verifyFunction(*F);
}
@@ -94,19 +404,38 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
return BoolHandler->createLiteral(Bool->getVal());
}
+ if (auto *Chr = dynamic_cast<CharExprAST*>(Expr)) {
+ return ConstantInt::get(Type::getInt8Ty(*TheContext), static_cast<unsigned char>(Chr->getVal()));
+ }
+
if (auto *Str = dynamic_cast<StringExprAST*>(Expr)) {
return StrHandler->createLiteral(Str->getVal());
}
-
+
if (auto *Var = dynamic_cast<VariableExprAST*>(Expr)) {
- Value *A = NamedValues[Var->getName()];
- if (!A) {
+ const SymbolInfo *Info = getSymbolInfo(Var->getName());
+ if (!Info) {
fprintf(stderr, "Error: Unknown variable name %s\n", Var->getName().c_str());
return nullptr;
}
-
- Type *AllocType = cast<AllocaInst>(A)->getAllocatedType();
- return Builder->CreateLoad(AllocType, A, Var->getName().c_str());
+ if (Info->IsArray) {
+ return Info->Storage;
+ }
+
+ const TypeInfo *TypeInfo = resolveType(Info->TypeName);
+ if (!TypeInfo || !TypeInfo->LLVMType) {
+ fprintf(stderr, "Error: Unknown type for variable %s\n", Var->getName().c_str());
+ return nullptr;
+ }
+
+ Value *Loaded = Builder->CreateLoad(TypeInfo->LLVMType, Info->Storage, Var->getName().c_str());
+ if (TypeInfo->isString()) {
+ Value *IsNull = Builder->CreateICmpEQ(Loaded,
+ ConstantPointerNull::get(cast<PointerType>(Loaded->getType())),
+ "str_is_null");
+ Loaded = Builder->CreateSelect(IsNull, EmptyStringStr, Loaded, "safe_var_str");
+ }
+ return Loaded;
}
if (auto *ArrAcc = dynamic_cast<ArrayAccessExprAST*>(Expr)) {
@@ -116,14 +445,9 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
if (auto *Unary = dynamic_cast<UnaryExprAST*>(Expr)) {
Value *Operand = emitExpr(Unary->getOperand());
if (!Operand) return nullptr;
-
+
if (Unary->getOp() == tok_not) {
- if (Operand->getType()->isIntegerTy(64)) {
- Operand = Builder->CreateICmpNE(Operand, ConstantInt::get(*TheContext, APInt(64, 0)), "tobool");
- } else if (Operand->getType()->isDoubleTy()) {
- Operand = Builder->CreateFCmpONE(Operand, ConstantFP::get(*TheContext, APFloat(0.0)), "tobool");
- }
-
+ Operand = coerceValueToType(Operand, resolveType("BOOLEAN"));
return Builder->CreateNot(Operand, "nottmp");
}
}
@@ -132,7 +456,6 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
Value *L = emitExpr(Bin->getLHS());
Value *R = emitExpr(Bin->getRHS());
if (!L || !R) return nullptr;
-
return ArithHandler->emitBinaryOp(Bin->getOp(), L, R, Bin->getLine());
}
@@ -144,18 +467,18 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
}
if (Name == "MID") {
if (Call->getArgs().size() != 3) { fprintf(stderr, "MID expects 3 args\n"); return nullptr; }
- return StrHandler->emitMid(emitExpr(Call->getArgs()[0].get()),
- emitExpr(Call->getArgs()[1].get()),
+ return StrHandler->emitMid(emitExpr(Call->getArgs()[0].get()),
+ emitExpr(Call->getArgs()[1].get()),
emitExpr(Call->getArgs()[2].get()));
}
if (Name == "RIGHT") {
if (Call->getArgs().size() != 2) { fprintf(stderr, "RIGHT expects 2 args\n"); return nullptr; }
- return StrHandler->emitRight(emitExpr(Call->getArgs()[0].get()),
+ return StrHandler->emitRight(emitExpr(Call->getArgs()[0].get()),
emitExpr(Call->getArgs()[1].get()));
}
if (Name == "LEFT") {
if (Call->getArgs().size() != 2) { fprintf(stderr, "LEFT expects 2 args\n"); return nullptr; }
- return StrHandler->emitLeft(emitExpr(Call->getArgs()[0].get()),
+ return StrHandler->emitLeft(emitExpr(Call->getArgs()[0].get()),
emitExpr(Call->getArgs()[1].get()));
}
if (Name == "LCASE") {
@@ -168,17 +491,27 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
}
if (Name == "ASC") {
if (Call->getArgs().size() != 1) return nullptr;
- Value *StrPtr = emitExpr(Call->getArgs()[0].get());
- Value *CharVal = Builder->CreateLoad(Type::getInt8Ty(*TheContext), StrPtr, "char_load");
- return ChrHandler->emitAsc(CharVal);
+ Value *ArgVal = emitExpr(Call->getArgs()[0].get());
+ const TypeInfo *ArgType = getExprTypeInfo(Call->getArgs()[0].get());
+ Value *CharVal = nullptr;
+ if (ArgType && ArgType->isChar()) {
+ CharVal = coerceValueToType(ArgVal, resolveType("CHAR"));
+ } else {
+ CharVal = Builder->CreateLoad(Type::getInt8Ty(*TheContext), ArgVal, "char_load");
+ }
+ Value *AscVal = ChrHandler->emitAsc(CharVal);
+ return coerceValueToType(AscVal, resolveType("INTEGER"));
}
if (Name == "CHR") {
if (Call->getArgs().size() != 1) return nullptr;
- Value *CharVal = ChrHandler->emitChr(emitExpr(Call->getArgs()[0].get()));
+ Value *IntVal = coerceValueToType(emitExpr(Call->getArgs()[0].get()), resolveType("INTEGER"));
+ Value *CharVal = ChrHandler->emitChr(IntVal);
Function *MallocF = TheModule->getFunction("malloc");
Value *Mem = Builder->CreateCall(MallocF, ConstantInt::get(*TheContext, APInt(64, 2)));
Builder->CreateStore(CharVal, Mem);
- Value *NullPtr = Builder->CreateInBoundsGEP(Type::getInt8Ty(*TheContext), Mem, ConstantInt::get(*TheContext, APInt(64, 1)));
+ Value *NullPtr = Builder->CreateInBoundsGEP(Type::getInt8Ty(*TheContext),
+ Mem,
+ ConstantInt::get(*TheContext, APInt(64, 1)));
Builder->CreateStore(ConstantInt::get(Type::getInt8Ty(*TheContext), 0), NullPtr);
return Mem;
}
@@ -189,8 +522,11 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
if (Name == "NUM_TO_STR") {
if (Call->getArgs().size() != 1) return nullptr;
Value *NumV = emitExpr(Call->getArgs()[0].get());
- bool isReal = NumV->getType()->isDoubleTy();
- return StrConvHandler->emitNumToStr(NumV, isReal);
+ bool IsReal = NumV->getType()->isDoubleTy();
+ if (NumV->getType()->isIntegerTy(8)) {
+ NumV = coerceValueToType(NumV, resolveType("INTEGER"));
+ }
+ return StrConvHandler->emitNumToStr(NumV, IsReal);
}
if (Name == "STR_TO_NUM") {
if (Call->getArgs().size() != 1) return nullptr;
@@ -199,28 +535,28 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
Function *CalleeF = TheModule->getFunction(Call->getCallee());
std::vector<Value*> Args;
-
+
for (unsigned i = 0; i < Call->getArgs().size(); ++i) {
ExprAST *ArgExpr = Call->getArgs()[i].get();
- bool isByRef = false;
+ bool IsByRef = false;
if (CalleeF && i < CalleeF->arg_size()) {
if (CalleeF->getArg(i)->getType()->isPointerTy()) {
- isByRef = true;
+ IsByRef = true;
}
}
- if (isByRef) {
+ if (IsByRef) {
if (auto *Var = dynamic_cast<VariableExprAST*>(ArgExpr)) {
- Value *Ptr = NamedValues[Var->getName()];
+ Value *Ptr = getNamedValue(Var->getName());
if (!Ptr) {
fprintf(stderr, "Error: Unknown variable %s in BYREF call\n", Var->getName().c_str());
return nullptr;
}
Args.push_back(Ptr);
} else {
- fprintf(stderr, "Error: BYREF argument must be a variable.\n");
- return nullptr;
+ fprintf(stderr, "Error: BYREF argument must be a variable.\n");
+ return nullptr;
}
} else {
Args.push_back(emitExpr(ArgExpr));
@@ -236,10 +572,7 @@ void CodeGen::emitIfStmt(IfStmtAST *Stmt) {
Value *CondV = emitExpr(Stmt->getCond());
if (!CondV) return;
- if (CondV->getType()->isIntegerTy(64))
- CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(64, 0)), "ifcond");
- if (CondV->getType()->isIntegerTy(1))
- CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(1, 0)), "ifcond");
+ CondV = coerceValueToType(CondV, resolveType("BOOLEAN"));
Function *TheFunction = Builder->GetInsertBlock()->getParent();
BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction);
@@ -261,7 +594,7 @@ void CodeGen::emitIfStmt(IfStmtAST *Stmt) {
void CodeGen::emitWhileStmt(WhileStmtAST *Stmt) {
Function *TheFunction = Builder->GetInsertBlock()->getParent();
-
+
BasicBlock *CondBB = BasicBlock::Create(*TheContext, "whilecond", TheFunction);
BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "whileloop", TheFunction);
BasicBlock *AfterBB = BasicBlock::Create(*TheContext, "whilecont", TheFunction);
@@ -271,16 +604,13 @@ void CodeGen::emitWhileStmt(WhileStmtAST *Stmt) {
Builder->SetInsertPoint(CondBB);
Value *CondV = emitExpr(Stmt->getCond());
if (!CondV) return;
- if (CondV->getType()->isIntegerTy(64))
- CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(64, 0)), "loopcond");
- if (CondV->getType()->isIntegerTy(1))
- CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(1, 0)), "loopcond");
-
+ CondV = coerceValueToType(CondV, resolveType("BOOLEAN"));
+
Builder->CreateCondBr(CondV, LoopBB, AfterBB);
Builder->SetInsertPoint(LoopBB);
for (const auto &S : Stmt->getBody()) emitStmt(S.get());
-
+
if (!Builder->GetInsertBlock()->getTerminator())
Builder->CreateBr(CondBB);
@@ -304,11 +634,7 @@ void CodeGen::emitRepeatStmt(RepeatStmtAST *Stmt) {
Builder->SetInsertPoint(CondBB);
Value *CondV = emitExpr(Stmt->getCond());
if (!CondV) return;
-
- if (CondV->getType()->isIntegerTy(64))
- CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(64, 0)), "untilcond");
- if (CondV->getType()->isIntegerTy(1))
- CondV = Builder->CreateICmpNE(CondV, ConstantInt::get(*TheContext, APInt(1, 0)), "untilcond");
+ CondV = coerceValueToType(CondV, resolveType("BOOLEAN"));
Builder->CreateCondBr(CondV, AfterBB, LoopBB);
@@ -318,15 +644,21 @@ void CodeGen::emitRepeatStmt(RepeatStmtAST *Stmt) {
void CodeGen::emitForStmt(ForStmtAST *Stmt) {
Function *TheFunction = Builder->GetInsertBlock()->getParent();
std::string VarName = Stmt->getVarName();
-
- Value *StartVal = emitExpr(Stmt->getStart());
- if (!StartVal) return;
- Value *Alloca = NamedValues[VarName];
- if (!Alloca) {
+ const SymbolInfo *Symbol = getSymbolInfo(VarName);
+ if (!Symbol) {
fprintf(stderr, "Error: Unknown variable in FOR loop %s\n", VarName.c_str());
return;
}
+ if (Symbol->TypeName != "INTEGER") {
+ fprintf(stderr, "Error: FOR loop variable %s must be INTEGER\n", VarName.c_str());
+ return;
+ }
+
+ Value *StartVal = coerceValueToType(emitExpr(Stmt->getStart()), resolveType("INTEGER"));
+ if (!StartVal) return;
+
+ Value *Alloca = Symbol->Storage;
Builder->CreateStore(StartVal, Alloca);
BasicBlock *CondBB = BasicBlock::Create(*TheContext, "forcond", TheFunction);
@@ -338,22 +670,19 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
Builder->SetInsertPoint(CondBB);
Value *CurVar = Builder->CreateLoad(Type::getInt64Ty(*TheContext), Alloca, VarName.c_str());
- Value *EndVal = emitExpr(Stmt->getEnd());
+ Value *EndVal = coerceValueToType(emitExpr(Stmt->getEnd()), resolveType("INTEGER"));
if (!EndVal) return;
- bool isNegativeStep = false;
+ bool IsNegativeStep = false;
if (Stmt->getStep()) {
if (auto *Num = dynamic_cast<IntegerExprAST*>(Stmt->getStep())) {
- if (Num->getVal() < 0) isNegativeStep = true;
+ if (Num->getVal() < 0) IsNegativeStep = true;
}
}
- Value *CondV;
- if (isNegativeStep) {
- CondV = Builder->CreateICmpSGE(CurVar, EndVal, "forcond_ge");
- } else {
- CondV = Builder->CreateICmpSLE(CurVar, EndVal, "forcond_le");
- }
+ Value *CondV = IsNegativeStep
+ ? Builder->CreateICmpSGE(CurVar, EndVal, "forcond_ge")
+ : Builder->CreateICmpSLE(CurVar, EndVal, "forcond_le");
Builder->CreateCondBr(CondV, LoopBB, AfterBB);
@@ -363,13 +692,13 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
Builder->CreateBr(IncBB);
Builder->SetInsertPoint(IncBB);
- Value *StepVal;
+ Value *StepVal = nullptr;
if (Stmt->getStep()) {
- StepVal = emitExpr(Stmt->getStep());
+ StepVal = coerceValueToType(emitExpr(Stmt->getStep()), resolveType("INTEGER"));
} else {
StepVal = ConstantInt::get(*TheContext, APInt(64, 1));
}
-
+
Value *CurValForInc = Builder->CreateLoad(Type::getInt64Ty(*TheContext), Alloca, VarName.c_str());
Value *NextVal = Builder->CreateAdd(CurValForInc, StepVal, "nextval");
Builder->CreateStore(NextVal, Alloca);
@@ -385,7 +714,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
Arrays->emitArrayDeclare(ArrDecl, *this);
return;
}
-
+
if (auto *ArrAssign = dynamic_cast<ArrayAssignStmtAST*>(Stmt)) {
Arrays->emitArrayAssign(ArrAssign, *this);
return;
@@ -394,40 +723,39 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
if (auto *FuncDef = dynamic_cast<FunctionDefAST*>(Stmt)) {
BasicBlock *SavedBlock = Builder->GetInsertBlock();
- FuncGen->emitFunctionDef(FuncDef, [this](StmtAST *S) {
- this->emitStmt(S);
+ FuncGen->emitFunctionDef(FuncDef, [this](StmtAST *S) {
+ this->emitStmt(S);
});
if (SavedBlock) Builder->SetInsertPoint(SavedBlock);
-
return;
}
- else if (auto *Call = dynamic_cast<CallStmtAST*>(Stmt)) {
+ if (auto *Call = dynamic_cast<CallStmtAST*>(Stmt)) {
Function *CalleeF = TheModule->getFunction(Call->getCallee());
std::vector<Value*> Args;
-
+
for (unsigned i = 0; i < Call->getArgs().size(); ++i) {
ExprAST *ArgExpr = Call->getArgs()[i].get();
- bool isByRef = false;
-
+ bool IsByRef = false;
+
if (CalleeF && i < CalleeF->arg_size()) {
if (CalleeF->getArg(i)->getType()->isPointerTy()) {
- isByRef = true;
+ IsByRef = true;
}
}
- if (isByRef) {
+ if (IsByRef) {
if (auto *Var = dynamic_cast<VariableExprAST*>(ArgExpr)) {
- Value *Ptr = NamedValues[Var->getName()];
+ Value *Ptr = getNamedValue(Var->getName());
if (!Ptr) {
fprintf(stderr, "Error: Unknown variable %s in BYREF call\n", Var->getName().c_str());
return;
}
Args.push_back(Ptr);
} else {
- fprintf(stderr, "Error: BYREF argument must be a variable.\n");
- return;
+ fprintf(stderr, "Error: BYREF argument must be a variable.\n");
+ return;
}
} else {
Args.push_back(emitExpr(ArgExpr));
@@ -437,7 +765,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
return;
}
- else if (auto *Ret = dynamic_cast<ReturnStmtAST*>(Stmt)) {
+ if (auto *Ret = dynamic_cast<ReturnStmtAST*>(Stmt)) {
Value *RetVal = nullptr;
if (Ret->getRetVal()) {
RetVal = emitExpr(Ret->getRetVal());
@@ -447,120 +775,106 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
}
if (auto *Decl = dynamic_cast<DeclareStmtAST*>(Stmt)) {
- if (Decl->getType() == "INTEGER") IntHandler->emitDeclare(Decl->getName());
- else if (Decl->getType() == "REAL") RealHelper->emitDeclare(Decl->getName());
- else if (Decl->getType() == "BOOLEAN") BoolHandler->emitDeclare(Decl->getName());
- else if (Decl->getType() == "STRING") StrHandler->emitDeclare(Decl->getName());
- else {
- fprintf(stderr, "Unknown type %s\n", Decl->getType().c_str());
- }
+ emitDeclareStmt(Decl);
+ return;
}
- else if (auto *Assign = dynamic_cast<AssignStmtAST*>(Stmt)) {
- Value *Val = emitExpr(Assign->getExpr());
- if (Val) {
- Value *Alloca = NamedValues[Assign->getName()];
- if (!Alloca) {
- fprintf(stderr, "Error: Unknown variable name %s\n", Assign->getName().c_str());
- return;
- }
-
- AllocaInst *AI = cast<AllocaInst>(Alloca);
-
- if (AI->getAllocatedType() == Type::getDoubleTy(*TheContext) && Val->getType()->isIntegerTy(64)) {
- Val = Builder->CreateSIToFP(Val, Type::getDoubleTy(*TheContext));
- }
- if (AI->getAllocatedType() == Type::getInt64Ty(*TheContext) && Val->getType()->isDoubleTy()) {
- Val = Builder->CreateFPToSI(Val, Type::getInt64Ty(*TheContext), "double_to_int");
- }
-
- if (AI->getAllocatedType() == Type::getInt64Ty(*TheContext) && Val->getType()->isIntegerTy(1)) {
- Val = Builder->CreateZExt(Val, Type::getInt64Ty(*TheContext));
- }
-
- Builder->CreateStore(Val, Alloca);
+ if (auto *Assign = dynamic_cast<AssignStmtAST*>(Stmt)) {
+ const SymbolInfo *Info = getSymbolInfo(Assign->getName());
+ if (!Info) {
+ fprintf(stderr, "Error: Unknown variable name %s\n", Assign->getName().c_str());
+ return;
+ }
+ if (Info->IsArray) {
+ fprintf(stderr, "Error: Cannot assign array %s without indices\n", Assign->getName().c_str());
+ return;
}
+
+ Value *Val = emitExpr(Assign->getExpr());
+ const TypeInfo *TargetType = resolveType(Info->TypeName);
+ Val = coerceValueToType(Val, TargetType);
+ if (!Val) return;
+
+ Builder->CreateStore(Val, Info->Storage);
+ return;
}
- else if (auto *In = dynamic_cast<InputStmtAST*>(Stmt)) {
- Value *Alloca = NamedValues[In->getName()];
- if (Alloca) {
- AllocaInst *AI = cast<AllocaInst>(Alloca);
- std::vector<Value*> Args;
-
- if (AI->getAllocatedType()->isDoubleTy()) {
- Args.push_back(ScanfFloatFormatStr);
- Args.push_back(Alloca);
- Builder->CreateCall(ScanfFunc, Args);
- } else if (AI->getAllocatedType()->isIntegerTy(1)) {
- AllocaInst *TempInt = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), "tmp_bool_input");
-
- Args.push_back(ScanfFormatStr);
- Args.push_back(TempInt);
- Builder->CreateCall(ScanfFunc, Args);
- Value *Val = Builder->CreateLoad(Type::getInt64Ty(*TheContext), TempInt);
- Value *BoolVal = Builder->CreateICmpNE(Val, ConstantInt::get(*TheContext, APInt(64, 0)), "bool_cast");
-
- Builder->CreateStore(BoolVal, Alloca);
- } else if (AI->getAllocatedType()->isPointerTy()) {
- Value *BufSize = ConstantInt::get(*TheContext, APInt(64, 256));
+ if (auto *In = dynamic_cast<InputStmtAST*>(Stmt)) {
+ const SymbolInfo *Info = getSymbolInfo(In->getName());
+ if (!Info) {
+ fprintf(stderr, "Error: Unknown variable name %s\n", In->getName().c_str());
+ return;
+ }
+ if (Info->IsArray) {
+ fprintf(stderr, "Error: INPUT for entire array %s is not supported\n", In->getName().c_str());
+ return;
+ }
- Args.push_back(ScanfStringFormatStr);
+ const TypeInfo *TypeInfo = resolveType(Info->TypeName);
+ if (!TypeInfo) {
+ fprintf(stderr, "Error: Unknown type for INPUT %s\n", In->getName().c_str());
+ return;
+ }
- AllocaInst *InputBuf = Builder->CreateAlloca(Type::getInt8Ty(*TheContext), ConstantInt::get(*TheContext, APInt(64, 1024)), "input_buf");
- Args.push_back(InputBuf);
- Builder->CreateCall(ScanfFunc, Args);
+ std::vector<Value*> Args;
+ if (TypeInfo->isReal()) {
+ Args.push_back(ScanfFloatFormatStr);
+ Args.push_back(Info->Storage);
+ Builder->CreateCall(ScanfFunc, Args);
+ } else if (TypeInfo->isBoolean()) {
+ AllocaInst *TempInt = CreateEntryBlockAlloca(Builder->GetInsertBlock()->getParent(), "tmp_bool_input");
+ Args.push_back(ScanfFormatStr);
+ Args.push_back(TempInt);
+ Builder->CreateCall(ScanfFunc, Args);
- Function *MallocF = TheModule->getFunction("malloc");
- if (MallocF) {
- Value *Mem = Builder->CreateCall(MallocF, ConstantInt::get(*TheContext, APInt(64, 1024)));
- Args[1] = Mem;
- Builder->CreateCall(ScanfFunc, Args);
- Builder->CreateStore(Mem, Alloca);
- }
- } else {
- Args.push_back(ScanfFormatStr);
- Args.push_back(Alloca);
- Builder->CreateCall(ScanfFunc, Args);
- }
+ Value *Val = Builder->CreateLoad(Type::getInt64Ty(*TheContext), TempInt);
+ Value *BoolVal = Builder->CreateICmpNE(Val, ConstantInt::get(*TheContext, APInt(64, 0)), "bool_cast");
+ Builder->CreateStore(BoolVal, Info->Storage);
+ } else if (TypeInfo->isString()) {
+ Function *MallocF = TheModule->getFunction("malloc");
+ Value *Mem = Builder->CreateCall(MallocF, ConstantInt::get(*TheContext, APInt(64, 1024)), "input_str");
+ Args.push_back(ScanfStringFormatStr);
+ Args.push_back(Mem);
+ Builder->CreateCall(ScanfFunc, Args);
+ Builder->CreateStore(Mem, Info->Storage);
+ } else if (TypeInfo->isChar()) {
+ Value *CharFmt = Builder->CreateGlobalStringPtr(" %c", "fmt_in_char", 0, TheModule.get());
+ Args.push_back(CharFmt);
+ Args.push_back(Info->Storage);
+ Builder->CreateCall(ScanfFunc, Args);
+ } else {
+ Args.push_back(ScanfFormatStr);
+ Args.push_back(Info->Storage);
+ Builder->CreateCall(ScanfFunc, Args);
}
+ return;
}
- else if (auto *Out = dynamic_cast<OutputStmtAST*>(Stmt)) {
- bool handled = Arrays->tryEmitArrayOutput(Out->getExpr(), *this, PrintfFunc, PrintfFormatStr);
-
- if (!handled) {
- Value *Val = emitExpr(Out->getExpr());
- if (Val) {
- std::vector<Value*> Args;
- if (Val->getType()->isDoubleTy()) {
- Args.push_back(PrintfFloatFormatStr);
- Args.push_back(Val);
- } else if (Val->getType()->isIntegerTy(1)) {
- Args.push_back(PrintfStringFormatStr);
- Value *StrPtr = Builder->CreateSelect(Val, TrueStr, FalseStr);
- Args.push_back(StrPtr);
- } else if (Val->getType()->isPointerTy()) {
- Args.push_back(PrintfStringFormatStr);
- Args.push_back(Val);
- } else {
- Args.push_back(PrintfFormatStr);
- Args.push_back(Val);
- }
-
- Builder->CreateCall(PrintfFunc, Args);
- }
- }
+
+ if (auto *Out = dynamic_cast<OutputStmtAST*>(Stmt)) {
+ bool Handled = Arrays->tryEmitArrayOutput(Out->getExpr(), *this);
+ if (Handled) return;
+
+ Value *Val = emitExpr(Out->getExpr());
+ const TypeInfo *TypeInfo = getExprTypeInfo(Out->getExpr());
+ if (!TypeInfo) TypeInfo = resolveType("INTEGER");
+ emitOutputValue(Val, TypeInfo, true);
+ return;
}
- else if (auto *IfStmt = dynamic_cast<IfStmtAST*>(Stmt)) {
+
+ if (auto *IfStmt = dynamic_cast<IfStmtAST*>(Stmt)) {
emitIfStmt(IfStmt);
+ return;
}
- else if (auto *WhileStmt = dynamic_cast<WhileStmtAST*>(Stmt)) {
+ if (auto *WhileStmt = dynamic_cast<WhileStmtAST*>(Stmt)) {
emitWhileStmt(WhileStmt);
+ return;
}
- else if (auto *RepeatStmt = dynamic_cast<RepeatStmtAST*>(Stmt)) {
+ if (auto *RepeatStmt = dynamic_cast<RepeatStmtAST*>(Stmt)) {
emitRepeatStmt(RepeatStmt);
+ return;
}
- else if (auto *ForStmt = dynamic_cast<ForStmtAST*>(Stmt)) {
+ if (auto *ForStmt = dynamic_cast<ForStmtAST*>(Stmt)) {
emitForStmt(ForStmt);
+ return;
}
}
diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc
index a929943..89aa3d8 100644
--- a/lib/CodeGen/FunctionGen.cc
+++ b/lib/CodeGen/FunctionGen.cc
@@ -1,16 +1,17 @@
#include "cps/FunctionGen.h"
#include "llvm/IR/Verifier.h"
-#include <iostream>
+#include <cstdio>
using namespace llvm;
using namespace cps;
Type *FunctionGen::getLLVMType(const std::string &TypeName) {
- if (TypeName == "INTEGER") return Type::getInt64Ty(Context);
- if (TypeName == "BOOLEAN") return Type::getInt1Ty(Context);
- if (TypeName == "REAL") return Type::getDoubleTy(Context);
- if (TypeName == "VOID") return Type::getVoidTy(Context);
- return Type::getInt64Ty(Context);
+ Type *Resolved = Types.getLLVMType(TypeName);
+ if (!Resolved) {
+ fprintf(stderr, "Error: Unknown type %s\n", TypeName.c_str());
+ return Type::getInt64Ty(Context);
+ }
+ return Resolved;
}
void FunctionGen::createArgumentAllocas(Function *F, const std::vector<std::tuple<std::string, std::string, bool>> &Args) {
@@ -19,20 +20,23 @@ void FunctionGen::createArgumentAllocas(Function *F, const std::vector<std::tupl
std::string ArgName = std::get<0>(Args[Idx]);
std::string ArgTypeStr = std::get<1>(Args[Idx]);
bool IsRef = std::get<2>(Args[Idx]);
-
+
Value *ArgVal = &(*AI);
ArgVal->setName(ArgName);
if (IsRef) {
NamedValues[ArgName] = ArgVal;
- } else {
- Type *ArgType = getLLVMType(ArgTypeStr);
- IRBuilder<> TmpB(&F->getEntryBlock(), F->getEntryBlock().begin());
- AllocaInst *Alloca = TmpB.CreateAlloca(ArgType, nullptr, ArgName);
-
- Builder.CreateStore(ArgVal, Alloca);
- NamedValues[ArgName] = Alloca;
+ Symbols[ArgName] = {ArgVal, ArgTypeStr, false};
+ continue;
}
+
+ Type *ArgType = getLLVMType(ArgTypeStr);
+ IRBuilder<> TmpB(&F->getEntryBlock(), F->getEntryBlock().begin());
+ AllocaInst *Alloca = TmpB.CreateAlloca(ArgType, nullptr, ArgName);
+
+ Builder.CreateStore(ArgVal, Alloca);
+ NamedValues[ArgName] = Alloca;
+ Symbols[ArgName] = {Alloca, ArgTypeStr, false};
}
}
@@ -48,23 +52,28 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) {
Type *RetType = getLLVMType(Proto->getReturnType());
FunctionType *FT = FunctionType::get(RetType, ArgTypes, false);
- Function *F = Function::Create(FT, Function::ExternalLinkage, Proto->getName(), &Module);
+ Function *F = Module.getFunction(Proto->getName());
+ if (!F) {
+ F = Function::Create(FT, Function::ExternalLinkage, Proto->getName(), &Module);
+ }
unsigned Idx = 0;
for (auto &Arg : F->args()) {
- if (Idx < Proto->getArgs().size())
+ if (Idx < Proto->getArgs().size()) {
Arg.setName(std::get<0>(Proto->getArgs()[Idx++]));
+ }
}
return F;
}
-Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
+Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
const std::function<void(StmtAST*)> &StmtEmitter) {
PrototypeAST *Proto = FuncAST->getProto();
Function *TheFunction = Module.getFunction(Proto->getName());
- if (!TheFunction)
+ if (!TheFunction) {
TheFunction = emitPrototype(Proto);
+ }
if (!TheFunction) return nullptr;
if (!TheFunction->empty()) {
@@ -76,8 +85,10 @@ Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
Builder.SetInsertPoint(BB);
std::map<std::string, llvm::Value*> OldNamedValues = NamedValues;
+ std::map<std::string, SymbolInfo> OldSymbols = Symbols;
NamedValues.clear();
-
+ Symbols.clear();
+
createArgumentAllocas(TheFunction, Proto->getArgs());
for (const auto &Stmt : FuncAST->getBody()) {
@@ -85,19 +96,24 @@ Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
}
if (!Builder.GetInsertBlock()->getTerminator()) {
- if (Proto->getReturnType() == "VOID")
+ if (Proto->getReturnType() == "VOID") {
Builder.CreateRetVoid();
- else
+ } else {
Builder.CreateRet(Constant::getNullValue(TheFunction->getReturnType()));
+ }
}
verifyFunction(*TheFunction);
NamedValues = OldNamedValues;
+ Symbols = OldSymbols;
return TheFunction;
}
-static Value *GenerateCall(llvm::Module &Module, llvm::IRBuilder<> &Builder, llvm::LLVMContext &Context,
- const std::string &CalleeName, const std::vector<llvm::Value*> &Args) {
+static Value *GenerateCall(llvm::Module &Module,
+ llvm::IRBuilder<> &Builder,
+ llvm::LLVMContext &Context,
+ const std::string &CalleeName,
+ const std::vector<llvm::Value*> &Args) {
Function *CalleeF = Module.getFunction(CalleeName);
if (!CalleeF) {
std::vector<Type*> ArgTypes;
diff --git a/lib/CodeGen/TypeSystem.cc b/lib/CodeGen/TypeSystem.cc
new file mode 100644
index 0000000..59dcc18
--- /dev/null
+++ b/lib/CodeGen/TypeSystem.cc
@@ -0,0 +1,156 @@
+#include "cps/TypeSystem.h"
+#include "llvm/IR/Constants.h"
+#include <utility>
+
+using namespace llvm;
+using namespace cps;
+
+bool TypeInfo::isNumeric() const {
+ return Kind == TypeKind::Integer || Kind == TypeKind::Real;
+}
+
+bool TypeInfo::isIntegral() const {
+ return Kind == TypeKind::Integer || Kind == TypeKind::Char;
+}
+
+bool TypeInfo::isReal() const {
+ return Kind == TypeKind::Real;
+}
+
+bool TypeInfo::isBoolean() const {
+ return Kind == TypeKind::Boolean;
+}
+
+bool TypeInfo::isString() const {
+ return Kind == TypeKind::String;
+}
+
+bool TypeInfo::isChar() const {
+ return Kind == TypeKind::Char;
+}
+
+bool TypeInfo::isVoid() const {
+ return Kind == TypeKind::Void;
+}
+
+TypeSystem::TypeSystem(LLVMContext &Ctx) : Context(Ctx) {
+ registerBuiltins();
+}
+
+void TypeSystem::registerBuiltins() {
+ registerType("INTEGER",
+ Type::getInt64Ty(Context),
+ 8,
+ TypeKind::Integer,
+ true,
+ false,
+ true);
+
+ registerType("REAL",
+ Type::getDoubleTy(Context),
+ 8,
+ TypeKind::Real,
+ true,
+ false,
+ true);
+
+ registerType("BOOLEAN",
+ Type::getInt1Ty(Context),
+ 1,
+ TypeKind::Boolean,
+ true,
+ false,
+ true);
+
+ registerType("STRING",
+ PointerType::getUnqual(Context),
+ 8,
+ TypeKind::String,
+ true,
+ true,
+ true);
+
+ registerType("CHAR",
+ Type::getInt8Ty(Context),
+ 1,
+ TypeKind::Char,
+ true,
+ false,
+ true);
+
+ registerType("VOID",
+ Type::getVoidTy(Context),
+ 0,
+ TypeKind::Void,
+ false,
+ false,
+ true);
+}
+
+const TypeInfo *TypeSystem::resolve(const std::string &TypeName) const {
+ auto It = Types.find(TypeName);
+ if (It == Types.end()) {
+ return nullptr;
+ }
+ return &It->second;
+}
+
+bool TypeSystem::hasType(const std::string &TypeName) const {
+ return resolve(TypeName) != nullptr;
+}
+
+const TypeInfo *TypeSystem::registerType(const std::string &TypeName,
+ Type *LLVMType,
+ uint64_t ElementSize,
+ TypeKind Kind,
+ bool Printable,
+ bool ReferenceLike,
+ bool Builtin) {
+ TypeInfo Info;
+ Info.Name = TypeName;
+ Info.LLVMType = LLVMType;
+ Info.ElementSize = ElementSize;
+ Info.Kind = Kind;
+ Info.Printable = Printable;
+ Info.Builtin = Builtin;
+ Info.ReferenceLike = ReferenceLike;
+
+ auto Result = Types.insert_or_assign(TypeName, std::move(Info));
+ return &Result.first->second;
+}
+
+Type *TypeSystem::getLLVMType(const std::string &TypeName) const {
+ const TypeInfo *Info = resolve(TypeName);
+ return Info ? Info->LLVMType : nullptr;
+}
+
+uint64_t TypeSystem::getElementSize(const std::string &TypeName) const {
+ const TypeInfo *Info = resolve(TypeName);
+ return Info ? Info->ElementSize : 0;
+}
+
+Constant *TypeSystem::getZeroValue(const std::string &TypeName) const {
+ const TypeInfo *Info = resolve(TypeName);
+ if (!Info || !Info->LLVMType || Info->LLVMType->isVoidTy()) {
+ return nullptr;
+ }
+
+ switch (Info->Kind) {
+ case TypeKind::Integer:
+ return ConstantInt::get(Context, APInt(64, 0));
+ case TypeKind::Real:
+ return ConstantFP::get(Context, APFloat(0.0));
+ case TypeKind::Boolean:
+ return ConstantInt::get(Context, APInt(1, 0));
+ case TypeKind::Char:
+ return ConstantInt::get(Context, APInt(8, 0));
+ case TypeKind::String:
+ return ConstantPointerNull::get(cast<PointerType>(Info->LLVMType));
+ case TypeKind::Void:
+ return nullptr;
+ case TypeKind::Custom:
+ return Constant::getNullValue(Info->LLVMType);
+ }
+
+ return Constant::getNullValue(Info->LLVMType);
+}