Heavily modify Target.hpp, add a pointerAs function, and add an overload to Yerbacon::exit
This commit is contained in:
parent
4771aed6b4
commit
c123965098
|
@ -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
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue