From c1239650984db28c90bee5f6142827d7896cf84f Mon Sep 17 00:00:00 2001 From: Username404 Date: Thu, 28 Oct 2021 22:18:01 +0200 Subject: [PATCH] Heavily modify Target.hpp, add a pointerAs function, and add an overload to Yerbacon::exit --- src/headers/Yerbacon.hpp | 5 ++ src/headers/parsing/ParseComponents.hpp | 1 + src/headers/transpiler/Target.hpp | 48 ++++++++++--------- src/headers/transpiler/implementations/Js.hpp | 14 ++++-- .../transpiler/implementations/Lua.hpp | 19 ++++---- src/headers/transpiler/implementations/Py.hpp | 11 +++-- src/main.cpp | 7 +-- 7 files changed, 61 insertions(+), 44 deletions(-) diff --git a/src/headers/Yerbacon.hpp b/src/headers/Yerbacon.hpp index 3c5ad2d..ae98e42 100644 --- a/src/headers/Yerbacon.hpp +++ b/src/headers/Yerbacon.hpp @@ -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 +template +constexpr T& pointerAs(const std::unique_ptr& ptr) { return reinterpret_cast(*ptr); } + #undef YBCON_VERSION #undef YBCON_FLAGS #undef YBCON_COMPILER diff --git a/src/headers/parsing/ParseComponents.hpp b/src/headers/parsing/ParseComponents.hpp index 2a43270..33c8426 100644 --- a/src/headers/parsing/ParseComponents.hpp +++ b/src/headers/parsing/ParseComponents.hpp @@ -89,6 +89,7 @@ public: } return optional>(); }; + 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(key); } inline size_t getCompCount() const { return subComponents.size(); } diff --git a/src/headers/transpiler/Target.hpp b/src/headers/transpiler/Target.hpp index dee17a4..877a869 100644 --- a/src/headers/transpiler/Target.hpp +++ b/src/headers/transpiler/Target.hpp @@ -7,18 +7,18 @@ #include #include #include +#include +#include +#include #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 task; + #define make_task(X, L) make_pair(type_index(typeid(X)), [this](const ParseTree& parsedTree, unsigned int& index) { const X& parseComponent = pointerAs(parsedTree[index]); L }) + typedef unordered_map> 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 forName(string_view name, bool newLines); - - #define with(X) if (id == typeid(X)) { this->on(reinterpret_cast(*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& component: tree) { + for (unsigned int i = 0; i < tree.getCompCount(); ++i) { + const unique_ptr& 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& 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::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; }; diff --git a/src/headers/transpiler/implementations/Js.hpp b/src/headers/transpiler/implementations/Js.hpp index a697b18..59181f8 100644 --- a/src/headers/transpiler/implementations/Js.hpp +++ b/src/headers/transpiler/implementations/Js.hpp @@ -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; }; diff --git a/src/headers/transpiler/implementations/Lua.hpp b/src/headers/transpiler/implementations/Lua.hpp index 0dcf2be..556c95b 100644 --- a/src/headers/transpiler/implementations/Lua.hpp +++ b/src/headers/transpiler/implementations/Lua.hpp @@ -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 << " "; // TODO Find an alternative to 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 << " "; // TODO Find an alternative to for lua <5.4 + output << " = "; + ), + make_task(types::String, stringInterpolation(parseComponent.content, "[[", "]]", "..");) + }; } using Target::Target; }; diff --git a/src/headers/transpiler/implementations/Py.hpp b/src/headers/transpiler/implementations/Py.hpp index aab2640..dc2bf5d 100644 --- a/src/headers/transpiler/implementations/Py.hpp +++ b/src/headers/transpiler/implementations/Py.hpp @@ -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; }; diff --git a/src/main.cpp b/src/main.cpp index 54ff8e1..5d7ad8a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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, ¤tTarget](string_view name) -> string { + string transpiledString = currentTarget->transpileWithTree(parseString(getFileContent(name.data()))); name.remove_suffix(6); string outputFile; (outputFile = name).append(target);