aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CodeGen.cc
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-07-26 17:32:24 +0000
committer_ov4 <ov4@ov4.org>2026-07-26 17:32:24 +0000
commitf19f1c956780f41f1440b372187770ce0be8efed (patch)
treefe0c2fe47a2cddb1bd8bd92206d47136bfcbfd37 /lib/CodeGen/CodeGen.cc
parent3366a2e0fae05d9e792169e74471c7282bf18681 (diff)
feat: user type registry and enumerated types (CIE 4.1/4.2)
- TypeSystem: TypeKinds Enum/Record/Pointer with per-kind payloads and checked accessors; two-pass registration (names first, then definitions in source order) so pointer TYPEs may forward-reference; enum-constant table owned by TypeSystem so constants stay visible inside function bodies across the Symbols save/clear/restore. Dead surface removed (Custom kind, Printable/Builtin/ReferenceLike, ElementSize, hasType, CodeGen::getNamedValue/getLLVMType). - Enums are i64 with 0-based ordinals (constexpr kEnumOrdinalBase); all type identity is by NAME. New emitCoercedExpr is the single admission gate, replacing raw coercion at assignments, array stores, BYVAL args, RETURN, IF/WHILE/REPEAT/FOR operands, file operands and builtin args; coerceValueToType now hard-errors if a user-kind target reaches it. - Binary ops with user-kind operands are intercepted ahead of ArithmeticHandler ('&'-intercept precedent): same-enum comparisons, enum +/- INTEGER (with a runtime range check, [Fatal] on overflow, the only site that can manufacture an invalid ordinal), same-name pointer =/<>; everything else is a compile error naming the operator. - OUTPUT is an exhaustive switch over TypeKind (enum prints its ordinal; record/pointer are compile errors, also covering whole-array OUTPUT); INPUT's silent %lld fallback for unknown kinds is now an explicit error. - Enum value names are globally reserved: collisions with DECLARE, array names, parameters and function names are compile errors. - RuntimeCheck: emitEnumRangeCheck + emitNullDerefCheck (used by the pointer phase) following the emitIndexCheck recipe. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/CodeGen.cc')
-rw-r--r--lib/CodeGen/CodeGen.cc205
1 files changed, 134 insertions, 71 deletions
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;