aboutsummaryrefslogtreecommitdiff
path: root/source/CodegenCompiler/CodegenUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/CodegenCompiler/CodegenUtils.cpp')
-rw-r--r--source/CodegenCompiler/CodegenUtils.cpp146
1 files changed, 146 insertions, 0 deletions
diff --git a/source/CodegenCompiler/CodegenUtils.cpp b/source/CodegenCompiler/CodegenUtils.cpp
new file mode 100644
index 0000000..0c70cb6
--- /dev/null
+++ b/source/CodegenCompiler/CodegenUtils.cpp
@@ -0,0 +1,146 @@
+#include "CodegenUtils.hpp"
+
+#include <Macros.hpp>
+#include <ScopeGuard.hpp>
+#include <Utils.hpp>
+
+#include <cstdio>
+#include <cstdlib>
+
+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::MakeFullName(std::string_view name, DeclNamespace* ns) {
+ size_t length = 0;
+ std::vector<std::string_view> components;
+ if (!name.empty()) {
+ components.push_back(name);
+ length += name.length();
+ }
+
+ DeclNamespace* currentNamespace = ns;
+ while (currentNamespace) {
+ components.push_back(currentNamespace->name);
+ length += currentNamespace->name.size() + /*::*/ 2;
+ currentNamespace = currentNamespace->container;
+ }
+
+ std::string fullname;
+ fullname.reserve(length);
+ for (auto it = components.rbegin(); it != components.rend(); ++it) {
+ fullname += *it;
+ fullname += "::";
+ }
+ // Get rid of the last "::"
+ fullname.pop_back();
+ fullname.pop_back();
+
+ return fullname;
+}
+
+// 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.
+#pragma once
+#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 <MetadataDetails.hpp>
+#include <frozen/string.h>
+#include <frozen/unordered_map.h>
+using namespace std::literals;
+)"""[1];
+
+ header.AddOutputThing(std::move(headerOut));
+ source.AddOutputThing(std::move(sourceOut));
+}
+
+void Utils::ProduceClassTypeInfo(CodegenOutput& source, std::string_view className, const DeclNamespace* ns) {
+ CodegenOutputThing thing;
+
+ source.AddOutputThing(std::move(thing));
+}