aboutsummaryrefslogtreecommitdiff
path: root/src/brussel.codegen.comp/CodegenUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/brussel.codegen.comp/CodegenUtils.cpp')
-rw-r--r--src/brussel.codegen.comp/CodegenUtils.cpp171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/brussel.codegen.comp/CodegenUtils.cpp b/src/brussel.codegen.comp/CodegenUtils.cpp
new file mode 100644
index 0000000..5bc5d79
--- /dev/null
+++ b/src/brussel.codegen.comp/CodegenUtils.cpp
@@ -0,0 +1,171 @@
+#include "CodegenUtils.hpp"
+
+#include <Macros.hpp>
+#include <ScopeGuard.hpp>
+#include <Utils.hpp>
+
+#include <cstdio>
+#include <cstdlib>
+
+using namespace std::literals;
+
+bool Utils::WriteOutputFile(const CodegenOutput& output, const char* path) {
+ auto outputFile = Utils::OpenCstdioFile(path, Utils::WriteTruncate);
+ if (!outputFile) {
+ printf("[ERROR] unable to open output file %s\n", path);
+ return false;
+ }
+ DEFER {
+ fclose(outputFile);
+ };
+
+ DEBUG_PRINTF("Writing output %s\n", path);
+ output.Write(outputFile);
+
+ return true;
+}
+
+std::string Utils::JoinNames(DeclNamespace* ns, std::string_view prefix, std::string_view suffix, std::string_view delimiter) {
+ size_t length = 0;
+ if (!prefix.empty()) {
+ length += prefix.length() + delimiter.length();
+ }
+ if (!suffix.empty()) {
+ length += suffix.length() + delimiter.length();
+ }
+ size_t nsCount = 0;
+ {
+ DeclNamespace* curr = ns;
+ while (curr) {
+ length += curr->name.length() + delimiter.length();
+
+ curr = curr->container;
+ ++nsCount;
+ }
+ }
+ length -= delimiter.length();
+
+ std::string joined;
+ joined.reserve(length);
+
+ if (!prefix.empty()) {
+ joined += prefix;
+ joined += delimiter;
+ }
+ {
+ DeclNamespace* curr = ns;
+ size_t i = 0;
+ while (curr) {
+ joined += curr->name;
+ if (!suffix.empty() || i != (nsCount - 1)) {
+ joined += delimiter;
+ }
+
+ curr = curr->container;
+ ++i;
+ }
+ }
+ if (!suffix.empty()) {
+ joined += suffix;
+ }
+
+ return joined;
+}
+
+std::string Utils::MakeFullName(std::string_view name, DeclNamespace* ns) {
+ return JoinNames(ns, ""sv, name, "::"sv);
+}
+
+std::string Utils::MakeMangledName(std::string_view name, DeclNamespace* ns) {
+ return JoinNames(ns, ""sv, name, "_"sv);
+}
+
+// NOTE: assuming we are only dealing with ASCII characters
+static bool IsLowerCase(char c) {
+ return c >= 'a' && c <= 'z';
+}
+static bool IsUpperCase(char c) {
+ return c >= 'A' && c <= 'Z';
+}
+static bool IsAlphabetic(char c) {
+ return IsLowerCase(c) || IsUpperCase(c);
+}
+static char MakeUpperCase(char c) {
+ if (IsAlphabetic(c)) {
+ return IsUpperCase(c)
+ ? c
+ : ('A' + (c - 'a'));
+ }
+ return c;
+}
+
+std::vector<std::string_view> Utils::SplitIdentifier(std::string_view name) {
+ // TODO handle SCREAMING_CASE
+
+ size_t chunkStart = 0;
+ size_t chunkEnd = 0;
+ std::vector<std::string_view> result;
+ auto PushChunk = [&]() { result.push_back(std::string_view(name.begin() + chunkStart, name.begin() + chunkEnd)); };
+ while (chunkEnd < name.size()) {
+ char c = name[chunkEnd];
+ if (IsUpperCase(c)) {
+ // Start of next chunk, using camelCase or PascalCase
+ PushChunk();
+ chunkStart = chunkEnd;
+ chunkEnd = chunkStart + 1;
+ continue;
+ } else if (c == '_') {
+ // End of this chunk, using snake_case
+ PushChunk();
+ chunkStart = chunkEnd + 1;
+ chunkEnd = chunkStart + 1;
+ continue;
+ } else if (c == '-') {
+ // End of this chunk, using kebab-case
+ PushChunk();
+ chunkStart = chunkEnd + 1;
+ chunkEnd = chunkStart + 1;
+ continue;
+ }
+ ++chunkEnd;
+ }
+
+ if ((chunkEnd - chunkStart) >= 1) {
+ PushChunk();
+ }
+
+ return result;
+}
+
+std::string Utils::MakePascalCase(std::string_view name) {
+ std::string result;
+ for (auto part : SplitIdentifier(name)) {
+ result += MakeUpperCase(part[0]);
+ result += part.substr(1);
+ }
+ return result;
+}
+
+void Utils::ProduceGeneratedHeader(const char* headerFilename, CodegenOutput& header, const char* sourceFilename, CodegenOutput& source) {
+ CodegenOutputThing headerOut;
+ headerOut.text += &R"""(
+// This file is generated. Any changes will be overidden when building.
+#include <MetadataBase.hpp>
+#include <cstddef>
+#include <cstdint>
+)"""[1];
+
+ CodegenOutputThing sourceOut;
+ APPEND_LIT_LN(sourceOut.text, "// This file is generated. Any changes will be overidden when building.");
+ APPEND_FMT_LN(sourceOut.text, "#include \"%s\"", headerFilename);
+ sourceOut.text += &R"""(
+#include <frozen/string.h>
+#include <frozen/unordered_map.h>
+#include <MetadataDetails.hpp>
+using namespace std::literals;
+using namespace Metadata;
+)"""[1];
+
+ header.AddOutputThing(std::move(headerOut), 0);
+ source.AddOutputThing(std::move(sourceOut), 0);
+}