#include #include #include #include #include "zen/config.hpp" #include "zen/po.hpp" #include "bolt/CST.hpp" #include "bolt/DiagnosticEngine.hpp" #include "bolt/Diagnostics.hpp" #include "bolt/Scanner.hpp" #include "bolt/Parser.hpp" #include "bolt/Checker.hpp" #include "bolt/Evaluator.hpp" using namespace bolt; ByteString readFile(std::string Path) { std::ifstream File(Path); ByteString Out; File.seekg(0, std::ios::end); Out.reserve(File.tellg()); File.seekg(0, std::ios::beg); Out.assign((std::istreambuf_iterator(File)), std::istreambuf_iterator()); return Out; } namespace po = zen::po; int main(int Argc, const char* Argv[]) { auto Match = po::program("bolt", "The offical compiler for the Bolt programming language") .flag(po::flag("direct-diagnostics", "Immediately print diagnostics without sorting them first")) // TODO support default values in zen::po .subcommand( po::command("check", "Check sources for programming mistakes") .pos_arg("file", po::some)) .subcommand( po::command("eval", "Run sources") .pos_arg("file", po::some) .fallback()) .parse_args(Argc, Argv) .unwrap(); ZEN_ASSERT(Match.has_subcommand()); auto DirectDiagnostics = Match.has_flag("direct-diagnostics") && Match.get_flag("direct-diagnostics"); auto [Name, Submatch] = Match.subcommand(); ConsoleDiagnostics DE; LanguageConfig Config; std::vector SourceFiles; for (auto Filename: Submatch->get_pos_args()) { auto Text = readFile(Filename); TextFile File { Filename, Text }; VectorStream Chars(Text, EOF); Scanner S(File, Chars); Punctuator PT(S); Parser P(File, PT, DE); auto SF = P.parseSourceFile(); if (SF == nullptr) { continue; } SF->setParents(); SourceFiles.push_back(SF); } DiagnosticStore DS; Checker TheChecker { Config, DirectDiagnostics ? static_cast(DE) : static_cast(DS) }; for (auto SF: SourceFiles) { TheChecker.check(SF); } auto lessThan = [](const Diagnostic* L, const Diagnostic* R) { auto N1 = L->getNode(); auto N2 = R->getNode(); if (N1 == nullptr && N2 == nullptr) { return false; } if (N1 == nullptr) { return true; } if (N2 == nullptr) { return false; } return N1->getStartLine() < N2->getStartLine() || N1->getStartColumn() < N2->getStartColumn(); }; std::sort(DS.Diagnostics.begin(), DS.Diagnostics.end(), lessThan); for (auto D: DS.Diagnostics) { DE.printDiagnostic(*D); } if (DE.hasError()) { return 1; } if (Name == "eval") { Evaluator E; Env GlobalEnv; GlobalEnv.add("print", Value::binding([](auto Args) { ZEN_ASSERT(Args.size() == 1) std::cerr << Args[0].asString() << "\n"; return Value::unit(); })); for (auto SF: SourceFiles) { // TODO add a SourceFile-local env that inherits from GlobalEnv E.evaluate(SF, GlobalEnv); } } return 0; }