1
0
mirror of https://github.com/exaloop/codon.git synced 2025-06-03 15:03:52 +08:00
codon/codon/compiler/compiler.cpp
2022-02-24 11:43:51 -08:00

142 lines
4.8 KiB
C++

#include "compiler.h"
#include "codon/parser/cache.h"
#include "codon/parser/peg/peg.h"
#include "codon/parser/visitors/doc/doc.h"
#include "codon/parser/visitors/format/format.h"
#include "codon/parser/visitors/simplify/simplify.h"
#include "codon/parser/visitors/translate/translate.h"
#include "codon/parser/visitors/typecheck/typecheck.h"
namespace codon {
namespace {
ir::transform::PassManager::Init getPassManagerInit(Compiler::Mode mode, bool isTest) {
using ir::transform::PassManager;
switch (mode) {
case Compiler::Mode::DEBUG:
return isTest ? PassManager::Init::RELEASE : PassManager::Init::DEBUG;
case Compiler::Mode::RELEASE:
return PassManager::Init::RELEASE;
case Compiler::Mode::JIT:
return PassManager::Init::JIT;
default:
return PassManager::Init::EMPTY;
}
}
} // namespace
Compiler::Compiler(const std::string &argv0, Compiler::Mode mode,
const std::vector<std::string> &disabledPasses, bool isTest)
: argv0(argv0), debug(mode == Mode::DEBUG), input(),
plm(std::make_unique<PluginManager>()),
cache(std::make_unique<ast::Cache>(argv0)),
module(std::make_unique<ir::Module>()),
pm(std::make_unique<ir::transform::PassManager>(getPassManagerInit(mode, isTest),
disabledPasses)),
llvisitor(std::make_unique<ir::LLVMVisitor>()) {
cache->module = module.get();
module->setCache(cache.get());
llvisitor->setDebug(debug);
llvisitor->setPluginManager(plm.get());
}
llvm::Error Compiler::load(const std::string &plugin) {
auto result = plm->load(plugin);
if (auto err = result.takeError())
return err;
auto *p = *result;
if (!p->info.stdlibPath.empty()) {
cache->pluginImportPaths.push_back(p->info.stdlibPath);
}
for (auto &kw : p->dsl->getExprKeywords()) {
cache->customExprStmts[kw.keyword] = kw.callback;
}
for (auto &kw : p->dsl->getBlockKeywords()) {
cache->customBlockStmts[kw.keyword] = {kw.hasExpr, kw.callback};
}
p->dsl->addIRPasses(pm.get(), debug);
return llvm::Error::success();
}
llvm::Error
Compiler::parse(bool isCode, const std::string &file, const std::string &code,
int startLine, int testFlags,
const std::unordered_map<std::string, std::string> &defines) {
input = file;
std::string abspath = (file != "-") ? ast::getAbsolutePath(file) : file;
try {
Timer t1("parse");
ast::StmtPtr codeStmt = isCode
? ast::parseCode(cache.get(), abspath, code, startLine)
: ast::parseFile(cache.get(), abspath);
t1.log();
cache->module0 = file;
if (testFlags)
cache->testFlags = testFlags;
Timer t2("simplify");
auto transformed = ast::SimplifyVisitor::apply(cache.get(), std::move(codeStmt),
abspath, defines, (testFlags > 1));
t2.log();
if (codon::getLogger().flags & codon::Logger::FLAG_USER) {
auto fo = fopen("_dump_simplify.sexp", "w");
fmt::print(fo, "{}\n", transformed->toString(0));
fclose(fo);
}
Timer t3("typecheck");
auto typechecked =
ast::TypecheckVisitor::apply(cache.get(), std::move(transformed));
t3.log();
if (codon::getLogger().flags & codon::Logger::FLAG_USER) {
auto fo = fopen("_dump_typecheck.sexp", "w");
fmt::print(fo, "{}\n", typechecked->toString(0));
for (auto &f : cache->functions)
for (auto &r : f.second.realizations)
fmt::print(fo, "{}\n", r.second->ast->toString(0));
fclose(fo);
}
Timer t4("translate");
ast::TranslateVisitor::apply(cache.get(), std::move(typechecked));
t4.log();
} catch (const exc::ParserException &e) {
return llvm::make_error<error::ParserErrorInfo>(e);
}
module->setSrcInfo({abspath, 0, 0, 0});
return llvm::Error::success();
}
llvm::Error
Compiler::parseFile(const std::string &file, int testFlags,
const std::unordered_map<std::string, std::string> &defines) {
return parse(/*isCode=*/false, file, /*code=*/"", /*startLine=*/0, testFlags,
defines);
}
llvm::Error
Compiler::parseCode(const std::string &file, const std::string &code, int startLine,
int testFlags,
const std::unordered_map<std::string, std::string> &defines) {
return parse(/*isCode=*/true, file, code, startLine, testFlags, defines);
}
llvm::Error Compiler::compile() {
pm->run(module.get());
llvisitor->visit(module.get());
return llvm::Error::success();
}
llvm::Expected<std::string> Compiler::docgen(const std::vector<std::string> &files) {
try {
auto j = ast::DocVisitor::apply(argv0, files);
return j->toString();
} catch (exc::ParserException &e) {
return llvm::make_error<error::ParserErrorInfo>(e);
}
}
} // namespace codon