aboutsummaryrefslogtreecommitdiff
path: root/include/cps/FileHandler.h
blob: 50593de92df255ee54a9257abfcb6dfb1d486ef7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

#pragma once
#include "cps/FileMode.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"

namespace cps {

class RuntimeCheck;
class ExceptionHandler;

// Emits the text-file runtime: a fixed-size open-file table plus internal
// __cps_file_* helper functions, synthesized once on first use so programs
// without file statements keep their IR unchanged. The table is keyed by
// filename *content* (strcmp), so the same file may be named by many
// different buffers.
// Leaf module: methods only take and return llvm::Value*s; expression
// evaluation, type coercion and the symbol table stay in CodeGen.
class FileHandler {
    llvm::LLVMContext &Context;
    llvm::IRBuilder<> &Builder;
    llvm::Module &Module;
    RuntimeCheck &Checker;
    ExceptionHandler &Exceptions;

    static constexpr uint64_t TableSize = 16;
    bool RuntimeEmitted = false;

    // libc — declared lazily on first file use
    llvm::FunctionCallee FopenFunc, FcloseFunc, FgetcFunc, UngetcFunc,
                         FputsFunc, FputcFunc, MallocFunc, ReallocFunc,
                         StrcmpFunc;

    // open-file table
    llvm::GlobalVariable *FileNames = nullptr;   // [TableSize x ptr] STRING passed to OPENFILE
    llvm::GlobalVariable *FileHandles = nullptr; // [TableSize x ptr] FILE*
    llvm::GlobalVariable *FileModes = nullptr;   // [TableSize x i8]  0 = free slot, else FileMode

    llvm::Value *ModeReadStr = nullptr, *ModeWriteStr = nullptr, *ModeAppendStr = nullptr;

    llvm::Value *ErrOpenFail = nullptr, *ErrAlreadyOpen = nullptr, *ErrTableFull = nullptr,
                *ErrNotOpen = nullptr, *ErrNotRead = nullptr, *ErrNotWrite = nullptr,
                *ErrPastEof = nullptr;

    // synthesized helpers (internal linkage; pseudocode identifiers cannot
    // start with '_', so these names are un-collidable)
    llvm::Function *FindFn = nullptr, *OpenFn = nullptr, *ReadFn = nullptr,
                   *WriteFn = nullptr, *CloseFn = nullptr, *EofFn = nullptr;

    void setupExternalFunctions();
    void setupGlobals();
    void ensureRuntime();

    llvm::Function *createHelper(const char *Name, llvm::FunctionType *FT);
    llvm::Value *emitSlotGEP(llvm::GlobalVariable *Table, llvm::Type *ElemTy, llvm::Value *Idx);
    llvm::Value *emitLookupOrFail(llvm::Value *Name, llvm::Value *Line);
    void buildFindFn();
    void buildOpenFn();
    void buildReadFn();
    void buildWriteFn();
    void buildCloseFn();
    void buildEofFn();

public:
    FileHandler(llvm::LLVMContext &Ctx, llvm::IRBuilder<> &B, llvm::Module &M,
                RuntimeCheck &RC, ExceptionHandler &EH);

    // NameStr/DataStr are already-coerced STRING ptrs; Line is the statement's
    // source line for runtime diagnostics. All methods null-check and bail;
    // the caller (CodeGen) does the diagnostics.
    void emitOpen(llvm::Value *NameStr, FileMode Mode, int Line);
    llvm::Value *emitRead(llvm::Value *NameStr, int Line); // returns STRING ptr
    void emitWrite(llvm::Value *NameStr, llvm::Value *DataStr, int Line);
    void emitClose(llvm::Value *NameStr, int Line);
    llvm::Value *emitEof(llvm::Value *NameStr, int Line); // returns i1
};

} // namespace cps