Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2021-2024 ChilliBits. All rights reserved. | ||
2 | |||
3 | #pragma once | ||
4 | |||
5 | #include <string> | ||
6 | |||
7 | #include <ast/ASTNodes.h> | ||
8 | #include <exception/AntlrThrowingErrorListener.h> | ||
9 | #include <global/RuntimeModuleManager.h> | ||
10 | #include <symboltablebuilder/Scope.h> | ||
11 | #include <util/CompilerWarning.h> | ||
12 | |||
13 | #include <llvm/IR/IRBuilder.h> | ||
14 | #include <llvm/Target/TargetMachine.h> | ||
15 | |||
16 | // Ignore some warnings in ANTLR generated code | ||
17 | #pragma GCC diagnostic push | ||
18 | #pragma GCC diagnostic ignored "-Woverloaded-virtual" | ||
19 | #include <SpiceLexer.h> | ||
20 | #include <SpiceParser.h> | ||
21 | #pragma GCC diagnostic pop | ||
22 | |||
23 | namespace spice::compiler { | ||
24 | |||
25 | // Forward declarations | ||
26 | class GlobalResourceManager; | ||
27 | class EntryNode; | ||
28 | class ASTNode; | ||
29 | class Timer; | ||
30 | struct CliOptions; | ||
31 | |||
32 | enum CompileStageType : uint8_t { | ||
33 | NONE, | ||
34 | LEXER, | ||
35 | PARSER, | ||
36 | CST_VISUALIZER, | ||
37 | AST_BUILDER, | ||
38 | AST_VISUALIZER, | ||
39 | IMPORT_COLLECTOR, | ||
40 | SYMBOL_TABLE_BUILDER, | ||
41 | TYPE_CHECKER_PRE, | ||
42 | TYPE_CHECKER_POST, | ||
43 | IR_GENERATOR, | ||
44 | IR_OPTIMIZER, | ||
45 | OBJECT_EMITTER, | ||
46 | FINISHED | ||
47 | }; | ||
48 | |||
49 | enum CompileStageIOType : uint8_t { | ||
50 | IO_CODE, | ||
51 | IO_TOKENS, | ||
52 | IO_CST, | ||
53 | IO_AST, | ||
54 | IO_IR, | ||
55 | IO_OBJECT_FILE, | ||
56 | }; | ||
57 | |||
58 | struct SourceFileAntlrCtx { | ||
59 | // Create error handlers for lexer and parser | ||
60 | std::unique_ptr<AntlrThrowingErrorListener> lexerErrorHandler; | ||
61 | std::unique_ptr<AntlrThrowingErrorListener> parserErrorHandler; | ||
62 | std::unique_ptr<antlr4::ANTLRInputStream> inputStream; | ||
63 | std::unique_ptr<SpiceLexer> lexer; | ||
64 | std::unique_ptr<antlr4::CommonTokenStream> tokenStream; | ||
65 | std::unique_ptr<SpiceParser> parser; | ||
66 | }; | ||
67 | |||
68 | struct TimerOutput { | ||
69 | uint64_t lexer = 0; | ||
70 | uint64_t parser = 0; | ||
71 | uint64_t cstVisualizer = 0; | ||
72 | uint64_t astBuilder = 0; | ||
73 | uint64_t astVisualizer = 0; | ||
74 | uint64_t importCollector = 0; | ||
75 | uint64_t symbolTableBuilder = 0; | ||
76 | uint64_t typeCheckerPre = 0; | ||
77 | uint64_t typeCheckerPost = 0; | ||
78 | uint64_t irGenerator = 0; | ||
79 | uint64_t irOptimizer = 0; | ||
80 | uint64_t objectEmitter = 0; | ||
81 | }; | ||
82 | |||
83 | struct CompilerOutput { | ||
84 | std::string cstString; | ||
85 | std::string astString; | ||
86 | std::string symbolTableString; | ||
87 | std::string irString; | ||
88 | std::string irOptString; | ||
89 | std::string asmString; | ||
90 | std::string typesString; | ||
91 | std::vector<CompilerWarning> warnings; | ||
92 | TimerOutput times; | ||
93 | }; | ||
94 | |||
95 | struct NameRegistryEntry { | ||
96 | std::string name; | ||
97 | uint64_t typeId; // Set for structs, interfaces, enums and aliases | ||
98 | SymbolTableEntry *targetEntry; | ||
99 | Scope *targetScope; | ||
100 | SymbolTableEntry *importEntry = nullptr; | ||
101 | }; | ||
102 | |||
103 | class SourceFile { | ||
104 | public: | ||
105 | // Constructors | ||
106 | SourceFile(GlobalResourceManager &resourceManager, SourceFile *parent, std::string name, const std::filesystem::path &filePath, | ||
107 | bool stdFile); | ||
108 | SourceFile(const SourceFile &) = delete; | ||
109 | |||
110 | // Friend classes | ||
111 | friend class RuntimeModuleManager; | ||
112 | |||
113 | // Compiler pipeline triggers | ||
114 | void runLexer(); | ||
115 | void runParser(); | ||
116 | void runCSTVisualizer(); | ||
117 | void runASTBuilder(); | ||
118 | void runASTVisualizer(); | ||
119 | void runImportCollector(); | ||
120 | void runSymbolTableBuilder(); | ||
121 | void runTypeChecker(); | ||
122 | |||
123 | private: | ||
124 | void runTypeCheckerPre(); | ||
125 | void runTypeCheckerPost(); | ||
126 | |||
127 | public: | ||
128 | void runIRGenerator(); | ||
129 | void runDefaultIROptimizer(); | ||
130 | void runPreLinkIROptimizer(); | ||
131 | void runBitcodeLinker(); | ||
132 | void runPostLinkIROptimizer(); | ||
133 | void runObjectEmitter(); | ||
134 | void concludeCompilation(); | ||
135 | |||
136 | // Shortcuts | ||
137 | void runFrontEnd(); | ||
138 | void runMiddleEnd(); | ||
139 | void runBackEnd(); | ||
140 | |||
141 | // Public methods | ||
142 | void addDependency(SourceFile *sourceFile, const ASTNode *declNode, const std::string &dependencyName, const std::string &path); | ||
143 | [[nodiscard]] bool imports(const SourceFile *sourceFile) const; | ||
144 | [[nodiscard]] bool isAlreadyImported(const std::string &filePathSearch, std::stack<const SourceFile *> &circle) const; | ||
145 | SourceFile *requestRuntimeModule(RuntimeModule runtimeModule); | ||
146 | bool isRuntimeModuleAvailable(RuntimeModule runtimeModule) const; | ||
147 | void addNameRegistryEntry(const std::string &symbolName, uint64_t typeId, SymbolTableEntry *entry, Scope *scope, | ||
148 | bool keepNewOnCollision = true, SymbolTableEntry *importEntry = nullptr); | ||
149 | [[nodiscard]] const NameRegistryEntry *getNameRegistryEntry(const std::string &symbolName) const; | ||
150 | [[nodiscard]] llvm::Type *getLLVMType(const Type *type); | ||
151 | void checkForSoftErrors() const; | ||
152 | void collectAndPrintWarnings(); | ||
153 | const SourceFile *getRootSourceFile() const; | ||
154 | bool isRT(RuntimeModule runtimeModule) const; | ||
155 |
3/6✓ Branch 1 taken 938 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 157 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 23 times.
✗ Branch 8 not taken.
|
1171 | ALWAYS_INLINE bool isStringRT() const { return isRT(STRING_RT); } |
156 |
1/2✓ Branch 1 taken 880 times.
✗ Branch 2 not taken.
|
880 | ALWAYS_INLINE bool isMemoryRT() const { return isRT(MEMORY_RT); } |
157 |
2/4✓ Branch 1 taken 322 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 136 times.
✗ Branch 5 not taken.
|
458 | ALWAYS_INLINE bool isRttiRT() const { return isRT(RTTI_RT); } |
158 | |||
159 | // Public fields | ||
160 | std::string name; | ||
161 | std::string fileName; | ||
162 | std::filesystem::path filePath; | ||
163 | std::string fileDir; | ||
164 | bool isStdFile = false; | ||
165 | bool isMainFile = true; | ||
166 | bool alwaysKeepSymbolsOnNameCollision = false; | ||
167 | bool ignoreWarnings = false; | ||
168 | bool restoredFromCache = false; | ||
169 | bool reVisitRequested = false; | ||
170 | CompileStageType previousStage = NONE; | ||
171 | SourceFileAntlrCtx antlrCtx; | ||
172 | CompilerOutput compilerOutput; | ||
173 | SourceFile *parent; | ||
174 | std::string cacheKey; | ||
175 | EntryNode *ast = nullptr; | ||
176 | std::unique_ptr<Scope> globalScope; | ||
177 | llvm::LLVMContext context; | ||
178 | llvm::IRBuilder<> builder; | ||
179 | std::unique_ptr<llvm::TargetMachine> targetMachine; | ||
180 | std::unique_ptr<llvm::Module> llvmModule; | ||
181 | std::map<std::string, SourceFile *> dependencies; // Has to be an ordered map to keep the compilation order deterministic | ||
182 | std::vector<const SourceFile *> dependants; | ||
183 | std::unordered_map<std::string, NameRegistryEntry> exportedNameRegistry; | ||
184 | std::vector<const Function *> testFunctions; | ||
185 | |||
186 | private: | ||
187 | // Private fields | ||
188 | GlobalResourceManager &resourceManager; | ||
189 | const CliOptions &cliOptions; | ||
190 | std::unordered_map<const Type *, llvm::Type *> typeToLLVMTypeMapping; | ||
191 | uint8_t importedRuntimeModules = 0; | ||
192 | uint8_t totalTypeCheckerRuns = 0; | ||
193 | |||
194 | // Private methods | ||
195 | bool haveAllDependantsBeenTypeChecked() const; | ||
196 | void mergeNameRegistries(const SourceFile &importedSourceFile, const std::string &importName); | ||
197 | void dumpOutput(const std::string &content, const std::string &caption, const std::string &fileSuffix) const; | ||
198 | void visualizerPreamble(std::stringstream &output) const; | ||
199 | void visualizerOutput(std::string outputName, const std::string &output) const; | ||
200 | void printStatusMessage(const char *stage, const CompileStageIOType &in, const CompileStageIOType &out, uint64_t stageRuntime, | ||
201 | unsigned short stageRuns = 0) const; | ||
202 | }; | ||
203 | |||
204 | } // namespace spice::compiler | ||
205 |