2022-08-19 19:52:57 +02:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
2023-05-24 14:11:59 +02:00
|
|
|
#include <algorithm>
|
2022-08-19 19:52:57 +02:00
|
|
|
|
|
|
|
#include "zen/config.hpp"
|
2023-06-04 22:46:44 +02:00
|
|
|
#include "zen/po.hpp"
|
2022-08-19 19:52:57 +02:00
|
|
|
|
|
|
|
#include "bolt/CST.hpp"
|
2023-05-24 19:38:04 +02:00
|
|
|
#include "bolt/DiagnosticEngine.hpp"
|
2022-08-19 19:52:57 +02:00
|
|
|
#include "bolt/Diagnostics.hpp"
|
|
|
|
#include "bolt/Scanner.hpp"
|
|
|
|
#include "bolt/Parser.hpp"
|
2022-08-21 16:25:52 +02:00
|
|
|
#include "bolt/Checker.hpp"
|
2023-06-03 11:54:31 +02:00
|
|
|
#include "bolt/Evaluator.hpp"
|
2022-08-19 19:52:57 +02:00
|
|
|
|
|
|
|
using namespace bolt;
|
|
|
|
|
2022-08-24 20:57:26 +02:00
|
|
|
ByteString readFile(std::string Path) {
|
2022-08-19 19:52:57 +02:00
|
|
|
|
|
|
|
std::ifstream File(Path);
|
2022-08-24 20:57:26 +02:00
|
|
|
ByteString Out;
|
2022-08-19 19:52:57 +02:00
|
|
|
|
2023-06-04 22:46:44 +02:00
|
|
|
File.seekg(0, std::ios::end);
|
2022-08-19 19:52:57 +02:00
|
|
|
Out.reserve(File.tellg());
|
|
|
|
File.seekg(0, std::ios::beg);
|
|
|
|
|
|
|
|
Out.assign((std::istreambuf_iterator<char>(File)),
|
|
|
|
std::istreambuf_iterator<char>());
|
|
|
|
|
|
|
|
return Out;
|
|
|
|
}
|
|
|
|
|
2023-06-04 22:46:44 +02:00
|
|
|
namespace po = zen::po;
|
2022-08-19 19:52:57 +02:00
|
|
|
|
2023-06-04 22:46:44 +02:00
|
|
|
int main(int Argc, const char* Argv[]) {
|
|
|
|
|
|
|
|
auto Match = po::program("bolt", "The offical compiler for the Bolt programming language")
|
|
|
|
.flag(po::flag<bool>("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<bool>("direct-diagnostics");
|
|
|
|
|
|
|
|
auto [Name, Submatch] = Match.subcommand();
|
2022-08-19 19:52:57 +02:00
|
|
|
|
2022-08-21 20:56:58 +02:00
|
|
|
ConsoleDiagnostics DE;
|
2023-05-20 23:48:26 +02:00
|
|
|
LanguageConfig Config;
|
2022-08-21 20:56:58 +02:00
|
|
|
|
2023-06-04 22:46:44 +02:00
|
|
|
std::vector<SourceFile*> SourceFiles;
|
2022-08-19 19:52:57 +02:00
|
|
|
|
2023-06-04 22:46:44 +02:00
|
|
|
for (auto Filename: Submatch->get_pos_args()) {
|
2022-08-19 19:52:57 +02:00
|
|
|
|
2023-06-04 22:46:44 +02:00
|
|
|
auto Text = readFile(Filename);
|
|
|
|
TextFile File { Filename, Text };
|
|
|
|
VectorStream<ByteString, Char> 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);
|
|
|
|
}
|
2022-08-24 12:36:43 +02:00
|
|
|
|
2023-05-24 14:11:59 +02:00
|
|
|
DiagnosticStore DS;
|
2023-06-04 22:46:44 +02:00
|
|
|
Checker TheChecker { Config, DirectDiagnostics ? static_cast<DiagnosticEngine&>(DE) : static_cast<DiagnosticEngine&>(DS) };
|
2022-08-21 16:25:52 +02:00
|
|
|
|
2023-06-04 22:46:44 +02:00
|
|
|
for (auto SF: SourceFiles) {
|
|
|
|
TheChecker.check(SF);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto lessThan = [](const Diagnostic* L, const Diagnostic* R) {
|
2023-05-24 14:11:59 +02:00
|
|
|
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();
|
|
|
|
};
|
2023-06-04 22:46:44 +02:00
|
|
|
std::sort(DS.Diagnostics.begin(), DS.Diagnostics.end(), lessThan);
|
2023-05-24 14:11:59 +02:00
|
|
|
|
|
|
|
for (auto D: DS.Diagnostics) {
|
2023-05-24 19:38:04 +02:00
|
|
|
DE.printDiagnostic(*D);
|
2023-05-24 14:11:59 +02:00
|
|
|
}
|
|
|
|
|
2023-06-03 11:54:31 +02:00
|
|
|
if (DE.hasError()) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2023-06-04 22:46:44 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2023-06-03 11:54:31 +02:00
|
|
|
|
2022-08-19 19:52:57 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|