aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/ArrayHandler.cc14
-rw-r--r--lib/CodeGen/CodeGen.cc205
-rw-r--r--lib/CodeGen/Designator.cc179
-rw-r--r--lib/CodeGen/FunctionGen.cc10
-rw-r--r--lib/CodeGen/RuntimeCheck.cc26
-rw-r--r--lib/CodeGen/TypeSystem.cc269
6 files changed, 564 insertions, 139 deletions
diff --git a/lib/CodeGen/ArrayHandler.cc b/lib/CodeGen/ArrayHandler.cc
index 7977563..d21d91c 100644
--- a/lib/CodeGen/ArrayHandler.cc
+++ b/lib/CodeGen/ArrayHandler.cc
@@ -84,6 +84,10 @@ void ArrayHandler::emitArrayDeclare(ArrayDeclareStmtAST *Stmt, CodeGen &CG) {
CG.reportError("Unknown array element type %s", Stmt->getType().c_str());
return;
}
+ if (Types.lookupEnumConstant(Name)) {
+ CG.reportError("'%s' is an enum value and cannot be declared as an array", Name.c_str());
+ return;
+ }
std::vector<Value*> Lows;
std::vector<Value*> Highs;
@@ -199,8 +203,7 @@ void ArrayHandler::emitArrayAssign(ArrayAssignStmtAST *Stmt, CodeGen &CG) {
Stmt->getLine(), CG, ElemTypeName);
if (!ElemPtr) return;
- Value *Val = CG.emitExpr(Stmt->getExpr());
- Val = CG.coerceValueToType(Val, Types.resolve(ElemTypeName));
+ Value *Val = CG.emitCoercedExpr(Stmt->getExpr(), Types.resolve(ElemTypeName));
if (!Val) return;
Builder->CreateStore(Val, ElemPtr);
@@ -256,6 +259,13 @@ bool ArrayHandler::tryEmitArrayOutput(ExprAST *Expr, CodeGen &CG) {
return false;
}
+ const TypeInfo *ElemInfo = Types.resolve(getMetadata(Name)->ElementTypeName);
+ if (ElemInfo && !ElemInfo->isOutputtable()) {
+ CG.reportError("Cannot OUTPUT array %s of type %s; output individual fields",
+ Name.c_str(), ElemInfo->Name.c_str());
+ return true; // diagnosed
+ }
+
std::vector<Value*> Indices;
if (IndexExprs && !emitCheckedIndices(Name, *IndexExprs, Line, false, CG, Indices)) {
return true; // diagnosed
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index 8940e63..ae8efa2 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -163,15 +163,6 @@ 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 = Symbols.find(Name);
- return It == Symbols.end() ? nullptr : It->second.Storage;
-}
-
const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) const {
if (!Expr) return nullptr;
@@ -183,7 +174,11 @@ const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) const {
if (auto *Var = dynamic_cast<VariableExprAST*>(Expr)) {
const SymbolInfo *Info = getSymbolInfo(Var->getName());
- return Info ? resolveType(Info->TypeName) : nullptr;
+ if (Info) return resolveType(Info->TypeName);
+ if (const EnumConstant *EC = Types->lookupEnumConstant(Var->getName())) {
+ return resolveType(EC->TypeName);
+ }
+ return nullptr;
}
if (auto *Arr = dynamic_cast<ArrayAccessExprAST*>(Expr)) {
@@ -217,6 +212,15 @@ const TypeInfo *CodeGen::getExprTypeInfo(ExprAST *Expr) const {
const TypeInfo *L = getExprTypeInfo(Bin->getLHS());
const TypeInfo *R = getExprTypeInfo(Bin->getRHS());
+ // Enum arithmetic: E +/- INTEGER (enum on the left) yields the enum;
+ // every other user-kind combination has no type (emission rejects it).
+ if ((L && L->isUserKind()) || (R && R->isUserKind())) {
+ if (L && L->isEnum() && R && R->Kind == TypeKind::Integer &&
+ (Bin->getOp() == '+' || Bin->getOp() == '-')) {
+ return L;
+ }
+ return nullptr;
+ }
if ((L && L->Kind == TypeKind::Real) || (R && R->Kind == TypeKind::Real)) {
return resolveType("REAL");
}
@@ -327,12 +331,15 @@ Value *CodeGen::coerceValueToType(Value *Val, const TypeInfo *TargetInfo) {
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;
+ // Enum/Record/Pointer identity lives in the type NAME; at this level
+ // an enum is a plain i64 and a pointer a plain ptr, so nothing can be
+ // checked here. emitCoercedExpr is the only legitimate door.
+ case TypeKind::Enum:
+ case TypeKind::Record:
+ case TypeKind::Pointer:
+ reportError("Internal: a %s value reached representation coercion without a name-level check",
+ TargetInfo->Name.c_str());
+ return nullptr;
}
reportError("Cannot coerce value of LLVM type to target type %s",
@@ -346,6 +353,11 @@ void CodeGen::emitDeclareStmt(DeclareStmtAST *Stmt) {
reportError("Unknown type %s", Stmt->getType().c_str());
return;
}
+ if (Types->lookupEnumConstant(Stmt->getName())) {
+ reportError("'%s' is an enum value and cannot be declared as a variable",
+ Stmt->getName().c_str());
+ return;
+ }
Function *TheFunction = Builder->GetInsertBlock()->getParent();
AllocaInst *Alloca = CreateEntryBlockAlloca(TheFunction, Info->LLVMType, Stmt->getName());
@@ -374,35 +386,42 @@ Value *CodeGen::emitStringNullGuard(Value *StrVal) {
void CodeGen::emitOutputValue(Value *Val, const TypeInfo *Info, bool AppendNewline) {
if (!Val || !Info) return;
- if (!Info->Printable && Info->Kind == TypeKind::Custom) {
- reportError("OUTPUT for custom type %s is not implemented yet", Info->Name.c_str());
- return;
- }
std::vector<Value*> Args;
Value *Fmt = nullptr;
- if (Info->isReal()) {
+ // Exhaustive over TypeKind (no default): the compiler warns when a new
+ // kind is added without deciding its OUTPUT story.
+ switch (Info->Kind) {
+ case TypeKind::Real:
Fmt = AppendNewline
? PrintfFloatFormatStr
: Builder->CreateGlobalStringPtr("%f", "fmt_flt_inline", 0, TheModule.get());
Args.push_back(Fmt);
Args.push_back(Val);
- } else if (Info->isBoolean()) {
+ break;
+
+ case TypeKind::Boolean: {
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()) {
+ break;
+ }
+
+ case TypeKind::String: {
Value *StrVal = emitStringNullGuard(Val);
Fmt = AppendNewline
? PrintfStringFormatStr
: Builder->CreateGlobalStringPtr("%s", "fmt_str_inline", 0, TheModule.get());
Args.push_back(Fmt);
Args.push_back(StrVal);
- } else if (Info->isChar()) {
+ break;
+ }
+
+ case TypeKind::Char: {
Value *CharVal = coerceValueToType(Val, resolveType("CHAR"));
Value *Promoted = Builder->CreateZExt(CharVal, Type::getInt32Ty(*TheContext), "char_for_printf");
Fmt = AppendNewline
@@ -410,13 +429,32 @@ void CodeGen::emitOutputValue(Value *Val, const TypeInfo *Info, bool AppendNewli
: Builder->CreateGlobalStringPtr("%c", "fmt_chr_inline", 0, TheModule.get());
Args.push_back(Fmt);
Args.push_back(Promoted);
- } else {
- Value *IntVal = coerceValueToType(Val, resolveType("INTEGER"));
+ break;
+ }
+
+ case TypeKind::Integer:
+ case TypeKind::Enum: { // an enum prints its ordinal (user decision)
+ Value *IntVal = Info->isEnum() ? Val : coerceValueToType(Val, resolveType("INTEGER"));
Fmt = AppendNewline
? PrintfFormatStr
: Builder->CreateGlobalStringPtr("%lld", "fmt_int_inline", 0, TheModule.get());
Args.push_back(Fmt);
Args.push_back(IntVal);
+ break;
+ }
+
+ case TypeKind::Record:
+ reportError("Cannot OUTPUT a value of record type %s; output its fields individually",
+ Info->Name.c_str());
+ return;
+
+ case TypeKind::Pointer:
+ reportError("Cannot OUTPUT a value of pointer type %s", Info->Name.c_str());
+ return;
+
+ case TypeKind::Void:
+ reportError("Cannot OUTPUT a VOID value");
+ return;
}
Builder->CreateCall(PrintfFunc, Args);
@@ -428,6 +466,9 @@ void CodeGen::compile(const std::vector<std::unique_ptr<StmtAST>> &Statements) {
BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", F);
Builder->SetInsertPoint(BB);
+ // User types first: prototypes may name them in parameters/returns.
+ runTypePrePass(Statements);
+
// Pre-register every top-level FUNCTION/PROCEDURE prototype so calls may
// precede definitions.
for (const auto &Stmt : Statements) {
@@ -479,6 +520,11 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
if (auto *Var = dynamic_cast<VariableExprAST*>(Expr)) {
const SymbolInfo *Info = getSymbolInfo(Var->getName());
if (!Info) {
+ // Enum values are bare identifiers; collisions with variables are
+ // rejected at declaration time, so the order here cannot shadow.
+ if (const EnumConstant *EC = Types->lookupEnumConstant(Var->getName())) {
+ return ConstantInt::get(*TheContext, APInt(64, static_cast<uint64_t>(EC->Ordinal), true));
+ }
reportError("Unknown variable name %s", Var->getName().c_str());
return nullptr;
}
@@ -504,16 +550,23 @@ 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) {
- Operand = coerceValueToType(Operand, resolveType("BOOLEAN"));
+ Value *Operand = emitCoercedExpr(Unary->getOperand(), resolveType("BOOLEAN"));
+ if (!Operand) return nullptr;
return Builder->CreateNot(Operand, "nottmp");
}
+ return nullptr;
}
if (auto *Bin = dynamic_cast<BinaryExprAST*>(Expr)) {
+ // Enum/Record/Pointer operands never reach ArithmeticHandler or the
+ // '&' path: their admissible operations are decided by name here.
+ const TypeInfo *LT = getExprTypeInfo(Bin->getLHS());
+ const TypeInfo *RT = getExprTypeInfo(Bin->getRHS());
+ if ((LT && LT->isUserKind()) || (RT && RT->isUserKind())) {
+ return emitUserKindBinaryOp(Bin, LT, RT);
+ }
+
Value *L = emitExpr(Bin->getLHS());
Value *R = emitExpr(Bin->getRHS());
if (!L || !R) return nullptr;
@@ -535,41 +588,47 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
}
}
if (Name == "LENGTH") {
- return StrHandler->emitLength(emitExpr(Call->getArgs()[0].get()));
+ Value *Str = emitCoercedExpr(Call->getArgs()[0].get(), resolveType("STRING"));
+ if (!Str) return nullptr;
+ return StrHandler->emitLength(Str);
}
if (Name == "MID") {
- 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"));
+ Value *Str = emitCoercedExpr(Call->getArgs()[0].get(), resolveType("STRING"));
+ Value *Start = emitCoercedExpr(Call->getArgs()[1].get(), resolveType("INTEGER"));
+ Value *Len = emitCoercedExpr(Call->getArgs()[2].get(), resolveType("INTEGER"));
if (!Str || !Start || !Len) return nullptr;
return StrHandler->emitMid(Str, Start, Len);
}
if (Name == "RIGHT") {
- Value *Str = emitExpr(Call->getArgs()[0].get());
- Value *Len = coerceValueToType(emitExpr(Call->getArgs()[1].get()), resolveType("INTEGER"));
+ Value *Str = emitCoercedExpr(Call->getArgs()[0].get(), resolveType("STRING"));
+ Value *Len = emitCoercedExpr(Call->getArgs()[1].get(), resolveType("INTEGER"));
if (!Str || !Len) return nullptr;
return StrHandler->emitRight(Str, Len);
}
if (Name == "LEFT") {
- Value *Str = emitExpr(Call->getArgs()[0].get());
- Value *Len = coerceValueToType(emitExpr(Call->getArgs()[1].get()), resolveType("INTEGER"));
+ Value *Str = emitCoercedExpr(Call->getArgs()[0].get(), resolveType("STRING"));
+ Value *Len = emitCoercedExpr(Call->getArgs()[1].get(), resolveType("INTEGER"));
if (!Str || !Len) return nullptr;
return StrHandler->emitLeft(Str, Len);
}
if (Name == "LCASE") {
- Value *Str = emitExpr(Call->getArgs()[0].get());
+ Value *Str = emitCoercedExpr(Call->getArgs()[0].get(), resolveType("STRING"));
if (!Str) return nullptr;
return StrHandler->emitLCase(Str);
}
if (Name == "UCASE") {
- Value *Str = emitExpr(Call->getArgs()[0].get());
+ Value *Str = emitCoercedExpr(Call->getArgs()[0].get(), resolveType("STRING"));
if (!Str) return nullptr;
return StrHandler->emitUCase(Str);
}
if (Name == "ASC") {
+ const TypeInfo *ArgType = getExprTypeInfo(Call->getArgs()[0].get());
+ if (ArgType && ArgType->isUserKind()) {
+ reportError("ASC expects a CHAR or STRING (got %s)", ArgType->Name.c_str());
+ return nullptr;
+ }
Value *ArgVal = emitExpr(Call->getArgs()[0].get());
if (!ArgVal) return nullptr;
- const TypeInfo *ArgType = getExprTypeInfo(Call->getArgs()[0].get());
Value *CharVal = nullptr;
if (ArgType && ArgType->isChar()) {
CharVal = coerceValueToType(ArgVal, resolveType("CHAR"));
@@ -580,17 +639,22 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
return coerceValueToType(AscVal, resolveType("INTEGER"));
}
if (Name == "CHR") {
- Value *IntVal = coerceValueToType(emitExpr(Call->getArgs()[0].get()), resolveType("INTEGER"));
+ Value *IntVal = emitCoercedExpr(Call->getArgs()[0].get(), resolveType("INTEGER"));
if (!IntVal) return nullptr;
Value *CharVal = Builder->CreateTrunc(IntVal, Type::getInt8Ty(*TheContext), "chr_val");
return coerceValueToType(CharVal, resolveType("STRING"));
}
if (Name == "IS_NUM") {
- Value *Str = emitExpr(Call->getArgs()[0].get());
+ Value *Str = emitCoercedExpr(Call->getArgs()[0].get(), resolveType("STRING"));
if (!Str) return nullptr;
return StrConvHandler->emitIsNum(Str);
}
if (Name == "NUM_TO_STR") {
+ const TypeInfo *ArgType = getExprTypeInfo(Call->getArgs()[0].get());
+ if (ArgType && ArgType->isUserKind()) {
+ reportError("NUM_TO_STR expects a number (got %s)", ArgType->Name.c_str());
+ return nullptr;
+ }
Value *NumV = emitExpr(Call->getArgs()[0].get());
if (!NumV) return nullptr;
bool IsReal = NumV->getType()->isDoubleTy();
@@ -600,7 +664,7 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
return StrConvHandler->emitNumToStr(NumV, IsReal);
}
if (Name == "STR_TO_NUM") {
- Value *Str = emitExpr(Call->getArgs()[0].get());
+ Value *Str = emitCoercedExpr(Call->getArgs()[0].get(), resolveType("STRING"));
if (!Str) return nullptr;
return StrConvHandler->emitStrToNum(Str, true);
}
@@ -609,8 +673,7 @@ Value *CodeGen::emitExpr(ExprAST *Expr) {
reportError("Cannot use a whole array as the EOF filename");
return nullptr;
}
- Value *FileName = coerceValueToType(emitExpr(Call->getArgs()[0].get()),
- resolveType("STRING"));
+ Value *FileName = emitCoercedExpr(Call->getArgs()[0].get(), resolveType("STRING"));
if (!FileName) return nullptr;
return Files->emitEof(FileName, Call->getLine());
}
@@ -681,7 +744,7 @@ bool CodeGen::marshalCallArgs(const std::string &Callee,
}
Out.push_back(Info->Storage);
} else {
- Value *V = coerceValueToType(emitExpr(ArgExpr), resolveType(TypeName));
+ Value *V = emitCoercedExpr(ArgExpr, resolveType(TypeName));
if (!V) return false;
Out.push_back(V);
}
@@ -690,11 +753,9 @@ bool CodeGen::marshalCallArgs(const std::string &Callee,
}
void CodeGen::emitIfStmt(IfStmtAST *Stmt) {
- Value *CondV = emitExpr(Stmt->getCond());
+ Value *CondV = emitCoercedExpr(Stmt->getCond(), resolveType("BOOLEAN"));
if (!CondV) return;
- CondV = coerceValueToType(CondV, resolveType("BOOLEAN"));
-
Function *TheFunction = Builder->GetInsertBlock()->getParent();
BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction);
BasicBlock *ElseBB = BasicBlock::Create(*TheContext, "else", TheFunction);
@@ -723,9 +784,8 @@ void CodeGen::emitWhileStmt(WhileStmtAST *Stmt) {
Builder->CreateBr(CondBB);
Builder->SetInsertPoint(CondBB);
- Value *CondV = emitExpr(Stmt->getCond());
+ Value *CondV = emitCoercedExpr(Stmt->getCond(), resolveType("BOOLEAN"));
if (!CondV) return;
- CondV = coerceValueToType(CondV, resolveType("BOOLEAN"));
Builder->CreateCondBr(CondV, LoopBB, AfterBB);
@@ -753,9 +813,8 @@ void CodeGen::emitRepeatStmt(RepeatStmtAST *Stmt) {
Builder->CreateBr(CondBB);
Builder->SetInsertPoint(CondBB);
- Value *CondV = emitExpr(Stmt->getCond());
+ Value *CondV = emitCoercedExpr(Stmt->getCond(), resolveType("BOOLEAN"));
if (!CondV) return;
- CondV = coerceValueToType(CondV, resolveType("BOOLEAN"));
Builder->CreateCondBr(CondV, AfterBB, LoopBB);
@@ -776,7 +835,7 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
return;
}
- Value *StartVal = coerceValueToType(emitExpr(Stmt->getStart()), resolveType("INTEGER"));
+ Value *StartVal = emitCoercedExpr(Stmt->getStart(), resolveType("INTEGER"));
if (!StartVal) return;
Value *Alloca = Symbol->Storage;
@@ -785,7 +844,7 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
// STEP is evaluated exactly once, before the loop.
Value *StepVal = nullptr;
if (Stmt->getStep()) {
- StepVal = coerceValueToType(emitExpr(Stmt->getStep()), resolveType("INTEGER"));
+ StepVal = emitCoercedExpr(Stmt->getStep(), resolveType("INTEGER"));
if (!StepVal) return;
} else {
StepVal = ConstantInt::get(*TheContext, APInt(64, 1));
@@ -800,7 +859,7 @@ void CodeGen::emitForStmt(ForStmtAST *Stmt) {
Builder->SetInsertPoint(CondBB);
Value *CurVar = Builder->CreateLoad(Type::getInt64Ty(*TheContext), Alloca, VarName.c_str());
- Value *EndVal = coerceValueToType(emitExpr(Stmt->getEnd()), resolveType("INTEGER"));
+ Value *EndVal = emitCoercedExpr(Stmt->getEnd(), resolveType("INTEGER"));
if (!EndVal) return;
// The loop direction depends on the STEP value at run time.
@@ -865,12 +924,13 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
if (auto *Ret = dynamic_cast<ReturnStmtAST*>(Stmt)) {
Value *RetVal = nullptr;
if (Ret->getRetVal()) {
- RetVal = emitExpr(Ret->getRetVal());
Function *F = Builder->GetInsertBlock()->getParent();
if (const FuncSig *Sig = FuncGen->getSignature(F->getName().str())) {
- RetVal = coerceValueToType(RetVal, resolveType(Sig->ReturnTypeName));
- if (!RetVal) return;
+ RetVal = emitCoercedExpr(Ret->getRetVal(), resolveType(Sig->ReturnTypeName));
+ } else {
+ RetVal = emitExpr(Ret->getRetVal());
}
+ if (!RetVal) return;
}
FuncGen->emitReturn(Ret, RetVal);
return;
@@ -892,9 +952,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
return;
}
- Value *Val = emitExpr(Assign->getExpr());
- const TypeInfo *TargetType = resolveType(Info->TypeName);
- Val = coerceValueToType(Val, TargetType);
+ Value *Val = emitCoercedExpr(Assign->getExpr(), resolveType(Info->TypeName));
if (!Val) return;
Builder->CreateStore(Val, Info->Storage);
@@ -943,10 +1001,14 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
Args.push_back(CharFmt);
Args.push_back(Info->Storage);
Builder->CreateCall(ScanfFunc, Args);
- } else {
+ } else if (TypeInfo->Kind == TypeKind::Integer) {
Args.push_back(ScanfFormatStr);
Args.push_back(Info->Storage);
Builder->CreateCall(ScanfFunc, Args);
+ } else {
+ // Enum/Record/Pointer and any future kind: scanf'ing raw bytes
+ // into typed storage would corrupt it — reject explicitly.
+ reportError("INPUT is not supported for a value of type %s", TypeInfo->Name.c_str());
}
return;
}
@@ -974,7 +1036,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
reportError("Cannot use a whole array as the OPENFILE filename");
return;
}
- Value *Name = coerceValueToType(emitExpr(Open->getFileName()), resolveType("STRING"));
+ Value *Name = emitCoercedExpr(Open->getFileName(), resolveType("STRING"));
if (!Name) return;
Files->emitOpen(Name, Open->getMode(), Open->getLine());
return;
@@ -999,7 +1061,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
reportError("Cannot use a whole array as the READFILE filename");
return;
}
- Value *Name = coerceValueToType(emitExpr(Read->getFileName()), resolveType("STRING"));
+ Value *Name = emitCoercedExpr(Read->getFileName(), resolveType("STRING"));
if (!Name) return;
Value *LineStr = Files->emitRead(Name, Read->getLine());
if (!LineStr) return;
@@ -1012,8 +1074,8 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
reportError("Cannot use a whole array in WRITEFILE");
return;
}
- Value *Name = coerceValueToType(emitExpr(Write->getFileName()), resolveType("STRING"));
- Value *Data = coerceValueToType(emitExpr(Write->getData()), resolveType("STRING"));
+ Value *Name = emitCoercedExpr(Write->getFileName(), resolveType("STRING"));
+ Value *Data = emitCoercedExpr(Write->getData(), resolveType("STRING"));
if (!Name || !Data) return;
Files->emitWrite(Name, Data, Write->getLine());
return;
@@ -1024,7 +1086,7 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
reportError("Cannot use a whole array as the CLOSEFILE filename");
return;
}
- Value *Name = coerceValueToType(emitExpr(Close->getFileName()), resolveType("STRING"));
+ Value *Name = emitCoercedExpr(Close->getFileName(), resolveType("STRING"));
if (!Name) return;
Files->emitClose(Name, Close->getLine());
return;
@@ -1047,12 +1109,13 @@ void CodeGen::emitStmt(StmtAST *Stmt) {
return;
}
- // TYPE-system stubs: parsed but not yet wired (phases C/D of the TYPE work).
+ // TYPE declarations are registered by compile()'s pre-pass (the parser
+ // guarantees they are top-level); nothing is emitted here.
if (dynamic_cast<EnumTypeDeclAST*>(Stmt) || dynamic_cast<PointerTypeDeclAST*>(Stmt) ||
dynamic_cast<RecordTypeDeclAST*>(Stmt)) {
- reportError("TYPE declarations are not implemented yet");
return;
}
+ // TYPE-system stub: wired in the record/lvalue phase.
if (dynamic_cast<DesignatorAssignStmtAST*>(Stmt)) {
reportError("Assignment to record fields / pointer targets is not implemented yet");
return;
diff --git a/lib/CodeGen/Designator.cc b/lib/CodeGen/Designator.cc
new file mode 100644
index 0000000..58898fe
--- /dev/null
+++ b/lib/CodeGen/Designator.cc
@@ -0,0 +1,179 @@
+// Type-name-level emission helpers for the user-defined TYPE system:
+// the type pre-pass, the admission gate for assignments/arguments, and the
+// binary-operator interception for Enum/Record/Pointer operands.
+// These are CodeGen methods; the file is split out to keep the hub
+// dispatch-only.
+#include "cps/CodeGen.h"
+#include "cps/TypeAST.h"
+#include "cps/Lexer.h"
+
+using namespace llvm;
+using namespace cps;
+
+namespace {
+
+// Operator spelling for diagnostics (raw ASCII or a keyword token).
+std::string opToText(int Op) {
+ switch (Op) {
+ case tok_eq: return "=";
+ case tok_ne: return "<>";
+ case tok_le: return "<=";
+ case tok_ge: return ">=";
+ case tok_and: return "AND";
+ case tok_or: return "OR";
+ case tok_div: return "DIV";
+ case tok_mod: return "MOD";
+ default:
+ if (Op >= 0) return std::string(1, static_cast<char>(Op));
+ return "?";
+ }
+}
+
+} // namespace
+
+// Registers every top-level TYPE declaration before prototypes are emitted.
+// Two passes so a pointer TYPE may reference a type declared later
+// (TYPE NodePtr = ^Node before TYPE Node — required for linked structures);
+// by-value record fields still require their record type to be complete,
+// which pass B's source order enforces.
+void CodeGen::runTypePrePass(const std::vector<std::unique_ptr<StmtAST>> &Statements) {
+ std::string Err;
+
+ for (const auto &S : Statements) {
+ bool Ok = true;
+ if (auto *E = dynamic_cast<EnumTypeDeclAST*>(S.get()))
+ Ok = Types->declareUserType(E->getName(), TypeKind::Enum, Err);
+ else if (auto *P = dynamic_cast<PointerTypeDeclAST*>(S.get()))
+ Ok = Types->declareUserType(P->getName(), TypeKind::Pointer, Err);
+ else if (auto *R = dynamic_cast<RecordTypeDeclAST*>(S.get()))
+ Ok = Types->declareUserType(R->getName(), TypeKind::Record, Err);
+ if (!Ok) reportError("%s", Err.c_str());
+ }
+
+ for (const auto &S : Statements) {
+ bool Ok = true;
+ if (auto *E = dynamic_cast<EnumTypeDeclAST*>(S.get())) {
+ Ok = Types->defineEnum(E->getName(), E->getValueNames(), Err);
+ } else if (auto *P = dynamic_cast<PointerTypeDeclAST*>(S.get())) {
+ Ok = Types->definePointer(P->getName(), P->getPointeeTypeName(), Err);
+ } else if (auto *R = dynamic_cast<RecordTypeDeclAST*>(S.get())) {
+ std::vector<std::pair<std::string, std::string>> Fields;
+ for (const RecordFieldDecl &F : R->getFields())
+ Fields.emplace_back(F.Name, F.TypeName);
+ Ok = Types->defineRecord(R->getName(), Fields, Err);
+ }
+ if (!Ok) reportError("%s", Err.c_str());
+ }
+}
+
+// The single name-level admission gate. Targets of a user kind demand exact
+// type-name equality (their representations are indistinguishable at the
+// LLVM level); builtin targets additionally reject user-kind sources, then
+// keep the existing representation coercions unchanged.
+Value *CodeGen::emitCoercedExpr(ExprAST *E, const TypeInfo *Target) {
+ if (!E || !Target) return nullptr;
+
+ const TypeInfo *Src = getExprTypeInfo(E);
+
+ if (Target->isUserKind()) {
+ // ^x into a pointer target compares pointee names, not type names;
+ // wired in the pointer phase.
+ if (Target->isPointer() && dynamic_cast<AddrOfExprAST*>(E)) {
+ return emitExpr(E);
+ }
+ if (!Src) {
+ // Emit anyway: an inadmissible sub-expression (e.g. enum * 2)
+ // then reports its own, more specific diagnostic.
+ if (emitExpr(E)) {
+ reportError("Cannot determine the type of the value used where %s is expected",
+ Target->Name.c_str());
+ }
+ return nullptr;
+ }
+ if (Src->Name != Target->Name) {
+ reportError("Cannot use a value of type %s where %s is expected",
+ Src->Name.c_str(), Target->Name.c_str());
+ return nullptr;
+ }
+ return emitExpr(E); // same nominal type: no conversion needed
+ }
+
+ if (Src && Src->isUserKind()) {
+ reportError("Cannot use a value of type %s where %s is expected",
+ Src->Name.c_str(), Target->Name.c_str());
+ return nullptr;
+ }
+ return coerceValueToType(emitExpr(E), Target);
+}
+
+// Binary operators with at least one Enum/Record/Pointer operand. Decides
+// admissibility by type name and emits directly; ArithmeticHandler stays
+// ignorant of user kinds.
+Value *CodeGen::emitUserKindBinaryOp(BinaryExprAST *Bin, const TypeInfo *LT, const TypeInfo *RT) {
+ int Op = Bin->getOp();
+ const char *LName = LT ? LT->Name.c_str() : "?";
+ const char *RName = RT ? RT->Name.c_str() : "?";
+
+ if ((LT && LT->isRecord()) || (RT && RT->isRecord())) {
+ reportError("Operator %s cannot be applied to a record value (type %s)",
+ opToText(Op).c_str(), (LT && LT->isRecord()) ? LName : RName);
+ return nullptr;
+ }
+
+ if ((LT && LT->isPointer()) || (RT && RT->isPointer())) {
+ bool SameName = LT && RT && LT->isPointer() && RT->isPointer() && LT->Name == RT->Name;
+ if (SameName && (Op == tok_eq || Op == tok_ne)) {
+ Value *L = emitExpr(Bin->getLHS());
+ Value *R = emitExpr(Bin->getRHS());
+ if (!L || !R) return nullptr;
+ return Op == tok_eq ? Builder->CreateICmpEQ(L, R, "ptr_eq")
+ : Builder->CreateICmpNE(L, R, "ptr_ne");
+ }
+ reportError("Pointer values support only = and <> between the same pointer type (got %s %s %s)",
+ LName, opToText(Op).c_str(), RName);
+ return nullptr;
+ }
+
+ // At least one enum operand from here on.
+ bool BothSameEnum = LT && RT && LT->isEnum() && RT->isEnum() && LT->Name == RT->Name;
+
+ switch (Op) {
+ case tok_eq: case tok_ne: case '<': case '>': case tok_le: case tok_ge: {
+ if (!BothSameEnum) break;
+ Value *L = emitExpr(Bin->getLHS());
+ Value *R = emitExpr(Bin->getRHS());
+ if (!L || !R) return nullptr;
+ switch (Op) {
+ case tok_eq: return Builder->CreateICmpEQ(L, R, "enum_eq");
+ case tok_ne: return Builder->CreateICmpNE(L, R, "enum_ne");
+ case '<': return Builder->CreateICmpSLT(L, R, "enum_lt");
+ case '>': return Builder->CreateICmpSGT(L, R, "enum_gt");
+ case tok_le: return Builder->CreateICmpSLE(L, R, "enum_le");
+ case tok_ge: return Builder->CreateICmpSGE(L, R, "enum_ge");
+ }
+ return nullptr;
+ }
+
+ case '+': case '-': {
+ // The one legal arithmetic shape (guide §4.2): enum on the left,
+ // INTEGER on the right, result checked against the enum's range.
+ if (!(LT && LT->isEnum() && RT && RT->Kind == TypeKind::Integer)) break;
+ Value *L = emitExpr(Bin->getLHS());
+ Value *R = emitExpr(Bin->getRHS());
+ if (!L || !R) return nullptr;
+ Value *Res = Op == '+' ? Builder->CreateAdd(L, R, "enum_step")
+ : Builder->CreateSub(L, R, "enum_step");
+ RuntimeChecker->emitEnumRangeCheck(Res, LT->asEnum()->ValueNames.size(),
+ LT->Name, Bin->getLine());
+ return Res;
+ }
+
+ default:
+ break;
+ }
+
+ reportError("Operator %s cannot be applied to %s and %s "
+ "(enums allow comparison with the same enum type, and enum + or - INTEGER)",
+ opToText(Op).c_str(), LName, RName);
+ return nullptr;
+}
diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc
index dc238b5..cbaee75 100644
--- a/lib/CodeGen/FunctionGen.cc
+++ b/lib/CodeGen/FunctionGen.cc
@@ -34,6 +34,10 @@ Type *FunctionGen::getLLVMType(const std::string &TypeName) {
void FunctionGen::createArgumentAllocas(Function *F, const std::vector<ParamDecl> &Params) {
Function::arg_iterator AI = F->arg_begin();
for (const ParamDecl &P : Params) {
+ if (Types.lookupEnumConstant(P.Name)) {
+ fprintf(stderr, "Error: parameter '%s' collides with an enum value\n", P.Name.c_str());
+ HadError = true;
+ }
Value *ArgVal = &(*AI);
++AI;
ArgVal->setName(P.Name);
@@ -70,6 +74,12 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) {
HadError = true;
return nullptr;
}
+ if (Types.lookupEnumConstant(Proto->getName())) {
+ fprintf(stderr, "Error: '%s' is an enum value and cannot be a FUNCTION/PROCEDURE name\n",
+ Proto->getName().c_str());
+ HadError = true;
+ return nullptr;
+ }
FuncSig Sig;
Sig.ReturnTypeName = Proto->getReturnType();
diff --git a/lib/CodeGen/RuntimeCheck.cc b/lib/CodeGen/RuntimeCheck.cc
index c2ced87..e6d4bf8 100644
--- a/lib/CodeGen/RuntimeCheck.cc
+++ b/lib/CodeGen/RuntimeCheck.cc
@@ -1,4 +1,5 @@
#include "cps/RuntimeCheck.h"
+#include "cps/TypeSystem.h" // kEnumOrdinalBase
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Constants.h"
@@ -24,6 +25,8 @@ void RuntimeCheck::setupExternalFunctions() {
DivZeroMsg = Builder.CreateGlobalStringPtr("[Fatal] line %d: Division by zero\n", "err_div_zero", 0, &TheModule);
OutOfBoundsMsg = Builder.CreateGlobalStringPtr("[Fatal] line %d: Array index out of bounds\n", "err_bounds", 0, &TheModule);
+ EnumRangeMsg = Builder.CreateGlobalStringPtr("[Fatal] line %d: Value out of range for enum %s\n", "err_enum_range", 0, &TheModule);
+ NullDerefMsg = Builder.CreateGlobalStringPtr("[Fatal] line %d: Dereference of an unset pointer\n", "err_null_deref", 0, &TheModule);
}
void RuntimeCheck::emitErrorAndExit(Value *Condition, Value *Msg, int Line) {
@@ -59,6 +62,27 @@ void RuntimeCheck::emitIndexCheck(Value *Index, Value *Lower, Value *Upper, int
Value *TooLow = Builder.CreateICmpSLT(Index, Lower, "too_low");
Value *TooHigh = Builder.CreateICmpSGT(Index, Upper, "too_high");
Value *OutOfBounds = Builder.CreateOr(TooLow, TooHigh, "out_of_bounds");
-
+
emitErrorAndExit(OutOfBounds, OutOfBoundsMsg, Line);
}
+
+void RuntimeCheck::emitEnumRangeCheck(Value *Ordinal, uint64_t ValueCount,
+ const std::string &TypeName, int Line) {
+ Value *Lo = ConstantInt::get(TheContext, APInt(64, static_cast<uint64_t>(kEnumOrdinalBase), true));
+ Value *Hi = ConstantInt::get(TheContext,
+ APInt(64, static_cast<uint64_t>(kEnumOrdinalBase) + ValueCount, true));
+ Value *TooLow = Builder.CreateICmpSLT(Ordinal, Lo, "enum_too_low");
+ Value *TooHigh = Builder.CreateICmpSGE(Ordinal, Hi, "enum_too_high");
+ Value *OutOfRange = Builder.CreateOr(TooLow, TooHigh, "enum_out_of_range");
+
+ Value *NameStr = Builder.CreateGlobalStringPtr(TypeName, "enum_name", 0, &TheModule);
+ emitErrorAndExit(OutOfRange, EnumRangeMsg,
+ {ConstantInt::get(TheContext, APInt(32, Line)), NameStr});
+}
+
+void RuntimeCheck::emitNullDerefCheck(Value *Ptr, int Line) {
+ Value *IsNull = Builder.CreateICmpEQ(Ptr,
+ ConstantPointerNull::get(PointerType::getUnqual(TheContext)),
+ "ptr_is_null");
+ emitErrorAndExit(IsNull, NullDerefMsg, Line);
+}
diff --git a/lib/CodeGen/TypeSystem.cc b/lib/CodeGen/TypeSystem.cc
index 830ce25..c170be8 100644
--- a/lib/CodeGen/TypeSystem.cc
+++ b/lib/CodeGen/TypeSystem.cc
@@ -5,6 +5,13 @@
using namespace llvm;
using namespace cps;
+const RecordFieldInfo *RecordPayload::findField(const std::string &Name) const {
+ for (const auto &F : Fields) {
+ if (F.first == Name) return &F.second;
+ }
+ return nullptr;
+}
+
bool TypeInfo::isNumeric() const {
return Kind == TypeKind::Integer || Kind == TypeKind::Real;
}
@@ -33,58 +40,62 @@ bool TypeInfo::isVoid() const {
return Kind == TypeKind::Void;
}
-TypeSystem::TypeSystem(LLVMContext &Ctx) : Context(Ctx) {
- registerBuiltins();
+bool TypeInfo::isEnum() const {
+ return Kind == TypeKind::Enum;
}
-void TypeSystem::registerBuiltins() {
- registerType("INTEGER",
- Type::getInt64Ty(Context),
- 8,
- TypeKind::Integer,
- true,
- false,
- true);
+bool TypeInfo::isRecord() const {
+ return Kind == TypeKind::Record;
+}
- registerType("REAL",
- Type::getDoubleTy(Context),
- 8,
- TypeKind::Real,
- true,
- false,
- true);
+bool TypeInfo::isPointer() const {
+ return Kind == TypeKind::Pointer;
+}
- registerType("BOOLEAN",
- Type::getInt1Ty(Context),
- 1,
- TypeKind::Boolean,
- true,
- false,
- true);
+bool TypeInfo::isUserKind() const {
+ return Kind == TypeKind::Enum || Kind == TypeKind::Record || Kind == TypeKind::Pointer;
+}
- registerType("STRING",
- PointerType::getUnqual(Context),
- 8,
- TypeKind::String,
- true,
- true,
- true);
+bool TypeInfo::isOutputtable() const {
+ switch (Kind) {
+ case TypeKind::Integer:
+ case TypeKind::Real:
+ case TypeKind::Boolean:
+ case TypeKind::String:
+ case TypeKind::Char:
+ case TypeKind::Enum: // prints its ordinal
+ return true;
+ case TypeKind::Void:
+ case TypeKind::Record:
+ case TypeKind::Pointer:
+ return false;
+ }
+ return false;
+}
- registerType("CHAR",
- Type::getInt8Ty(Context),
- 1,
- TypeKind::Char,
- true,
- false,
- true);
+const RecordPayload *TypeInfo::asRecord() const {
+ return Kind == TypeKind::Record ? &Record : nullptr;
+}
- registerType("VOID",
- Type::getVoidTy(Context),
- 0,
- TypeKind::Void,
- false,
- false,
- true);
+const EnumPayload *TypeInfo::asEnum() const {
+ return Kind == TypeKind::Enum ? &Enum : nullptr;
+}
+
+const PointerPayload *TypeInfo::asPointer() const {
+ return Kind == TypeKind::Pointer ? &Pointer : nullptr;
+}
+
+TypeSystem::TypeSystem(LLVMContext &Ctx) : Context(Ctx) {
+ registerBuiltins();
+}
+
+void TypeSystem::registerBuiltins() {
+ registerType("INTEGER", Type::getInt64Ty(Context), TypeKind::Integer);
+ registerType("REAL", Type::getDoubleTy(Context), TypeKind::Real);
+ registerType("BOOLEAN", Type::getInt1Ty(Context), TypeKind::Boolean);
+ registerType("STRING", PointerType::getUnqual(Context), TypeKind::String);
+ registerType("CHAR", Type::getInt8Ty(Context), TypeKind::Char);
+ registerType("VOID", Type::getVoidTy(Context), TypeKind::Void);
}
const TypeInfo *TypeSystem::resolve(const std::string &TypeName) const {
@@ -95,38 +106,162 @@ const TypeInfo *TypeSystem::resolve(const std::string &TypeName) const {
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) {
+ TypeKind Kind) {
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;
+bool TypeSystem::declareUserType(const std::string &Name, TypeKind Kind, std::string &Err) {
+ if (Types.count(Name)) {
+ Err = "Type " + Name + " is already defined";
+ return false;
+ }
+ if (EnumConstants.count(Name)) {
+ Err = "'" + Name + "' is an enum value and cannot name a type";
+ return false;
+ }
+
+ Type *LLVMType = nullptr;
+ switch (Kind) {
+ case TypeKind::Enum:
+ LLVMType = Type::getInt64Ty(Context); // INTEGER representation; identity is the name
+ break;
+ case TypeKind::Pointer:
+ LLVMType = PointerType::getUnqual(Context);
+ break;
+ case TypeKind::Record:
+ // Opaque named struct; the body is set in pass B.
+ LLVMType = StructType::create(Context, std::string(kRecordStructPrefix) + Name);
+ break;
+ default:
+ Err = "Internal: declareUserType called with a builtin kind";
+ return false;
+ }
+
+ registerType(Name, LLVMType, Kind);
+ return true;
+}
+
+bool TypeSystem::defineEnum(const std::string &Name,
+ const std::vector<std::string> &Values,
+ std::string &Err) {
+ auto It = Types.find(Name);
+ if (It == Types.end() || It->second.Kind != TypeKind::Enum) {
+ Err = "Internal: defineEnum on undeclared enum " + Name;
+ return false;
+ }
+
+ for (size_t I = 0; I < Values.size(); ++I) {
+ const std::string &V = Values[I];
+ for (size_t J = 0; J < I; ++J) {
+ if (Values[J] == V) {
+ Err = "Duplicate value '" + V + "' in enum " + Name;
+ return false;
+ }
+ }
+ if (Types.count(V)) {
+ Err = "Enum value '" + V + "' in " + Name + " collides with a type name";
+ return false;
+ }
+ if (auto CIt = EnumConstants.find(V); CIt != EnumConstants.end()) {
+ Err = "Enum value '" + V + "' in " + Name + " is already a value of enum " +
+ CIt->second.TypeName;
+ return false;
+ }
+ }
+
+ It->second.Enum.ValueNames = Values;
+ for (size_t I = 0; I < Values.size(); ++I) {
+ EnumConstants[Values[I]] = {Name, static_cast<int64_t>(I) + kEnumOrdinalBase};
+ }
+ return true;
+}
+
+bool TypeSystem::defineRecord(const std::string &Name,
+ const std::vector<std::pair<std::string, std::string>> &Fields,
+ std::string &Err) {
+ auto It = Types.find(Name);
+ if (It == Types.end() || It->second.Kind != TypeKind::Record) {
+ Err = "Internal: defineRecord on undeclared record " + Name;
+ return false;
+ }
+
+ std::vector<Type*> FieldTypes;
+ RecordPayload Payload;
+ for (const auto &[FieldName, FieldTypeName] : Fields) {
+ if (Payload.findField(FieldName)) {
+ Err = "Duplicate field '" + FieldName + "' in record " + Name;
+ return false;
+ }
+ const TypeInfo *FieldInfo = resolve(FieldTypeName);
+ if (!FieldInfo) {
+ Err = "Unknown type " + FieldTypeName + " for field " + FieldName +
+ " of record " + Name;
+ return false;
+ }
+ if (FieldInfo->isVoid()) {
+ Err = "Field " + FieldName + " of record " + Name + " cannot be VOID";
+ return false;
+ }
+ // By-value record fields require a *completed* record (source order);
+ // this also rules out self/mutual inclusion. Inclusion via a pointer
+ // type is fine (opaque ptr, always complete).
+ if (FieldInfo->isRecord() && llvm::cast<StructType>(FieldInfo->LLVMType)->isOpaque()) {
+ Err = "Record type " + FieldTypeName + " must be fully defined before field " +
+ FieldName + " of record " + Name + " (records cannot contain themselves)";
+ return false;
+ }
+
+ RecordFieldInfo FI;
+ FI.TypeName = FieldInfo->Name;
+ FI.Index = static_cast<unsigned>(FieldTypes.size());
+ Payload.Fields.emplace_back(FieldName, FI);
+ FieldTypes.push_back(FieldInfo->LLVMType);
+ }
+
+ llvm::cast<StructType>(It->second.LLVMType)->setBody(FieldTypes);
+ It->second.Record = std::move(Payload);
+ return true;
+}
+
+bool TypeSystem::definePointer(const std::string &Name,
+ const std::string &PointeeName,
+ std::string &Err) {
+ auto It = Types.find(Name);
+ if (It == Types.end() || It->second.Kind != TypeKind::Pointer) {
+ Err = "Internal: definePointer on undeclared pointer type " + Name;
+ return false;
+ }
+
+ const TypeInfo *Pointee = resolve(PointeeName);
+ if (!Pointee) {
+ Err = "Unknown pointee type " + PointeeName + " in pointer type " + Name;
+ return false;
+ }
+ if (Pointee->isVoid()) {
+ Err = "Pointer type " + Name + " cannot point to VOID";
+ return false;
+ }
+
+ It->second.Pointer.PointeeTypeName = Pointee->Name;
+ return true;
+}
+
+const EnumConstant *TypeSystem::lookupEnumConstant(const std::string &Name) const {
+ auto It = EnumConstants.find(Name);
+ return It == EnumConstants.end() ? nullptr : &It->second;
}
-uint64_t TypeSystem::getElementSize(const std::string &TypeName) const {
+Type *TypeSystem::getLLVMType(const std::string &TypeName) const {
const TypeInfo *Info = resolve(TypeName);
- return Info ? Info->ElementSize : 0;
+ return Info ? Info->LLVMType : nullptr;
}
Constant *TypeSystem::getSizeOfConstant(Type *Ty) const {
@@ -152,8 +287,12 @@ Constant *TypeSystem::getZeroValue(const std::string &TypeName) const {
return ConstantPointerNull::get(cast<PointerType>(Info->LLVMType));
case TypeKind::Void:
return nullptr;
- case TypeKind::Custom:
- return Constant::getNullValue(Info->LLVMType);
+ case TypeKind::Enum:
+ return ConstantInt::get(Context, APInt(64, kEnumOrdinalBase));
+ case TypeKind::Record:
+ return Constant::getNullValue(Info->LLVMType); // zeroinitializer
+ case TypeKind::Pointer:
+ return ConstantPointerNull::get(cast<PointerType>(Info->LLVMType));
}
return Constant::getNullValue(Info->LLVMType);