diff options
author | Matthew Kosarek <mattkae@protonmail.com> | 2021-07-01 19:46:08 -0400 |
---|---|---|
committer | Matthew Kosarek <mattkae@protonmail.com> | 2021-07-01 19:46:08 -0400 |
commit | 4878f0fc6a039d220dd7adecb18d19c688ae50b0 (patch) | |
tree | 993893f1d894aedb350e86c759370c0e8c54c443 /tools/transpiler | |
parent | 9f968320c83ce79f98006dec71674feff4686e3b (diff) |
(mkosarek) Decent SAT description for now
Diffstat (limited to 'tools/transpiler')
-rw-r--r-- | tools/transpiler/List.h | 222 | ||||
-rw-r--r-- | tools/transpiler/Logger.cpp | 123 | ||||
-rw-r--r-- | tools/transpiler/Logger.h | 43 | ||||
-rw-r--r-- | tools/transpiler/MathHelper.h | 33 | ||||
-rw-r--r-- | tools/transpiler/MyString.cpp | 392 | ||||
-rw-r--r-- | tools/transpiler/MyString.h | 76 | ||||
-rwxr-xr-x | tools/transpiler/build.sh | 1 | ||||
-rw-r--r-- | tools/transpiler/pages.txt | 16 | ||||
-rw-r--r-- | tools/transpiler/replacer.cpp | 128 | ||||
-rw-r--r-- | tools/transpiler/replacer.h | 3 | ||||
-rwxr-xr-x | tools/transpiler/transpiler | bin | 0 -> 52160 bytes | |||
-rw-r--r-- | tools/transpiler/transpiler.cpp | 255 |
12 files changed, 1292 insertions, 0 deletions
diff --git a/tools/transpiler/List.h b/tools/transpiler/List.h new file mode 100644 index 0000000..00a466a --- /dev/null +++ b/tools/transpiler/List.h @@ -0,0 +1,222 @@ +#pragma once +#include <cstdlib> +#include <cstring> +#include "Logger.h" + +#define FOREACH(list) \ + for (size_t idx = 0; idx < list.numElements; idx++) \ + if (auto value = list.getValue(idx)) \ + + +template <typename T> +struct List { + T* data = nullptr; + size_t capacity = 0; + size_t numElements = 0; + bool growDynamically = true; + + void allocate(size_t size); + void add(T* element); + void add(T& element); + void add(T&& element); + bool grow(size_t newSize); + void set(T* value, size_t index); + void remove(size_t index); + void clear(); + void deallocate(); + bool isEmpty() { + return data == nullptr || numElements == 0; + } + T* getValue(int index) const; + T& operator[](int idx) const; + void binarySort(int (*f)(T *first, T* second)); + void setFromArray(T* arry, int size) { + allocate(size); + memcpy(data, arry, size * sizeof(T)); + numElements = size; + } + void remove(int index) { + if (index >= numElements) { + logger_error("Cannot remove element at index: %d", index); + return; + } + + + if (index == numElements - 1) { + numElements--; + return; + } + + memmove(data[index], data[index + 1], sizeof(T) * (numElements - index)); + numElements--; + } +}; + +template <typename T> +void List<T>::allocate(size_t size) { + if (size == 0 || size == capacity) { + numElements = 0; + return; + } + + if (data != nullptr) { + deallocate(); + } + + data = static_cast<T*>(malloc(sizeof(T) * size)); + capacity = size; + numElements = 0; +} + +template <typename T> +bool List<T>::grow(size_t newSize) { + if (!growDynamically) { + return false; + } + + if (newSize == 0) { + return false; + } + + T* newData = static_cast<T*>(malloc(sizeof(T) * newSize)); + + if (data != nullptr) { + memcpy(newData, data, numElements * sizeof(T)); + delete data; + } + + data = newData; + capacity = newSize; + return true; +} + +template <typename T> +void List<T>::set(T* value, size_t index) { + if (index >= capacity && !grow(index * 2)) { + return; + } + + memcpy(&data[index], value, sizeof(T)); +} + +template <typename T> +void List<T>::add(T* element) { + if (data == nullptr) { + allocate(2); + } + + if (element == nullptr) { + logger_error("Element not defined"); + return; + } + + size_t newNumElements = numElements + 1; + if (newNumElements > capacity) { + if (!grow(2 * capacity)) { + logger_error("Trying to add to list but unable to grow the array"); + return; + } + } + + memcpy(&data[numElements], element, sizeof(T)); + numElements = newNumElements; +} + +template <typename T> +void List<T>::add(T& element) { + if (data == nullptr) { + allocate(2); + } + + size_t newNumElements = numElements + 1; + if (newNumElements > capacity) { + if (!grow(2 * capacity)) { + logger_error("Trying to add to list but unable to grow the array"); + return; + } + } + + memcpy(&data[numElements], &element, sizeof(T)); + numElements = newNumElements; +} + +template <typename T> +void List<T>::add(T&& element) { + if (data == nullptr) { + allocate(2); + } + + size_t newNumElements = numElements + 1; + if (newNumElements > capacity) { + if (!grow(2 * capacity)) { + logger_error("Trying to add to list but unable to grow the array"); + return; + } + } + + memcpy(&data[numElements], &element, sizeof(T)); + numElements = newNumElements; +} + +template <typename T> +void List<T>::remove(size_t idx) { + if (idx >= numElements) { + logger_error("Index is outside of the list: %d >= %d", idx, numElements); + return; + } + + for (; idx < numElements - 1; idx++) { + data[idx] = data[idx + 1]; + } + + numElements--; +} + +template <typename T> +void List<T>::deallocate() { + if (data != nullptr) { + free(data); + data = nullptr; + } + + capacity = 0; + numElements = 0; +} + +template <typename T> +void List<T>::clear() { + numElements = 0; +} + +template <typename T> +T* List<T>::getValue(int idx) const { + return &data[idx]; +} + +template <typename T> +T& List<T>::operator[](int idx) const { + return data[idx]; +} + +template <typename T> +void List<T>::binarySort(int (*f)(T *first, T* second)) { + if (data == nullptr) { + return; + } + + for (size_t idx = 0; idx < numElements - 1; idx++) { + int minIdx = idx; + T firstValue = data[idx]; + + for (int innerIdx = idx + 1; innerIdx < numElements; innerIdx++) {\ + T secondValue = data[innerIdx]; + if (f(&firstValue, &secondValue) > 0) { + minIdx= innerIdx; + } + } + + T temp = data[minIdx]; + memmove(&data[minIdx], &data[idx], sizeof(T)); + memmove(&data[idx], &temp, sizeof(T)); + } +} diff --git a/tools/transpiler/Logger.cpp b/tools/transpiler/Logger.cpp new file mode 100644 index 0000000..1068d88 --- /dev/null +++ b/tools/transpiler/Logger.cpp @@ -0,0 +1,123 @@ +#include "Logger.h" +#include <chrono> +#include <cstdarg> +#include <cstdio> + +namespace Logger { + LogLevel gLogLevel = LogLevel_Debug; + FILE* gFilePointer = NULL; + + void initialize(LoggerOptions options) { + setLevel(options.level); + if (options.logToFile) { +#ifdef WIN32 + fopen_s(&gFilePointer, options.filePath, "a"); +#else + gFilePointer = fopen(options.filePath, "a"); +#endif + } + } + + void setLevel(LogLevel level) { + gLogLevel = level; + } + + LogLevel getLevel() { + return gLogLevel; + } + + void printHeader(const char* levelStr, const char* fileName, int lineNumber) { + time_t t = time(0); + tm now; +#ifdef WIN32 + localtime_s(&now, &t); +#else + now = *localtime(&t); +#endif + + printf("%s:%d [%d-%d-%d %d:%d:%d] %s: ", fileName, lineNumber, (now.tm_year + 1900), (now.tm_mon + 1), now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec, levelStr); + if (gFilePointer != NULL) { + fprintf(gFilePointer, "[%d-%d-%d %d:%d:%d] %s: ", (now.tm_year + 1900), (now.tm_mon + 1), now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec, levelStr); + } + } + + void logInternal(const char* file, int lineNumber,LogLevel level, const char* format, va_list args) { + if (level < gLogLevel) { + return; + } + + + const char* levelStr; + switch (level) { + case LogLevel_Debug: + levelStr = "Debug"; + break; + case LogLevel_Info: + levelStr = "Info"; + break; + case LogLevel_Warn: + levelStr = "Warning"; + break; + case LogLevel_Error: + levelStr = "Error"; + break; + default: + levelStr = "Unknown"; + break; + } + + if (gFilePointer != NULL) { + va_list fileArgs; + va_copy(fileArgs, args); + vfprintf(gFilePointer, format, fileArgs); + fprintf(gFilePointer, "\n"); + } + + printHeader(levelStr, file, lineNumber); + + vprintf(format, args); + printf("\n"); + } + + void doLog(const char* file, int lineNumber,LogLevel level, const char* format, ...) { + va_list args; + va_start(args, format); + logInternal(file, lineNumber, level, format, args); + va_end(args); + } + + void doDebug(const char* file, int lineNumber,const char* format, ...) { + va_list args; + va_start(args, format); + logInternal(file, lineNumber, LogLevel_Debug, format, args); + va_end(args); + } + + void doInfo(const char* file, int lineNumber,const char* format, ...) { + va_list args; + va_start(args, format); + logInternal(file, lineNumber, LogLevel_Info, format, args); + va_end(args); + } + + void doWarning(const char* file, int lineNumber,const char* format, ...) { + va_list args; + va_start(args, format); + logInternal(file, lineNumber, LogLevel_Warn, format, args); + va_end(args); + } + + void doError(const char* file, int lineNumber,const char* format, ...) { + va_list args; + va_start(args, format); + logInternal(file, lineNumber, LogLevel_Error, format, args); + va_end(args); + } + + void free() { + if (gFilePointer) { + fclose(gFilePointer); + gFilePointer = NULL; + } + } +} diff --git a/tools/transpiler/Logger.h b/tools/transpiler/Logger.h new file mode 100644 index 0000000..7596b6f --- /dev/null +++ b/tools/transpiler/Logger.h @@ -0,0 +1,43 @@ +#ifndef LOGGER_H +#define LOGGER_H + +#include <cstring> + +enum LogLevel { + LogLevel_Debug = 0, + LogLevel_Info = 1, + LogLevel_Warn = 2, + LogLevel_Error = 3 +}; + +struct LoggerOptions { + LogLevel level = LogLevel_Debug; + bool logToFile = false; + const char* filePath = "debug.log"; +}; + +namespace Logger { + void initialize(LoggerOptions options); + void setLevel(LogLevel level); + LogLevel getLevel(); + void doLog(const char* file, int lineNumber, LogLevel level, const char* format, ...); + void doDebug(const char* file, int lineNumber, const char* format, ...); + void doInfo(const char* file, int lineNumber, const char* format, ...); + void doWarning(const char* file, int lineNumber, const char* format, ...); + void doError(const char* file, int lineNumber, const char* format, ...); + void free(); +}; + +#if WIN32 +#define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) +#else +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) +#endif + +#define logger_log(level, format, ...) Logger::doLog(__FILENAME__, __LINE__, level, format, ## __VA_ARGS__) +#define logger_debug(format, ...) Logger::doDebug(__FILENAME__, __LINE__, format, ## __VA_ARGS__) +#define logger_info(format, ...) Logger::doInfo(__FILENAME__, __LINE__, format, ## __VA_ARGS__) +#define logger_warning(format, ...) Logger::doWarning(__FILENAME__, __LINE__, format, ## __VA_ARGS__) +#define logger_error(format, ...) Logger::doError(__FILENAME__, __LINE__, format, ## __VA_ARGS__) + +#endif diff --git a/tools/transpiler/MathHelper.h b/tools/transpiler/MathHelper.h new file mode 100644 index 0000000..b9c9cb6 --- /dev/null +++ b/tools/transpiler/MathHelper.h @@ -0,0 +1,33 @@ +#pragma once + +#define PI 3.14159265358979323846f + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) +#define CLAMP(x, upper, lower) (MIN(upper, MAX(x, lower))) +#define DTOR (PI / 180.0f) +#define SWAP(x, y, T) do { T SWAP = x; x = y; y = SWAP; } while (0) + +namespace MathHelper { + inline float radiansToDegrees(float radians) { + return radians * 180.f / PI; + } + + inline float degreesToRadians(float degrees) { + return degrees * PI / 180.f; + } + + inline int nearestPowerOfTwo(int n) { + int v = n; + + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; // next power of 2 + + return v; + } +} diff --git a/tools/transpiler/MyString.cpp b/tools/transpiler/MyString.cpp new file mode 100644 index 0000000..1a63960 --- /dev/null +++ b/tools/transpiler/MyString.cpp @@ -0,0 +1,392 @@ +#include "MyString.h" +#include "MathHelper.h" +#include <cstdlib> +#include <cstdio> +#include <iostream> +#include <cstdarg> +#include <cmath> + +int StringBuffer::add(const char* str) { + int spaceNeeded = strlen(str); + int spaceAvailable = BUFFER_SIZE - pointer; + + int amountToCopy = 0; + if (spaceAvailable >= spaceNeeded) { + amountToCopy = spaceNeeded; + } else { + amountToCopy = spaceAvailable; + } + + memcpy(&buffer[pointer], str, sizeof(char) * amountToCopy); + pointer += amountToCopy; + buffer[pointer] = '\0'; + return amountToCopy; +} + +void StringBuffer::reset() { + buffer[0] = '\0'; + pointer = 0; +} + +bool StringBuffer::isFull() { + return pointer == BUFFER_SIZE; +} + +StringBuffer* StringBuilder::getCurrentBuffer() { + if (bufferPointer == 0) { + if (!defaultBuffer.isFull()) { + return &defaultBuffer; + } + + StringBuffer newBuffer; + dynamicBuffer.allocate(2); + bufferPointer++; + dynamicBuffer.add(&newBuffer); + } + + if (dynamicBuffer[bufferPointer - 1].isFull()) { + StringBuffer newBuffer; + dynamicBuffer.add(&newBuffer); + bufferPointer++; + } + + return &dynamicBuffer[bufferPointer - 1]; +} + +StringBuffer* StringBuilder::getBufferAtIdx(int index) { + if (index == 0) { + return &defaultBuffer; + } + + index = index - 1; + if (index < static_cast<int>(dynamicBuffer.numElements)) { + return &dynamicBuffer[index]; + } + + return nullptr; +} + +const StringBuffer* StringBuilder::getBufferAtIdxConst(int index) const { + if (index == 0) { + return &defaultBuffer; + } + + index = index - 1; + if (index < static_cast<int>(dynamicBuffer.numElements)) { + return &dynamicBuffer[index]; + } + + return nullptr; +} + +String StringBuilder::toString() { + int strSize = (bufferPointer + 1) * StringBuffer::BUFFER_SIZE; + String retval; + + if (strSize > String::SSO_SIZE) { + retval.dynamicBuffer = new char[strSize + 1]; + memcpy(retval.dynamicBuffer, defaultBuffer.buffer, sizeof(char) * StringBuffer::BUFFER_SIZE); + FOREACH(dynamicBuffer) { + memcpy(&retval.dynamicBuffer[(idx + 1) * StringBuffer::BUFFER_SIZE], value->buffer, sizeof(char) * StringBuffer::BUFFER_SIZE); + } + retval.isSSO = false; + } else { + memcpy(retval.defaultBuffer, defaultBuffer.buffer, sizeof(char) * strSize); + retval.isSSO = true; + } + + retval.capacity = strSize; + retval.length = length; + retval.getValue()[retval.length] = '\0'; + return retval; +} + +void StringBuilder::addStr(String* str) { + addStr(str->getValue()); +} + +void StringBuilder::addStr(const char* str, int inLength) { + int amountLeft = inLength < 0 ? strlen(str) : inLength; + length += amountLeft; + int ptr = 0; + + do { + StringBuffer* currentBuffer = getCurrentBuffer(); + int amtAdded = currentBuffer->add(&str[ptr]); + amountLeft = amountLeft - amtAdded; + ptr += amtAdded; + } while (amountLeft > 0); +} + +void StringBuilder::addChar(char c) { + char wrapper[2] = { c, '\0' }; + addStr(wrapper); +} + +const int DEFAULT_NUMBER_BUFFER_SIZE = 32; + +void StringBuilder::addInt(int value) { + char buffer[DEFAULT_NUMBER_BUFFER_SIZE]; + sprintf(buffer, "%d", value); + addStr(buffer); +} + +// Pulled from here: https://stackoverflow.com/questions/7228438/convert-double-float-to-string +inline int n_tu(int number, int count) { + int result = 1; + while(count-- > 0) + result *= number; + + return result; +} + +void StringBuilder::addFloat(float value) { + char buffer[DEFAULT_NUMBER_BUFFER_SIZE]; + sprintf(buffer, "%f", value); + addStr(buffer); +} + +void StringBuilder::replace(const char* strToReplace, const char* replaceStr) { + +} + +int StringBuilder::indexOf(const char* str) { + return -1; +} + +void StringBuilder::removeAt(int index, int count) { + if (index >= length) { + printf("Index is larger than the length"); + return; + } + + if (count <= 0) { + printf("Count was <= zero"); + return; + } + + int newLength = length - count; + if (newLength == 0) { + clear(); + return; + } + + // Easiest way to do this is to move the entire string to the left, starting at index by count + int currentIndex = index; + int copyIndex = index + count; + + while (currentIndex < newLength) { + int bufferPos = floor(static_cast<float>(currentIndex) / static_cast<float>(StringBuffer::BUFFER_SIZE)); + int pointerIdx = currentIndex % StringBuffer::BUFFER_SIZE; + StringBuffer* buffer = getBufferAtIdx(bufferPos); + + char newChar = '\0'; + int copyBufferPos = floor(static_cast<float>(copyIndex) / static_cast<float>(StringBuffer::BUFFER_SIZE)); + StringBuffer* copyBuffer = getBufferAtIdx(copyBufferPos); + if (copyBuffer != nullptr) { + int bufferPointerIdx = copyIndex % StringBuffer::BUFFER_SIZE; + if (bufferPointerIdx < copyBuffer->pointer) { + newChar = copyBuffer->buffer[bufferPointerIdx]; + } + } + + buffer->buffer[pointerIdx] = newChar; + + currentIndex++; + copyIndex++; + } + + // Brute force update the buffer that we're currently using + length = newLength; + int newNumBuffers = ceil(static_cast<float>(length) / static_cast<float>(StringBuffer::BUFFER_SIZE)); // This is how many buffers we should have + if (newNumBuffers <= 1) { + dynamicBuffer.numElements = 0; + bufferPointer = 0; + } else { + dynamicBuffer.numElements = newNumBuffers - 1; + bufferPointer = newNumBuffers - 1; + } + + StringBuffer* lastBuffer = getBufferAtIdx(bufferPointer); + if (lastBuffer->pointer != StringBuffer::BUFFER_SIZE) { + lastBuffer->pointer = length % StringBuffer::BUFFER_SIZE; + } + lastBuffer->buffer[lastBuffer->pointer] = '\0'; +} + +void StringBuilder::format(const char* str, ...) { + va_list args; + va_start(args, str); + + while (*str != '\0') { + if (*str == '%') { + str++; + switch (*str) { + case 'd': + addInt(va_arg(args, int)); + break; + case 'f': + addFloat(static_cast<float>(va_arg(args, double))); + break; + case 's': + addStr(va_arg(args, char*), -1); + default: + break; + } + } else { + addChar(*str); + } + + str++; + } + + va_end(args); +} + +void StringBuilder::clear() { + bufferPointer = 0; + length = 0; + defaultBuffer.reset(); + + if (!dynamicBuffer.isEmpty()) { + FOREACH(dynamicBuffer) { + value->reset(); + } + } + + dynamicBuffer.clear(); +} + +void StringBuilder::free() { + dynamicBuffer.deallocate(); +} + +char StringBuilder::getCharAtIdx(int index) const { + int bufferPos = floor(static_cast<float>(index) / static_cast<float>(StringBuffer::BUFFER_SIZE)); + int pointerIdx = index % StringBuffer::BUFFER_SIZE; + const StringBuffer* buffer = getBufferAtIdxConst(bufferPos); + if (buffer != nullptr && pointerIdx < buffer->pointer) { + return buffer->buffer[pointerIdx]; + } + + return '\0'; +} + +void StringBuilder::insert(char c, int index) { + if (index >= length) { + addChar(c); + return; + } + + // Move all of the characters forward by one + char currentChar = c; + for (int cIdx = index; cIdx < length + 1; cIdx++) { + int bufferPos = floor(static_cast<float>(cIdx) / static_cast<float>(StringBuffer::BUFFER_SIZE)); + int pointerIdx = cIdx % StringBuffer::BUFFER_SIZE; + StringBuffer* buffer = getBufferAtIdx(bufferPos); + if (buffer == nullptr) { + buffer = getCurrentBuffer(); // Get a new buffer if this one is filled up + } + + char nextCurrent = buffer->buffer[pointerIdx]; + buffer->buffer[pointerIdx] = currentChar; + currentChar = nextCurrent; + } + + // Move the final buffer forward + StringBuffer* finalBuffer = getCurrentBuffer(); + finalBuffer->pointer++; + finalBuffer->buffer[finalBuffer->pointer] = '\0'; + length = length + 1; +} + +String::String() { +} + +String::String(const char* str) { + set(str); +} + +void String::operator =(const char* str) { + set(str); +} + +char* String::getValue() { + return isSSO ? defaultBuffer : dynamicBuffer; +} + +const char* String::getValueConst() const { + return isSSO ? defaultBuffer : dynamicBuffer; +} + +void String::set(const char* str) { + int inLen = strlen(str); + + if (inLen <= SSO_SIZE) { + isSSO = true; + memcpy(defaultBuffer, str, inLen); + defaultBuffer[inLen] = '\0'; + } else { + if (capacity >= inLen) { + memcpy(dynamicBuffer, str, inLen); + } else { + free(); + capacity = MathHelper::nearestPowerOfTwo(inLen + 1); + dynamicBuffer = new char[capacity]; + memcpy(dynamicBuffer, str, inLen); + } + isSSO = false; + dynamicBuffer[inLen] = '\0'; + } + + length = inLen; +} + +void String::free() { + capacity = 0; + length = 0; + isSSO = true; + if (dynamicBuffer != nullptr) { + delete dynamicBuffer; + } + + defaultBuffer[0] = '\0'; +} + +int String::toInteger() { + return atoi(getValue()); +} + +float String::toFloat() { + return static_cast<float>(atof(getValue())); +} + +int String::indexOf(char c) { + char* buffer = getValue(); + int idx = 0; + while (buffer[idx] != '\0') { + if (buffer[idx] == c) { + return idx; + } + idx++; + } + + return -1; +} + +StringView String::substring(int start, int end) { + StringView retval; + if (start >= length) { + retval.error = true; + return retval; + } + + if (end >= length) { + end = length - 1; + } + + char* value = getValue(); + retval.value = &value[start]; + retval.length = end - start; + return retval; +} diff --git a/tools/transpiler/MyString.h b/tools/transpiler/MyString.h new file mode 100644 index 0000000..805f5de --- /dev/null +++ b/tools/transpiler/MyString.h @@ -0,0 +1,76 @@ +#pragma once +#include "List.h" + +struct StringView { + bool error = false; + char* value = nullptr; + size_t length = 0; +}; + +struct String { + const static int SSO_SIZE = 31; + + char defaultBuffer[String::SSO_SIZE + 1] = { '\0' }; + char* dynamicBuffer = nullptr; + + int length = 0; + int capacity = 0; + bool isSSO = true; + + String(); + String(const char* str); + char* getValue(); + const char* getValueConst() const; + void operator =(const char* str); + void set(const char* str); + void free(); + int toInteger(); + float toFloat(); + int indexOf(char c); + inline bool equals(const String& other) { return strcmp(getValueConst(), other.getValueConst()) == 0; }; + inline bool equalsCstr(const char* str) { return strcmp(getValueConst(), str) == 0; }; + StringView substring(int start, int end); +}; + +struct StringBuffer { + const static int BUFFER_SIZE = 31; + + int pointer = 0; + char buffer[StringBuffer::BUFFER_SIZE + 1]; // Leave space for trailing escape character + + /* + * Appends the string to the buffer + * @param str + * @returns number of characters copied + */ + int add(const char* str); + bool isFull(); + void reset(); +}; + +struct StringBuilder { + int bufferPointer = 0; + int length = 0; + + StringBuffer defaultBuffer; + List<StringBuffer> dynamicBuffer; + + StringBuffer* getCurrentBuffer(); + StringBuffer* getBufferAtIdx(int index); + const StringBuffer* getBufferAtIdxConst(int index) const; + void addStr(String* str); + void addStr(const char* str, int length = -1); + void addChar(char c); + void format(const char* str, ...); + void addInt(int value); + void addFloat(float value); + void replace(const char* strToReplace, const char* replaceStr); + void removeAt(int index, int count); + int indexOf(char c); + int indexOf(const char* str); + String toString(); + void clear(); + char getCharAtIdx(int index) const; + void insert(char c, int index); + void free(); +}; diff --git a/tools/transpiler/build.sh b/tools/transpiler/build.sh new file mode 100755 index 0000000..ea1cb93 --- /dev/null +++ b/tools/transpiler/build.sh @@ -0,0 +1 @@ +g++ -o transpiler transpiler.cpp Logger.cpp MyString.cpp replacer.cpp diff --git a/tools/transpiler/pages.txt b/tools/transpiler/pages.txt new file mode 100644 index 0000000..cea23dd --- /dev/null +++ b/tools/transpiler/pages.txt @@ -0,0 +1,16 @@ +🏀 "2D" +>"Rigidbody" +>>/2d/rigidbody/rigidbody_1.html "Linear Forces" +>>/2d/rigidbody/rigidbody_2.html "Rotational Forces" +>>/2d/rigidbody/rigidbody_3.html "Collisions" +>"Collisions" +>>/2d/_collisions/rectangle_line.html "Rectangle-Line" +>>/2d/_collisions/rectangle_rectangle.html "Rectangle-Rectangle" +>>/2d/_collisions/polygon_polygon.html "Separating Axis Theorem" +🌠 "3D" +>"Rigidbody" +>>/3d/rigidbody.html "Rigidbody in 3D" +🔧 "WebAssembly" +>>/intro/intro.html "Introduction" +🛈 "About" +>>/roadmap.html "Roadmap" diff --git a/tools/transpiler/replacer.cpp b/tools/transpiler/replacer.cpp new file mode 100644 index 0000000..3f48089 --- /dev/null +++ b/tools/transpiler/replacer.cpp @@ -0,0 +1,128 @@ +#include "replacer.h" +#include "Logger.h" +#include <ctype.h> + +const char* keywords[] = { + "cosnt", "struct", "static", "return" +}; + +const char* types[] = { + "void", + "int", "int8", "int16", "int32", "int64", + "float", "float8", "float16", "float32", "float64", + "long", + "double", + "bool", + "Vector2", "Vector3", "Vector4", + "struct", "class", "static", "return", "const" +}; + +const char* commentType = "//"; + +bool isType(char* str, int size) { + if (size == 0) { + return false; + } + + for (int i = 0; i < sizeof(types) / sizeof(char*); i++) { + if (size == strlen(types[i]) && strncmp(str, types[i], size) == 0) { + return true; + } + } + + return false; +} + +bool isTokenDelim(char c) { + return isspace(c) || c == '\0' || c == ';' || c == ','; +} + +// @TODO: This has brought me to two realizations: +// 1) C++ string manipulaton is difficult for no apparent reason +// 2) My current implementation of String is lacking so many features that I would want +// 3) I have no plans to update my current implementation any time soon, so I will +// begrudginly give my heart and soul over to the standard library. +std::string insertCodeSnippets(char* workingDirectory, char* bodyContent) { + std::string strWorkingDirectory (workingDirectory); + strWorkingDirectory = strWorkingDirectory.substr(0, strWorkingDirectory.find_last_of("/") + 1); + std::string strContent(bodyContent); + + size_t found = -1; + do { + found = strContent.find("#SNIPPET", found + 1); + if (found == std::string::npos) { + break; + } + int startFound = found; + found += strlen("#SNIPPET "); + + std::string fileName(strWorkingDirectory); + while (!isspace(strContent[found])) { + fileName += strContent[found]; + found++; + } + + size_t endFound = found + 1; + + FILE* snippetFile = fopen(fileName.c_str(), "r+"); + if (snippetFile == NULL) { + logger_warning("Could not find snippet: %s", fileName.c_str()); + continue; + } + + fseek(snippetFile, 0, SEEK_END); + long fsize = ftell(snippetFile); + fseek(snippetFile, 0, SEEK_SET); + + char* snippetContent = new char[fsize + 1]; + fread(snippetContent, 1, fsize, snippetFile); + snippetContent[fsize] = '\0'; + + std::string s; + int tokenStart = 0, tokenEnd = 0; + while (snippetContent[tokenEnd] != '\0') { + while (!isTokenDelim(snippetContent[tokenEnd])) { + tokenEnd++; + } + + int tokenLength = (tokenEnd - tokenStart); + + if (tokenLength == strlen(commentType) && strncmp(&snippetContent[tokenStart], commentType, tokenLength) == 0) { + // @NOTE: Assuming comments are always on a single line + s.append("<span class=\"code_comment\">"); + while (snippetContent[tokenEnd] != '\n') { + tokenEnd++; + } + s.append(&snippetContent[tokenStart], tokenEnd - tokenStart); + s.append("</span>"); + } else if (isType(&snippetContent[tokenStart], tokenLength)) { + s.append("<span class=\"code_keyword\">"); + s.append(&snippetContent[tokenStart], tokenLength); + s.append("</span>"); + } else { + s.append(&snippetContent[tokenStart], tokenLength); + } + + s += snippetContent[tokenEnd]; + + tokenStart = tokenEnd + 1; + tokenEnd = tokenStart; + } + + while (s[0] == '\n') { + s.erase(0, 1); + } + + s.insert(0, "<code>"); + s.insert(0, "<pre>"); + s.append("</code>"); + s.append("</pre>"); + + delete [] snippetContent; + + strContent.replace(startFound, endFound - startFound, s); + + } while (true); + + return strContent; +} diff --git a/tools/transpiler/replacer.h b/tools/transpiler/replacer.h new file mode 100644 index 0000000..f795bca --- /dev/null +++ b/tools/transpiler/replacer.h @@ -0,0 +1,3 @@ +#include <string> + +std::string insertCodeSnippets(char* workingDirectory, char* bodyContent); diff --git a/tools/transpiler/transpiler b/tools/transpiler/transpiler Binary files differnew file mode 100755 index 0000000..dda66e9 --- /dev/null +++ b/tools/transpiler/transpiler diff --git a/tools/transpiler/transpiler.cpp b/tools/transpiler/transpiler.cpp new file mode 100644 index 0000000..c27ce51 --- /dev/null +++ b/tools/transpiler/transpiler.cpp @@ -0,0 +1,255 @@ +#include "MyString.h" +#include "List.h" +#include "Logger.h" +#include "replacer.h" +#include <cstdio> +#include <vector> +#include <cstring> + +struct InnerCategory { + bool isLabel = false; + String label; + String path; + + void toCode(StringBuilder& sb) { + if (isLabel) { + sb.format("\t\t\t\t\t<li><label>%s</label></li>\n", label.getValue()); + } else { + sb.format("\t\t\t\t\t<li><a title=\"%s\" href=\"%s\">%s</a></li>\n", path.getValue(), path.getValue(), label.getValue()); + } + } + + void free() { + label.free(); + path.free(); + } +}; + +struct OuterCategory { + String outerName; + String outerSymbol; + List<InnerCategory> items; + + void toCode(StringBuilder& sb) { + sb.addStr("\t\t\t<li>\n"); + sb.format("\t\t\t\t<span>%s<span>%s</span></span>\n", outerSymbol.getValue(), outerName.getValue()); + sb.addStr("\t\t\t\t<ul class=\"inner-tree\">\n"); + + FOREACH(items) { + value->toCode(sb); + } + + sb.addStr("\t\t\t\t</ul>\n"); + sb.addStr("\t\t\t</li>\n"); + } + + void reset() { + outerName.free(); + outerSymbol.free(); + items.clear(); + } + + void free() { + outerName.free(); + outerSymbol.free(); + + FOREACH(items) { + value->free(); + } + items.deallocate(); + } +}; + +int main() { + logger_info("Running transpiler"); + FILE* pagesFile = fopen("tools/transpiler/pages.txt", "r+"); + + char * cLine = NULL; + size_t len = 0; + ssize_t read; + + StringBuilder sb; + StringBuilder otherSb; + + sb.addStr("\t\t<nav>\n\t\t<ul class=\"outer-tree\">\n"); + sb.addStr("\t\t\t<li><a href=\"/\">Introduction</a></li>\n"); + + bool isFirst = true; + OuterCategory oc; + List<String> servedFiles; + + servedFiles.add("./index.html"); + while ((read = getline(&cLine, &len, pagesFile)) != -1) { + char* line = cLine; + + int indent = 0; + while (line[0] == '>') { + line++; + indent++; + } + + switch (indent) { + case 0: { + if (!isFirst) { + oc.toCode(sb); + } + oc.reset(); + + isFirst = false; + // Outer tree item + while (line[0] != ' ') { + otherSb.addChar(line[0]); + line++; + } + line++; + + oc.outerSymbol = otherSb.toString(); + otherSb.clear(); + + while (line[0] != '\n') { + if (line[0] != '\"') { + otherSb.addChar(line[0]); + } + line++; + } + + oc.outerName = otherSb.toString(); + logger_info(oc.outerName.getValue()); + otherSb.clear(); + + break; + } + case 1: { + InnerCategory ic; + ic.isLabel = true; + while (line[0] != '\n') { + if (line[0] != '\"') { + otherSb.addChar(line[0]); + } + line++; + } + ic.label = otherSb.toString(); + otherSb.clear(); + oc.items.add(ic); + + break; + } + case 2: { + InnerCategory ic; + ic.isLabel = false; + + while (line[0] != ' ') { + otherSb.addChar(line[0]); + line++; + } + line++; + + ic.path = otherSb.toString(); + otherSb.insert('.', 0); + String pathCopy = otherSb.toString(); + servedFiles.add(pathCopy); + otherSb.clear(); + + while (line[0] != '\n') { + if (line[0] != '\"') { + otherSb.addChar(line[0]); + } + line++; + } + + ic.label = otherSb.toString(); + otherSb.clear(); + oc.items.add(ic); + + break; + } + } + } + + oc.toCode(sb); + sb.addStr("\t\t</ul>\n\t\t</nav>\n"); + oc.reset(); + fclose(pagesFile); + + String navbarRetval = sb.toString(); + sb.clear(); + + logger_info("Creating served files"); + + // Create the header + FOREACH(servedFiles) { + otherSb.clear(); + otherSb.format("%s.content", value->getValue()); + String contentFileName = otherSb.toString(); + FILE* contentFile = fopen(contentFileName.getValue(), "r+"); + if (contentFile == NULL) { + logger_warning("Could not output file, most likely unimplemented: %s", contentFileName.getValue()); + continue; + } + + logger_info("Outputting file: %s", contentFileName.getValue()); + + // Header + sb.addStr("<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + "\t<head>\n" + "\t\t<meta charset=\"utf-8\">\n" + "\t\t<link rel=\"stylesheet\" href=\"/index.css\">\n" + "\t\t<title>Physics for Games</title>\n" + "\t\t<link rel=\"shortcut icon\" href=\"/favicon/favicon.ico\" type=\"image/x-icon\">\n" + "\t\t<meta name=\"description\" content=\"A place to learn all about real-time physics simulations through descriptions, code snippets, and example programs all written in C++ and OpenGL.\">\n" + "\t\t<meta name=\"og:description\" content=\"A place to learn all about real-time physics simulations through descriptions, code snippets, and example programs all written in C++ and OpenGL.\">\n" + "\t</head>\n" + "\t<body>\n" + "\t\t<header>\n" + "\t\t\t<h1><a title=\"physicsforgames.com\" href=\"/\">Physics for Games</a></h1>\n" + "\t\t</header>\n" + "\t\t<main>\n"); + + // Write navigation bar + sb.addStr(navbarRetval.getValue()); + // Read body + + fseek(contentFile, 0, SEEK_END); + long fsize = ftell(contentFile); + fseek(contentFile, 0, SEEK_SET); + + char* bodyContent = new char[fsize + 1]; + fread(bodyContent, 1, fsize, contentFile); + bodyContent[fsize] = '\0'; + + auto processedBody = insertCodeSnippets(contentFileName.getValue(), bodyContent); + + sb.addStr(processedBody.c_str()); + delete [] bodyContent; + + + contentFileName.free(); + fclose(contentFile); + + // Footer + sb.addStr("\t\t</main>\n" + "\t</body>\n" + "</html>\n"); + + FILE* outFile = fopen(value->getValue(), "w+"); + String outStr = sb.toString(); + fwrite(outStr.getValue(), 1, outStr.length, outFile); + outStr.free(); + fclose(outFile); + sb.clear(); + } + + logger_info("Outputting files to their proper directories..."); + sb.free(); + navbarRetval.free(); + otherSb.free(); + + FOREACH(servedFiles) { + value->free(); + } + + servedFiles.deallocate(); + + return 0; +} |