aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CodeGen.cc
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-16 09:42:45 +0000
committer_ov4 <ov4@ov4.org>2026-10-16 09:42:45 +0000
commit3dc3a15c86287b2788142b58e2512269cd5274c6 (patch)
tree1610b02343fd3e8b6b733c0cbfe327be6fef4394 /lib/CodeGen/CodeGen.cc
parentdb6ac29d0ac769ff780f3901ed987b97965f3f5e (diff)
refactor(codegen): split emission by responsibility
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/CodeGen.cc')
-rw-r--r--lib/CodeGen/CodeGen.cc1099
1 files changed, 2 insertions, 1097 deletions
diff --git a/lib/CodeGen/CodeGen.cc b/lib/CodeGen/CodeGen.cc
index 7e463db..6c6f682 100644
--- a/lib/CodeGen/CodeGen.cc
+++ b/lib/CodeGen/CodeGen.cc
@@ -1,10 +1,8 @@
#include "cps/CodeGen.h"
#include "cps/ArrayHandler.h"
-#include "cps/FileAST.h"
#include "cps/FileHandler.h"
#include "cps/ExceptionHandler.h"
-#include "cps/Lexer.h"
-#include "cps/TypeAST.h"
+#include "Builtins.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Verifier.h"
#include <cstdarg>
@@ -13,40 +11,7 @@
using namespace llvm;
using namespace cps;
-namespace {
-
-// Single source of truth for the built-in functions: name, arity and return
-// type. emitExpr checks arity against this table before dispatching, and
-// getExprTypeInfo reads the return type from it.
-struct BuiltinInfo {
- const char *Name;
- unsigned Arity;
- const char *ReturnTypeName;
-};
-
-constexpr BuiltinInfo Builtins[] = {
- {"LENGTH", 1, "INTEGER"},
- {"MID", 3, "STRING"},
- {"RIGHT", 2, "STRING"},
- {"LEFT", 2, "STRING"},
- {"LCASE", 1, "STRING"},
- {"UCASE", 1, "STRING"},
- {"ASC", 1, "INTEGER"},
- {"CHR", 1, "STRING"},
- {"IS_NUM", 1, "BOOLEAN"},
- {"NUM_TO_STR", 1, "STRING"},
- {"STR_TO_NUM", 1, "REAL"},
- {"EOF", 1, "BOOLEAN"},
-};
-
-const BuiltinInfo *findBuiltin(const std::string &Name) {
- for (const auto &B : Builtins) {
- if (Name == B.Name) return &B;
- }
- return nullptr;
-}
-
-} // namespace
+using namespace cps::detail;
CodeGen::~CodeGen() = default;
@@ -177,362 +142,6 @@ const TypeInfo *CodeGen::resolveType(const std::string &TypeName) const {
return Types->resolve(TypeName);
}
-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 *Cast = dynamic_cast<CastExprAST*>(Expr))
- return resolveType(Cast->getTypeName());
-
- if (auto *Var = dynamic_cast<VariableExprAST*>(Expr)) {
- const SymbolInfo *Info = getSymbolInfo(Var->getName());
- 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)) {
- const SymbolInfo *Info = getSymbolInfo(Arr->getName());
- return Info ? resolveType(Info->TypeName) : nullptr;
- }
-
- if (auto *D = dynamic_cast<DesignatorExprAST*>(Expr)) {
- const SymbolInfo *Info = getSymbolInfo(D->getBaseName());
- if (!Info) return nullptr;
- std::string TypeName = Info->TypeName;
- size_t Start = 0;
- if (Info->IsArray) {
- // SymbolInfo already holds the ELEMENT type name for arrays.
- if (D->getAccesses().empty() || D->getAccesses()[0].Kind != AccessKind::Index)
- return nullptr;
- Start = 1;
- }
- for (size_t I = Start; I < D->getAccesses().size(); ++I) {
- const TypeInfo *Cur = resolveType(TypeName);
- if (!Cur) return nullptr;
- const DesignatorAccess &A = D->getAccesses()[I];
- if (A.Kind == AccessKind::Field) {
- const RecordPayload *RP = Cur->asRecord();
- const RecordFieldInfo *FI = RP ? RP->findField(A.FieldName) : nullptr;
- if (!FI) return nullptr;
- if (!FI->IsPublic) return nullptr;
- TypeName = FI->TypeName;
- } else if (A.Kind == AccessKind::Deref) {
- const PointerPayload *PP = Cur->asPointer();
- if (!PP) return nullptr;
- TypeName = PP->PointeeTypeName;
- } else {
- return nullptr; // indexing a non-array
- }
- }
- return resolveType(TypeName);
- }
-
- // ^x has no pseudocode type of its own; only the pointer admission in
- // emitCoercedExpr may consume it.
- if (dynamic_cast<AddrOfExprAST*>(Expr)) return nullptr;
-
- if (auto *Unary = dynamic_cast<UnaryExprAST*>(Expr)) {
- if (Unary->getOp() == tok_not) {
- return resolveType("BOOLEAN");
- }
- const TypeInfo *Operand = getExprTypeInfo(Unary->getOperand());
- if (Operand && Operand->isC()) return Types->promoteCScalar(Operand);
- if (Operand && !Operand->isC() && !Operand->isUserKind())
- return Operand->isReal() ? resolveType("REAL") : resolveType("INTEGER");
- return nullptr;
- }
-
- 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");
- case '/':
- return resolveType("REAL");
- default:
- break;
- }
-
- const TypeInfo *L = getExprTypeInfo(Bin->getLHS());
- const TypeInfo *R = getExprTypeInfo(Bin->getRHS());
- if ((L && L->isC()) || (R && R->isC())) return Types->commonCScalar(L, R);
- // 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");
- }
- return resolveType("INTEGER");
- }
-
- if (auto *Call = dynamic_cast<CallExprAST*>(Expr)) {
- const std::string &Name = Call->getCallee();
- if (const BuiltinInfo *B = findBuiltin(Name)) {
- return resolveType(B->ReturnTypeName);
- }
- if (const FuncSig *Sig = FuncGen->getSignature(Name)) {
- return resolveType(Sig->ReturnTypeName);
- }
-
- 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)) {
- Value *Mem = Builder->CreateCall(MallocFunc,
- 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;
-
- // 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:
- case TypeKind::CScalar:
- case TypeKind::CPointer:
- 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",
- TargetInfo->Name.c_str());
- return nullptr;
-}
-
-void CodeGen::emitDeclareStmt(DeclareStmtAST *Stmt) {
- const TypeInfo *Info = resolveType(Stmt->getType());
- if (!Info || !Info->LLVMType || Info->isVoid()) {
- 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;
- }
- if (Types->resolve(Stmt->getName())) {
- reportError("'%s' is a type name 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());
-
- 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);
-}
-
-Value *CodeGen::emitStringNullGuard(Value *StrVal) {
- if (!StrVal || !StrVal->getType()->isPointerTy()) return StrVal;
- Value *IsNull = Builder->CreateICmpEQ(StrVal,
- ConstantPointerNull::get(cast<PointerType>(StrVal->getType())),
- "str_is_null");
- return Builder->CreateSelect(IsNull, EmptyStringStr, StrVal, "safe_str");
-}
-
-void CodeGen::emitOutputValue(Value *Val, const TypeInfo *Info, bool AppendNewline) {
- if (!Val || !Info) return;
-
- std::vector<Value*> Args;
- Value *Fmt = nullptr;
-
- // 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->CreateGlobalString("%f", "fmt_flt_inline", 0, TheModule.get());
- Args.push_back(Fmt);
- Args.push_back(Val);
- break;
-
- case TypeKind::Boolean: {
- Value *BoolVal = coerceValueToType(Val, resolveType("BOOLEAN"));
- Fmt = AppendNewline
- ? PrintfStringFormatStr
- : Builder->CreateGlobalString("%s", "fmt_str_inline", 0, TheModule.get());
- Args.push_back(Fmt);
- Args.push_back(Builder->CreateSelect(BoolVal, TrueStr, FalseStr));
- break;
- }
-
- case TypeKind::String: {
- Value *StrVal = emitStringNullGuard(Val);
- Fmt = AppendNewline
- ? PrintfStringFormatStr
- : Builder->CreateGlobalString("%s", "fmt_str_inline", 0, TheModule.get());
- Args.push_back(Fmt);
- Args.push_back(StrVal);
- break;
- }
-
- case TypeKind::Char: {
- Value *CharVal = coerceValueToType(Val, resolveType("CHAR"));
- Value *Promoted = Builder->CreateZExt(CharVal, Type::getInt32Ty(*TheContext), "char_for_printf");
- Fmt = AppendNewline
- ? PrintfCharFormatStr
- : Builder->CreateGlobalString("%c", "fmt_chr_inline", 0, TheModule.get());
- Args.push_back(Fmt);
- Args.push_back(Promoted);
- 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->CreateGlobalString("%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::CScalar:
- emitCOutput(Val, Info, AppendNewline);
- return;
- case TypeKind::CPointer:
- reportError("OUTPUT is not supported for type %s", Info->Name.c_str());
- return;
-
- case TypeKind::Void:
- reportError("Cannot OUTPUT a VOID value");
- return;
- }
-
- Builder->CreateCall(PrintfFunc, Args);
-}
-
void CodeGen::compile(const std::vector<std::unique_ptr<StmtAST>> &Statements) {
FunctionType *FT = FunctionType::get(Type::getInt32Ty(*TheContext), false);
Function *F = Function::Create(FT, Function::ExternalLinkage, "main", TheModule.get());
@@ -581,268 +190,6 @@ void CodeGen::print(raw_ostream &Output) {
TheModule->print(Output, nullptr);
}
-Value *CodeGen::emitExpr(ExprAST *Expr) {
- if (auto *Cast = dynamic_cast<CastExprAST*>(Expr)) return emitCast(Cast);
- if (!Expr) return nullptr;
-
- if (auto *Num = dynamic_cast<IntegerExprAST*>(Expr)) {
- return ConstantInt::get(*TheContext, APInt(64, Num->getVal(), true));
- }
-
- if (auto *Real = dynamic_cast<RealExprAST*>(Expr)) {
- return ConstantFP::get(*TheContext, APFloat(Real->getVal()));
- }
-
- if (auto *Bool = dynamic_cast<BooleanExprAST*>(Expr)) {
- return ConstantInt::get(*TheContext, APInt(1, Bool->getVal() ? 1 : 0));
- }
-
- 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)) {
- 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;
- }
- if (Info->IsArray) {
- return Info->Storage;
- }
-
- const TypeInfo *TypeInfo = resolveType(Info->TypeName);
- if (!TypeInfo || !TypeInfo->LLVMType) {
- reportError("Unknown type for variable %s", Var->getName().c_str());
- return nullptr;
- }
-
- Value *Loaded = Builder->CreateLoad(TypeInfo->LLVMType, Info->Storage, Var->getName().c_str());
- if (TypeInfo->isString()) {
- Loaded = emitStringNullGuard(Loaded);
- }
- return Loaded;
- }
-
- if (auto *ArrAcc = dynamic_cast<ArrayAccessExprAST*>(Expr)) {
- return Arrays->emitArrayAccess(ArrAcc, *this);
- }
-
- if (auto *Unary = dynamic_cast<UnaryExprAST*>(Expr)) {
- if (Unary->getOp() == tok_not) {
- const TypeInfo *Info = getExprTypeInfo(Unary->getOperand());
- Value *Operand = Info && Info->isC()
- ? convertNumericValue(emitExpr(Unary->getOperand()), Info, resolveType("BOOLEAN"))
- : emitCoercedExpr(Unary->getOperand(), resolveType("BOOLEAN"));
- if (Info && Info->Kind == TypeKind::CPointer) {
- reportError("NOT does not support C pointer operands");
- return nullptr;
- }
- if (!Operand) return nullptr;
- return Builder->CreateNot(Operand, "nottmp");
- }
- if (Unary->getOp() == '-') {
- const TypeInfo *Info = getExprTypeInfo(Unary->getOperand());
- if (Info && Info->Kind == TypeKind::CScalar && !Info->isVoid()) {
- const TypeInfo *Promoted = Types->promoteCScalar(Info);
- Value *Operand = convertNumericValue(emitExpr(Unary->getOperand()), Info, Promoted);
- if (!Operand) return nullptr;
- return Promoted->isReal() ? Builder->CreateFNeg(Operand, "c_neg")
- : Builder->CreateNeg(Operand, "c_neg");
- }
- if (!Info || Info->isC() || Info->isUserKind() || Info->isString() || Info->isVoid()) {
- reportError("Unary '-' requires a supported numeric operand");
- return nullptr;
- }
- Value *Operand = emitExpr(Unary->getOperand());
- if (!Operand) return nullptr;
- return ArithHandler->emitBinaryOp('-', ConstantInt::get(Type::getInt64Ty(*TheContext), 0),
- Operand, 0);
- }
- return nullptr;
- }
-
- if (auto *Bin = dynamic_cast<BinaryExprAST*>(Expr)) {
- // Whole arrays evaluate to raw data pointers and ^x to raw addresses;
- // neither is a value any operator may consume.
- if (isWholeArrayVar(Bin->getLHS()) || isWholeArrayVar(Bin->getRHS())) {
- reportError("A whole array cannot be used as an operand; index it");
- return nullptr;
- }
- if (dynamic_cast<AddrOfExprAST*>(Bin->getLHS()) ||
- dynamic_cast<AddrOfExprAST*>(Bin->getRHS())) {
- reportError("'^' (address-of) can only be used where a pointer type is expected");
- return nullptr;
- }
-
- // 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->isC()) || (RT && RT->isC())) {
- return emitCBinaryOp(Bin, LT, RT);
- }
- 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;
- if (Bin->getOp() == '&') {
- L = coerceValueToType(L, resolveType("STRING"));
- R = coerceValueToType(R, resolveType("STRING"));
- if (!L || !R) return nullptr;
- return StrHandler->emitConcat(L, R);
- }
- // STRING and explicit pointers share LLVM's ptr representation;
- // string comparisons must dispatch on the pseudocode type.
- switch (Bin->getOp()) {
- case tok_eq: case tok_ne: case '<': case '>': case tok_le: case tok_ge:
- if ((LT && LT->isString()) || (RT && RT->isString())) {
- if (!(LT && LT->isString() && RT && RT->isString())) {
- reportError("STRING comparison requires two STRING operands (line %d)", Bin->getLine());
- return nullptr;
- }
- return StrHandler->emitCompare(Bin->getOp(), L, R);
- }
- break;
- default:
- break;
- }
- return ArithHandler->emitBinaryOp(Bin->getOp(), L, R, Bin->getLine());
- }
-
- if (auto *Call = dynamic_cast<CallExprAST*>(Expr)) {
- std::string Name = Call->getCallee();
- if (const BuiltinInfo *B = findBuiltin(Name)) {
- if (Call->getArgs().size() != B->Arity) {
- reportError("%s expects %u arg%s", B->Name, B->Arity, B->Arity == 1 ? "" : "s");
- return nullptr;
- }
- }
- if (Name == "LENGTH") {
- Value *Str = emitCoercedExpr(Call->getArgs()[0].get(), resolveType("STRING"));
- if (!Str) return nullptr;
- return StrHandler->emitLength(Str);
- }
- if (Name == "MID") {
- 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 = 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 = 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 = emitCoercedExpr(Call->getArgs()[0].get(), resolveType("STRING"));
- if (!Str) return nullptr;
- return StrHandler->emitLCase(Str);
- }
- if (Name == "UCASE") {
- 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() || ArgType->isC())) {
- 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;
- Value *CharVal = nullptr;
- if (ArgType && ArgType->isChar()) {
- CharVal = coerceValueToType(ArgVal, resolveType("CHAR"));
- } else {
- CharVal = Builder->CreateLoad(Type::getInt8Ty(*TheContext), ArgVal, "char_load");
- }
- Value *AscVal = Builder->CreateZExt(CharVal, Type::getInt32Ty(*TheContext), "asc_val");
- return coerceValueToType(AscVal, resolveType("INTEGER"));
- }
- if (Name == "CHR") {
- 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 = 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() || ArgType->isC())) {
- 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();
- if (NumV->getType()->isIntegerTy(8)) {
- NumV = coerceValueToType(NumV, resolveType("INTEGER"));
- }
- return StrConvHandler->emitNumToStr(NumV, IsReal);
- }
- if (Name == "STR_TO_NUM") {
- Value *Str = emitCoercedExpr(Call->getArgs()[0].get(), resolveType("STRING"));
- if (!Str) return nullptr;
- return StrConvHandler->emitStrToNum(Str, true);
- }
- if (Name == "EOF") {
- if (isWholeArrayVar(Call->getArgs()[0].get())) {
- reportError("Cannot use a whole array as the EOF filename");
- return nullptr;
- }
- Value *FileName = emitCoercedExpr(Call->getArgs()[0].get(), resolveType("STRING"));
- if (!FileName) return nullptr;
- return Files->emitEof(FileName, Call->getLine());
- }
-
- std::vector<Value*> Args;
- if (!marshalCallArgs(Name, Call->getArgs(), Call->getLine(), Args)) return nullptr;
- return FuncGen->emitCallExpr(Call, Args);
- }
-
- if (auto *D = dynamic_cast<DesignatorExprAST*>(Expr)) {
- LValueInfo LV;
- if (!emitLValue(D, LV)) return nullptr;
- return loadFromLValue(LV);
- }
-
- // ^x produces a raw address; it is only admissible where a pointer type
- // is expected, which emitCoercedExpr enforces by pointee name.
- if (auto *Addr = dynamic_cast<AddrOfExprAST*>(Expr)) {
- LValueInfo LV;
- if (!emitLValue(Addr->getTarget(), LV)) return nullptr;
- return LV.Addr;
- }
-
- return nullptr;
-}
-
// Collects the arguments for a call to a user FUNCTION/PROCEDURE, dispatching
// on the *declared* signature: BYREF parameters take the variable's alloca,
// BYVAL parameters are evaluated and coerced to the declared parameter type.
@@ -912,445 +259,3 @@ bool CodeGen::marshalCallArgs(const std::string &Callee,
}
return true;
}
-
-void CodeGen::emitTryStmt(TryStmtAST *Stmt) {
- auto *F = Builder->GetInsertBlock()->getParent();
- auto *CatchBB = BasicBlock::Create(*TheContext, "catch", F);
- auto *AfterBB = BasicBlock::Create(*TheContext, "try_cont", F);
- auto SavedArrays = Arrays->snapshotTable();
-
- Exceptions->pushHandler(CatchBB);
- for (const auto &S : Stmt->getBody()) emitStmt(S.get());
- auto *Exception = Exceptions->popHandler();
- if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(AfterBB);
- Arrays->exchangeTable(SavedArrays);
-
- Builder->SetInsertPoint(CatchBB);
- Exceptions->beginCatch(Exception);
- for (const auto &S : Stmt->getCatchBody()) emitStmt(S.get());
- Exceptions->endCatch();
- if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(AfterBB);
- Arrays->exchangeTable(std::move(SavedArrays));
- Builder->SetInsertPoint(AfterBB);
-}
-
-void CodeGen::emitIfStmt(IfStmtAST *Stmt) {
- Value *CondV = emitCoercedExpr(Stmt->getCond(), resolveType("BOOLEAN"));
- if (!CondV) return;
-
- Function *TheFunction = Builder->GetInsertBlock()->getParent();
- BasicBlock *ThenBB = BasicBlock::Create(*TheContext, "then", TheFunction);
- BasicBlock *ElseBB = BasicBlock::Create(*TheContext, "else", TheFunction);
- BasicBlock *MergeBB = BasicBlock::Create(*TheContext, "ifcont", TheFunction);
-
- Builder->CreateCondBr(CondV, ThenBB, ElseBB);
-
- // Arrays are block-scoped: metadata SSA values and the buffer setup live
- // inside the branch, so a declaration must not survive it.
- auto SavedArrays = Arrays->snapshotTable();
- Builder->SetInsertPoint(ThenBB);
- for (const auto &S : Stmt->getThenStmts()) emitStmt(S.get());
- if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(MergeBB);
- Arrays->exchangeTable(SavedArrays);
-
- Builder->SetInsertPoint(ElseBB);
- for (const auto &S : Stmt->getElseStmts()) emitStmt(S.get());
- if (!Builder->GetInsertBlock()->hasTerminator()) Builder->CreateBr(MergeBB);
- Arrays->exchangeTable(std::move(SavedArrays));
-
- Builder->SetInsertPoint(MergeBB);
-}
-
-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);
-
- Builder->CreateBr(CondBB);
-
- Builder->SetInsertPoint(CondBB);
- Value *CondV = emitCoercedExpr(Stmt->getCond(), resolveType("BOOLEAN"));
- if (!CondV) return;
-
- Builder->CreateCondBr(CondV, LoopBB, AfterBB);
-
- // Arrays declared in the body are block-scoped (see emitIfStmt).
- auto SavedArrays = Arrays->snapshotTable();
- Builder->SetInsertPoint(LoopBB);
- for (const auto &S : Stmt->getBody()) emitStmt(S.get());
- Arrays->exchangeTable(std::move(SavedArrays));
-
- if (!Builder->GetInsertBlock()->hasTerminator())
- Builder->CreateBr(CondBB);
-
- Builder->SetInsertPoint(AfterBB);
-}
-
-void CodeGen::emitRepeatStmt(RepeatStmtAST *Stmt) {
- Function *TheFunction = Builder->GetInsertBlock()->getParent();
-
- BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "repeatloop", TheFunction);
- BasicBlock *CondBB = BasicBlock::Create(*TheContext, "repeatcond", TheFunction);
- BasicBlock *AfterBB = BasicBlock::Create(*TheContext, "repeatcont", TheFunction);
-
- Builder->CreateBr(LoopBB);
-
- // Arrays declared in the body are block-scoped (see emitIfStmt).
- auto SavedArrays = Arrays->snapshotTable();
- Builder->SetInsertPoint(LoopBB);
- for (const auto &S : Stmt->getBody()) emitStmt(S.get());
- Arrays->exchangeTable(std::move(SavedArrays));
- if (!Builder->GetInsertBlock()->hasTerminator())
- Builder->CreateBr(CondBB);
-
- Builder->SetInsertPoint(CondBB);
- Value *CondV = emitCoercedExpr(Stmt->getCond(), resolveType("BOOLEAN"));
- if (!CondV) return;
-
- Builder->CreateCondBr(CondV, AfterBB, LoopBB);
-
- Builder->SetInsertPoint(AfterBB);
-}
-
-void CodeGen::emitForStmt(ForStmtAST *Stmt) {
- Function *TheFunction = Builder->GetInsertBlock()->getParent();
- std::string VarName = Stmt->getVarName();
-
- const SymbolInfo *Symbol = getSymbolInfo(VarName);
- if (!Symbol) {
- reportError("Unknown variable in FOR loop %s", VarName.c_str());
- return;
- }
- if (Symbol->TypeName != "INTEGER") {
- reportError("FOR loop variable %s must be INTEGER", VarName.c_str());
- return;
- }
-
- Value *StartVal = emitCoercedExpr(Stmt->getStart(), resolveType("INTEGER"));
- if (!StartVal) return;
-
- Value *Alloca = Symbol->Storage;
- Builder->CreateStore(StartVal, Alloca);
-
- // STEP is evaluated exactly once, before the loop.
- Value *StepVal = nullptr;
- if (Stmt->getStep()) {
- StepVal = emitCoercedExpr(Stmt->getStep(), resolveType("INTEGER"));
- if (!StepVal) return;
- } else {
- StepVal = ConstantInt::get(*TheContext, APInt(64, 1));
- }
-
- BasicBlock *CondBB = BasicBlock::Create(*TheContext, "forcond", TheFunction);
- BasicBlock *LoopBB = BasicBlock::Create(*TheContext, "forloop", TheFunction);
- BasicBlock *IncBB = BasicBlock::Create(*TheContext, "forinc", TheFunction);
- BasicBlock *AfterBB = BasicBlock::Create(*TheContext, "forcont", TheFunction);
-
- Builder->CreateBr(CondBB);
- Builder->SetInsertPoint(CondBB);
-
- Value *CurVar = Builder->CreateLoad(Type::getInt64Ty(*TheContext), Alloca, VarName.c_str());
- Value *EndVal = emitCoercedExpr(Stmt->getEnd(), resolveType("INTEGER"));
- if (!EndVal) return;
-
- // The loop direction depends on the STEP value at run time.
- Value *StepNonNeg = Builder->CreateICmpSGE(StepVal,
- ConstantInt::get(*TheContext, APInt(64, 0)),
- "step_nonneg");
- Value *CondUp = Builder->CreateICmpSLE(CurVar, EndVal, "forcond_le");
- Value *CondDown = Builder->CreateICmpSGE(CurVar, EndVal, "forcond_ge");
- Value *CondV = Builder->CreateSelect(StepNonNeg, CondUp, CondDown, "forcond");
-
- Builder->CreateCondBr(CondV, LoopBB, AfterBB);
-
- // Arrays declared in the body are block-scoped (see emitIfStmt).
- auto SavedArrays = Arrays->snapshotTable();
- Builder->SetInsertPoint(LoopBB);
- for (const auto &S : Stmt->getBody()) emitStmt(S.get());
- Arrays->exchangeTable(std::move(SavedArrays));
- if (!Builder->GetInsertBlock()->hasTerminator())
- Builder->CreateBr(IncBB);
-
- Builder->SetInsertPoint(IncBB);
- Value *CurValForInc = Builder->CreateLoad(Type::getInt64Ty(*TheContext), Alloca, VarName.c_str());
- Value *NextVal = Builder->CreateAdd(CurValForInc, StepVal, "nextval");
- Builder->CreateStore(NextVal, Alloca);
- Builder->CreateBr(CondBB);
-
- Builder->SetInsertPoint(AfterBB);
-}
-
-void CodeGen::emitStmt(StmtAST *Stmt) {
- if (!Stmt) return;
-
- if (auto *FuncDef = dynamic_cast<FunctionDefAST*>(Stmt)) {
- BasicBlock *SavedBlock = Builder->GetInsertBlock();
- // Function bodies get a fresh array scope (metadata SSA values belong
- // to the emitting function), mirroring FunctionGen's Symbols handling.
- auto SavedArrays = Arrays->exchangeTable({});
-
- FuncGen->emitFunctionDef(FuncDef, [this](StmtAST *S) {
- this->emitStmt(S);
- });
-
- Arrays->exchangeTable(std::move(SavedArrays));
- if (SavedBlock) Builder->SetInsertPoint(SavedBlock);
- return;
- }
-
- // Keep diagnosing statements after RETURN/THROW without appending code
- // to a terminated block or making those statements reachable.
- if (Builder->GetInsertBlock()->hasTerminator()) {
- auto *F = Builder->GetInsertBlock()->getParent();
- Builder->SetInsertPoint(BasicBlock::Create(*TheContext, "unreachable_code", F));
- }
-
- if (auto *Try = dynamic_cast<TryStmtAST*>(Stmt)) {
- emitTryStmt(Try);
- return;
- }
- if (dynamic_cast<ThrowStmtAST*>(Stmt)) {
- Exceptions->emitThrow();
- return;
- }
- if (auto *ArrDecl = dynamic_cast<ArrayDeclareStmtAST*>(Stmt)) {
- Arrays->emitArrayDeclare(ArrDecl, *this);
- return;
- }
- if (auto *ArrAssign = dynamic_cast<ArrayAssignStmtAST*>(Stmt)) {
- Arrays->emitArrayAssign(ArrAssign, *this);
- return;
- }
-
- if (auto *Call = dynamic_cast<CallStmtAST*>(Stmt)) {
- std::vector<Value*> Args;
- if (!marshalCallArgs(Call->getCallee(), Call->getArgs(), Call->getLine(), Args)) return;
- FuncGen->emitCallStmt(Call, Args);
- return;
- }
-
- if (auto *Ret = dynamic_cast<ReturnStmtAST*>(Stmt)) {
- Function *F = Builder->GetInsertBlock()->getParent();
- const FuncSig *Sig = FuncGen->getSignature(F->getName().str());
- // Pseudocode cannot name a function "main" (reserved runtime symbol),
- // so no signature means we are emitting the top level.
- if (!Sig) {
- reportError("RETURN is only allowed inside a FUNCTION or PROCEDURE");
- return;
- }
- if (F->getReturnType()->isVoidTy() && Ret->getRetVal()) {
- reportError("RETURN with a value is only allowed in a FUNCTION");
- return;
- }
- if (!F->getReturnType()->isVoidTy() && !Ret->getRetVal()) {
- reportError("RETURN in a FUNCTION requires a value");
- return;
- }
- Value *RetVal = nullptr;
- if (Ret->getRetVal()) {
- RetVal = emitCoercedExpr(Ret->getRetVal(), resolveType(Sig->ReturnTypeName));
- if (!RetVal) return;
- }
- FuncGen->emitReturn(Ret, RetVal);
- return;
- }
-
- if (auto *Decl = dynamic_cast<DeclareStmtAST*>(Stmt)) {
- emitDeclareStmt(Decl);
- return;
- }
-
- if (auto *Assign = dynamic_cast<AssignStmtAST*>(Stmt)) {
- const SymbolInfo *Info = getSymbolInfo(Assign->getName());
- if (!Info) {
- if (Types->lookupEnumConstant(Assign->getName())) {
- reportError("Enum value %s is not an assignable location", Assign->getName().c_str());
- } else {
- reportError("Unknown variable name %s", Assign->getName().c_str());
- }
- return;
- }
- if (Info->IsArray) {
- reportError("Cannot assign array %s without indices", Assign->getName().c_str());
- return;
- }
-
- Value *Val = emitCoercedExpr(Assign->getExpr(), resolveType(Info->TypeName));
- if (!Val) return;
-
- Builder->CreateStore(Val, Info->Storage);
- return;
- }
-
- if (auto *In = dynamic_cast<InputStmtAST*>(Stmt)) {
- const SymbolInfo *Info = getSymbolInfo(In->getName());
- if (!Info) {
- reportError("Unknown variable name %s", In->getName().c_str());
- return;
- }
- if (Info->IsArray) {
- reportError("INPUT for entire array %s is not supported", In->getName().c_str());
- return;
- }
-
- const TypeInfo *TypeInfo = resolveType(Info->TypeName);
- if (!TypeInfo) {
- reportError("Unknown type for INPUT %s", In->getName().c_str());
- return;
- }
-
- std::vector<Value*> Args;
- if (TypeInfo->isC()) {
- emitCInput(Info, TypeInfo);
- } else 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);
-
- 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()) {
- Value *Mem = Builder->CreateCall(MallocFunc, 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->CreateGlobalString(" %c", "fmt_in_char", 0, TheModule.get());
- Args.push_back(CharFmt);
- Args.push_back(Info->Storage);
- Builder->CreateCall(ScanfFunc, Args);
- } 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;
- }
-
- if (auto *Out = dynamic_cast<OutputStmtAST*>(Stmt)) {
- const auto &Exprs = Out->getExprs();
- for (size_t I = 0; I < Exprs.size(); ++I) {
- ExprAST *Expr = Exprs[I].get();
- if (Arrays->tryEmitArrayOutput(Expr, *this)) continue;
-
- Value *Val = emitExpr(Expr);
- const TypeInfo *TypeInfo = getExprTypeInfo(Expr);
- if (!TypeInfo) {
- reportError("Cannot infer the type of the OUTPUT expression");
- continue;
- }
- if (TypeInfo->isVoid()) {
- reportError("Cannot OUTPUT the result of a PROCEDURE call");
- continue;
- }
- emitOutputValue(Val, TypeInfo, I + 1 == Exprs.size());
- }
- return;
- }
-
- if (auto *Open = dynamic_cast<OpenFileStmtAST*>(Stmt)) {
- if (isWholeArrayVar(Open->getFileName())) {
- reportError("Cannot use a whole array as the OPENFILE filename");
- return;
- }
- Value *Name = emitCoercedExpr(Open->getFileName(), resolveType("STRING"));
- if (!Name) return;
- Files->emitOpen(Name, Open->getMode(), Open->getLine());
- return;
- }
-
- if (auto *Read = dynamic_cast<ReadFileStmtAST*>(Stmt)) {
- const SymbolInfo *Info = getSymbolInfo(Read->getVarName());
- if (!Info) {
- reportError("Unknown variable name %s", Read->getVarName().c_str());
- return;
- }
- if (Info->IsArray) {
- reportError("READFILE into entire array %s is not supported", Read->getVarName().c_str());
- return;
- }
- if (Info->TypeName != "STRING") {
- reportError("READFILE variable %s must be of type STRING (got %s)",
- Read->getVarName().c_str(), Info->TypeName.c_str());
- return;
- }
- if (isWholeArrayVar(Read->getFileName())) {
- reportError("Cannot use a whole array as the READFILE filename");
- return;
- }
- Value *Name = emitCoercedExpr(Read->getFileName(), resolveType("STRING"));
- if (!Name) return;
- Value *LineStr = Files->emitRead(Name, Read->getLine());
- if (!LineStr) return;
- Builder->CreateStore(LineStr, Info->Storage);
- return;
- }
-
- if (auto *Write = dynamic_cast<WriteFileStmtAST*>(Stmt)) {
- if (isWholeArrayVar(Write->getFileName()) || isWholeArrayVar(Write->getData())) {
- reportError("Cannot use a whole array in WRITEFILE");
- return;
- }
- 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;
- }
-
- if (auto *Close = dynamic_cast<CloseFileStmtAST*>(Stmt)) {
- if (isWholeArrayVar(Close->getFileName())) {
- reportError("Cannot use a whole array as the CLOSEFILE filename");
- return;
- }
- Value *Name = emitCoercedExpr(Close->getFileName(), resolveType("STRING"));
- if (!Name) return;
- Files->emitClose(Name, Close->getLine());
- return;
- }
-
- if (auto *IfStmt = dynamic_cast<IfStmtAST*>(Stmt)) {
- emitIfStmt(IfStmt);
- return;
- }
- if (auto *WhileStmt = dynamic_cast<WhileStmtAST*>(Stmt)) {
- emitWhileStmt(WhileStmt);
- return;
- }
- if (auto *RepeatStmt = dynamic_cast<RepeatStmtAST*>(Stmt)) {
- emitRepeatStmt(RepeatStmt);
- return;
- }
- if (auto *ForStmt = dynamic_cast<ForStmtAST*>(Stmt)) {
- emitForStmt(ForStmt);
- return;
- }
-
- // 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) || dynamic_cast<CTypeDeclAST*>(Stmt)) {
- return;
- }
- if (auto *DA = dynamic_cast<DesignatorAssignStmtAST*>(Stmt)) {
- LValueInfo LV;
- if (!emitLValue(DA->getTarget(), LV)) return;
- Value *Val = emitCoercedExpr(DA->getExpr(), resolveType(LV.TypeName));
- if (!Val) return;
- Builder->CreateStore(Val, LV.Addr);
- return;
- }
-}