Yerbacon/src/main.cpp

104 lines
4.6 KiB
C++

#include <iostream>
#include <set>
#include "headers/Yerbacon.hpp"
#include <future>
#include <filesystem>
using namespace std;
#include "headers/misc.hpp"
#include "headers/arguments.hpp"
#include "headers/transpiler/Target.hpp"
int main(int argc, char* argv[]) {
setlocale(LC_ALL, "");
string target = ".lua";
bool printResult = false,
parallel = false,
newLines = true;
set<string_view> files;
for (signed int i = 1; i < argc; ++i)
{
const string_view currentArg (argv[i]);
if (currentArg == ArgumentShort("printresult")) printResult = true;
else if (currentArg == ArgumentAssignable("target")) {
const string_view value = ArgumentAssignable::getValueFor(currentArg);
if (not value.empty()) (target = '.') += value;
else Yerbacon::exit("No target was provided.");
}
else if (currentArg == Argument("parallel")) parallel = true;
else if (currentArg == ArgumentAssignable("newlines")) {
const string_view enabled = ArgumentAssignable::getValueFor(currentArg);
if (enabled == "off") {
newLines = false;
} else if (enabled == "on") {
newLines = true;
} else goto invalid_argument;
}
else if (currentArg.ends_with(".ybcon")) files.insert(currentArg);
else {
if (argc == 2) {
if (currentArg == Argument("version")) {
cout << Yerbacon::getVersion();
} else if (currentArg == Argument("buildInfo")) {
cout << Yerbacon::getBuildInfo();
} else goto invalid_argument;
cout << '\n'; exit(EXIT_SUCCESS);
} else invalid_argument: Yerbacon::exit({"\"", currentArg.data(), "\" is not a valid argument."});
}
}
const auto currentTarget = Target::forName(target, newLines);
const auto compile = [&target, &currentTarget](string_view name) -> string {
string transpiledString = currentTarget->transpileWithTree(parseString(getFileContent(name.data())));
name.remove_suffix(6);
string outputFile;
(outputFile = name).append(target);
outputFileContent(outputFile, transpiledString);
return transpiledString;
};
int8_t exit_code = EXIT_SUCCESS;
if (!files.empty()) {
using unit = future<pair<string, optional<Yerbacon::Exception>>>;
vector<unit> Units(files.size());
const launch& Policy = not parallel ? launch::deferred : launch::async;
transform(files.cbegin(), files.cend(), Units.begin(), [&Policy, &compile](const string_view& fileName){
return async(Policy, [&fileName, &compile]() {
pair<string, optional<Yerbacon::Exception>> resultingPair;
try {
resultingPair.first = compile(fileName);
} catch (const Yerbacon::Exception& error) {
size_t lastSlash = 0;
const size_t position1 = fileName.find_last_of('/');
if (cmp_not_equal(position1, string_view::npos)) lastSlash = position1;
if constexpr(filesystem::path::preferred_separator != '/') {
const size_t position2 = fileName.find_last_of(filesystem::path::preferred_separator);
if (cmp_not_equal(position2, string_view::npos)) {
lastSlash = max(lastSlash, position2);
}
}
resultingPair.first = fileName.substr(lastSlash + 1);
resultingPair.second.emplace(error);
}
return resultingPair;
});
});
if (printResult) cout << "~~~~[Yerbacon compilation result]~~~~\n\n";
if (any_of(Units.rbegin(), Units.rend(), [&printResult](unit& currentFuture) -> bool {
const pair result = currentFuture.get();
const bool is_exception = result.second.has_value();
if (not is_exception) {
if (printResult && !(result.first.empty() || all_of(result.first.begin(), result.first.end(), [](const char& character){
return isspace(character);
}))) {
cout << result.first << '\n';
}
} else {
cout << "Compilation of " << result.first << " has failed with the following error:" << endl;
cerr << result.second.value().what() << '\n';
}
return is_exception;
})) {
exit_code = EXIT_FAILURE;
}
} else cout << "No valid file provided.\n";
return exit_code;
}