15#include <llvm/ADT/StringRef.h>
16#include <llvm/IR/Module.h>
17#include <llvm/Support/ErrorOr.h>
18#include <llvm/Support/MemoryBuffer.h>
19#include <llvm/Support/PrettyStackTrace.h>
20#include <llvm/Support/Signals.h>
21#include <llvm/Support/raw_ostream.h>
29#if __has_include("yumec-version.hpp")
30#include "yumec-version.hpp"
33static constexpr std::string_view
VERSION =
"???";
41using namespace std::string_literals;
55 return static_cast<CompilerFlags>(
static_cast<int>(a) |
static_cast<int>(b));
63 return (
static_cast<int>(a) &
static_cast<int>(b)) != 0;
67 const char* env_lib_dir = std::getenv(
"YUME_LIB_DIR");
68 if (env_lib_dir ==
nullptr)
69 env_lib_dir = YUME_LIB_DIR;
74auto compile(
const std::optional<std::string>& target_triple, std::vector<std::string> src_file_names,
77 src_file_names.insert(src_file_names.begin(),
lib_dir() +
"std.ym");
79 std::vector<yume::SourceFile> source_files{};
80 source_files.reserve(src_file_names.size());
83 std::vector<std::unique_ptr<llvm::MemoryBuffer>> inputs{};
84 inputs.reserve(src_file_names.size());
86 std::unique_ptr<llvm::raw_ostream> dot_file{};
87 std::unique_ptr<yume::diagnostic::DotVisitor> dot_visitor{};
90 dot_visitor = std::make_unique<yume::diagnostic::DotVisitor>(*dot_file);
93 for (
const auto& i : src_file_names) {
94 auto buffer = llvm::MemoryBuffer::getFileOrSTDIN(i);
96 throw std::runtime_error(
"While opening file "s + i +
": " + buffer.getError().message());
98 inputs.emplace_back(std::move(buffer.get()));
101 for (
auto& src_input : inputs) {
102 auto src_name = src_input->getBufferIdentifier().str();
103 auto src_special = src_name.front() ==
'<' && src_name.back() ==
'>';
105 src_special ? std::filesystem::path{} : std::filesystem::canonical(std::filesystem::absolute(src_name));
106 auto src_stream = std::stringstream(std::string(src_input->getBufferStart(), src_input->getBufferSize()));
107 auto& source = source_files.emplace_back(src_stream, src_path);
110 dot_visitor->visit(*source.program,
"");
114 llvm::errs() <<
"\n";
117 auto token_it = source.iterator;
118 if (!token_it.at_end()) {
119 llvm::outs() <<
"unconsumed tokens:\n";
120 while (!token_it.at_end())
121 llvm::outs() <<
" " << *token_it++ <<
"\n";
122 llvm::outs() <<
"\n";
123 llvm::outs().flush();
133 auto compiler =
yume::Compiler{target_triple, std::move(source_files)};
137 for (
const auto& i : compiler.source_files()) {
138 const std::string full_name =
"output_"s + i.path.stem().native() +
".dot";
148 compiler.write_object(
"output.s",
false);
149 compiler.write_object(
"output.o",
true);
150 llvm::outs().flush();
152 std::system(
"cc output.o -o yume.out");
159 llvm::outs() <<
"lib: " <<
lib_dir() <<
"\n";
160 llvm::outs() <<
"build-time LIB_DIR: " YUME_LIB_DIR
"\n";
161 llvm::outs() <<
"build-time SRC_DIR: " YUME_SRC_DIR
"\n";
164auto main(
int argc,
const char* argv[]) ->
int {
165 auto raw_args = std::span(argv, argc);
166 auto args = raw_args.subspan(1);
168 llvm::outs().enable_colors(llvm::outs().has_colors());
169 llvm::errs().enable_colors(llvm::errs().has_colors());
171 auto fatal_error = [&]() ->
auto& {
173 llvm::outs() <<
"\n";
174 llvm::outs().changeColor(llvm::raw_ostream::WHITE,
true) << raw_args[0];
175 llvm::outs().resetColor() <<
": ";
176 llvm::outs().changeColor(llvm::raw_ostream::RED) <<
"error";
177 llvm::outs().resetColor() <<
": ";
181 std::optional<std::string> target_triple = {};
182 std::vector<std::string> source_file_names = {};
183 bool consuming_target =
false;
184 bool done_with_flags =
false;
187 for (
const auto& arg : args) {
188 if (consuming_target) {
190 consuming_target =
false;
193 if (arg ==
"--version"s) {
197 if (arg ==
"--target"s) {
198 consuming_target =
true;
199 }
else if (arg ==
"-c"s) {
201 }
else if (arg ==
"--emit-llvm"s) {
203 }
else if (arg ==
"--emit-asm"s) {
205 }
else if (arg ==
"--emit-dot"s) {
207 }
else if (arg ==
"--emit-untyped-dot"s) {
209 }
else if (arg ==
"--dump-ast"s) {
211 }
else if (arg ==
"--no-prelude"s) {
213 }
else if (arg ==
"--"s) {
214 done_with_flags =
true;
215 }
else if (!done_with_flags && std::string(arg).starts_with(
'-')) {
216 fatal_error() <<
"unknown flag " << arg <<
"\n";
219 source_file_names.emplace_back(arg);
223 if (source_file_names.empty()) {
224 fatal_error() <<
"provide at least one source file\n";
229 llvm::EnablePrettyStackTrace();
230 llvm::setBugReportMsg(
"");
233 return compile(target_triple, source_file_names, flags);
The Compiler the the primary top-level type during compilation. A single instance is created during t...
void run()
Begin compilation!
auto visit(const ast::AST &expr, string_view label) -> PrintVisitor &override
auto open_file(nonnull< const char * > filename) -> unique_ptr< llvm::raw_pwrite_stream >
Opens a writeable stream to a file with the given filename relative to the current working directory.
static constexpr std::string_view GIT_SHORTHASH
static constexpr std::string_view VERSION
auto operator|(CompilerFlags a, CompilerFlags b) -> CompilerFlags
auto __ubsan_default_options() -> const char *
auto main(int argc, const char *argv[]) -> int
auto lib_dir() -> std::string
auto operator&(CompilerFlags a, CompilerFlags b) -> bool
auto operator|=(CompilerFlags &a, CompilerFlags b) -> CompilerFlags
auto operator~(CompilerFlags a) -> CompilerFlags
auto compile(const std::optional< std::string > &target_triple, std::vector< std::string > src_file_names, CompilerFlags flags) -> int