Heavily modify Target.hpp, add a pointerAs function, and add an overload to Yerbacon::exit

This commit is contained in:
Username404 2021-10-28 22:18:01 +02:00
parent 4771aed6b4
commit c123965098
Signed by: Username404-59
GPG Key ID: 7AB361FBB257A5D1
7 changed files with 61 additions and 44 deletions

View File

@ -47,6 +47,7 @@ namespace Yerbacon {
std::cout << std::endl;
std::exit(EXIT_FAILURE);
}
inline void exit(const char* reason) { exit({reason}); }
class Exception: public std::exception {
std::string exceptionCause;
public:
@ -60,6 +61,10 @@ namespace Yerbacon {
};
}
#include <memory>
template<typename T, typename U>
constexpr T& pointerAs(const std::unique_ptr<U>& ptr) { return reinterpret_cast<T&>(*ptr); }
#undef YBCON_VERSION
#undef YBCON_FLAGS
#undef YBCON_COMPILER

View File

@ -89,6 +89,7 @@ public:
}
return optional<reference_wrapper<T>>();
};
inline decltype(*subComponents.data()) operator[](const unsigned int& index) const { return subComponents[index]; }
IS(StandardComponents::NamedIdentifier)
inline auto operator[](const string& key) const { return findReferenceByName<T>(key); }
inline size_t getCompCount() const { return subComponents.size(); }

View File

@ -7,18 +7,18 @@
#include <memory>
#include <sstream>
#include <cstring>
#include <unordered_map>
#include <typeindex>
#include <optional>
#include "../parsing/ParseComponents.hpp"
#define INCLUDECOMPONENT(X) virtual void on(const X& parseComponent) {}
class Target {
constexpr static const char* const interpolationString = "${";
constexpr static const char* const interpolationCloseString = "}";
protected:
virtual constexpr bool supportsOneLine() { return true; };
std::stringstream output;
INCLUDECOMPONENT(StandardComponents::Define);
INCLUDECOMPONENT(StandardComponents::types::String);
inline void stringInterpolation(const char* multiline, const string& view) { stringInterpolation(view, multiline, multiline); }
void stringInterpolation(string view, const char* openMultiline = "", const char* closeMultiline = "", const char* concatenationCharacters = "+") {
typedef string::size_type strSize;
@ -62,33 +62,38 @@ protected:
}
} else output << openCharacters << view << closeCharacters << '\n';
}
INCLUDECOMPONENT(StandardComponents::Reference);
INCLUDECOMPONENT(StandardComponents::Class);
typedef function<void (const ParseTree& parsedTree, unsigned int& index)> task;
#define make_task(X, L) make_pair(type_index(typeid(X)), [this](const ParseTree& parsedTree, unsigned int& index) { const X& parseComponent = pointerAs<X>(parsedTree[index]); L })
typedef unordered_map<type_index, optional<task>> unordered_task_map;
virtual unordered_task_map getTaskMap() = 0;
public:
unordered_task_map& getTaskMapInstance() {
static unordered_task_map staticMap = getTaskMap();
return staticMap;
};
static shared_ptr<Target> forName(string_view name, bool newLines);
#define with(X) if (id == typeid(X)) { this->on(reinterpret_cast<X&>(*component)); continue; }
const bool newLines;
string transpileWithTree(const ParseTree& tree) {
const unordered_task_map& taskMap = getTaskMapInstance();
if (not newLines && !supportsOneLine()) {
throw Yerbacon::Exception("--newlines=off is not supported by the current target");
}
output.str(string());
for (const unique_ptr<ParseComponent>& component: tree) {
for (unsigned int i = 0; i < tree.getCompCount(); ++i) {
const unique_ptr<ParseComponent>& component = tree[i];
const type_info& id = component->getId();
with(StandardComponents::Define);
with(StandardComponents::types::String);
with(StandardComponents::Reference);
with(StandardComponents::Class);
try {
const optional<task>& currentTask = taskMap.at(id);
if (currentTask.has_value()) currentTask.value()(tree, i);
} catch (const out_of_range&) {
throw Yerbacon::Exception(string(id.name()) += " is not supported by the current target");
}
}
return output.str();
};
#undef with
const bool newLines;
explicit Target(const bool newLines): newLines(newLines) {};
virtual ~Target() = default;
};
#undef INCLUDECOMPONENT
inline string transpile(const ParseTree& tree, const string_view& language, const bool newLines) {
return Target::forName(language, newLines)->transpileWithTree(tree);
}
#include "implementations/Lua.hpp"
#include "implementations/Js.hpp"
@ -121,10 +126,7 @@ shared_ptr<Target> Target::forName(string_view name, const bool newLines = true)
default: Yerbacon::exit({"\"", string(1, (char) toupper(name.at(1))).data(), name.substr(2).data(), "\" is not a valid target."});
}
#undef ADDTARGET
if (not newLines and not target->supportsOneLine()) {
name.remove_prefix(1);
throw Yerbacon::Exception(string("--newlinesoff cannot be used with --target=") += name);
}
#undef make_task
return target;
};

View File

@ -1,12 +1,16 @@
#ifndef JS_HPP
#define JS_HPP JsTarget
using namespace StandardComponents;
struct JsTarget: Target {
void on(const StandardComponents::Define& parseComponent) override {
output << (parseComponent.final ? "const " : "let ") << parseComponent.name << " = ";
}
void on(const StandardComponents::types::String& parseComponent) override {
stringInterpolation(parseComponent.content);
unordered_task_map getTaskMap() final {
return {
make_task(Define,
output << (parseComponent.final ? "const " : "let ") << parseComponent.name << " = ";
output << "ah";
),
make_task(types::String, stringInterpolation(parseComponent.content);)
};
}
using Target::Target;
};

View File

@ -1,15 +1,18 @@
#ifndef LUA_HPP
#define LUA_HPP LuaTarget
using namespace StandardComponents;
struct LuaTarget: Target {
void on(const StandardComponents::Define& parseComponent) override {
if (parseComponent.final) output << "local ";
output << parseComponent.name;
if (parseComponent.final) output << " <const>"; // TODO Find an alternative to <const> for lua <5.4
output << " = ";
}
void on(const StandardComponents::types::String& parseComponent) override {
stringInterpolation(parseComponent.content, "[[", "]]", "..");
unordered_task_map getTaskMap() final {
return {
make_task(Define,
if (parseComponent.final) output << "local ";
output << parseComponent.name;
if (parseComponent.final) output << " <const>"; // TODO Find an alternative to <const> for lua <5.4
output << " = ";
),
make_task(types::String, stringInterpolation(parseComponent.content, "[[", "]]", "..");)
};
}
using Target::Target;
};

View File

@ -1,13 +1,14 @@
#ifndef PY_HPP
#define PY_HPP PyTarget
using namespace StandardComponents;
struct PyTarget: Target {
bool supportsOneLine() final { return false; }
void on(const StandardComponents::Define& parseComponent) override {
output << parseComponent.name << " = ";
}
void on(const StandardComponents::types::String& parseComponent) override {
stringInterpolation(R"(""")", parseComponent.content);
unordered_task_map getTaskMap() final {
return {
make_task(Define, output << parseComponent.name << " = ";),
make_task(types::String, stringInterpolation(R"(""")", parseComponent.content);)
};
}
using Target::Target;
};

View File

@ -22,7 +22,7 @@ int main(int argc, char* argv[]) {
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 Yerbacon::exit("No target was provided.");
}
else if (currentArg == Argument("parallel")) parallel = true;
else if (currentArg == ArgumentAssignable("newlines")) {
@ -45,8 +45,9 @@ int main(int argc, char* argv[]) {
} else invalid_argument: Yerbacon::exit({"\"", currentArg.data(), "\" is not a valid argument."});
}
}
const auto compile = [&target, &newLines](string_view name) -> string {
string transpiledString = transpile(parseString(getFileContent(name.data())), target, newLines);
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);