diff options
Diffstat (limited to 'frontend/transpiler')
-rw-r--r-- | frontend/transpiler/List.h | 222 | ||||
-rw-r--r-- | frontend/transpiler/Logger.cpp | 123 | ||||
-rw-r--r-- | frontend/transpiler/Logger.h | 43 | ||||
-rw-r--r-- | frontend/transpiler/MathHelper.h | 33 | ||||
-rw-r--r-- | frontend/transpiler/MyString.cpp | 392 | ||||
-rw-r--r-- | frontend/transpiler/MyString.h | 76 | ||||
-rwxr-xr-x | frontend/transpiler/build.sh | 1 | ||||
-rw-r--r-- | frontend/transpiler/pages.txt | 14 | ||||
-rwxr-xr-x | frontend/transpiler/transpiler | bin | 0 -> 38744 bytes | |||
-rw-r--r-- | frontend/transpiler/transpiler.cpp | 249 |
10 files changed, 1153 insertions, 0 deletions
diff --git a/frontend/transpiler/List.h b/frontend/transpiler/List.h new file mode 100644 index 0000000..00a466a --- /dev/null +++ b/frontend/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/frontend/transpiler/Logger.cpp b/frontend/transpiler/Logger.cpp new file mode 100644 index 0000000..1068d88 --- /dev/null +++ b/frontend/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/frontend/transpiler/Logger.h b/frontend/transpiler/Logger.h new file mode 100644 index 0000000..7596b6f --- /dev/null +++ b/frontend/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/frontend/transpiler/MathHelper.h b/frontend/transpiler/MathHelper.h new file mode 100644 index 0000000..b9c9cb6 --- /dev/null +++ b/frontend/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/frontend/transpiler/MyString.cpp b/frontend/transpiler/MyString.cpp new file mode 100644 index 0000000..1cb3d43 --- /dev/null +++ b/frontend/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 amountLeft = strlen(str); + 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*)); + 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/frontend/transpiler/MyString.h b/frontend/transpiler/MyString.h new file mode 100644 index 0000000..d05d84a --- /dev/null +++ b/frontend/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); + 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(); +};
\ No newline at end of file diff --git a/frontend/transpiler/build.sh b/frontend/transpiler/build.sh new file mode 100755 index 0000000..6ca478e --- /dev/null +++ b/frontend/transpiler/build.sh @@ -0,0 +1 @@ +g++ -o transpiler transpiler.cpp Logger.cpp MyString.cpp
\ No newline at end of file diff --git a/frontend/transpiler/pages.txt b/frontend/transpiler/pages.txt new file mode 100644 index 0000000..caa420c --- /dev/null +++ b/frontend/transpiler/pages.txt @@ -0,0 +1,14 @@ +🏀 "2D" +>"Rigidbody" +>>/2d/_rigidbody/part_1.html "Linear Forces" +>>/2d/_rigidbody/part_2.html "Rotational Forces" +>>/2d/_rigidbody/part_3.html "Collision Forces" +>"Collisions" +>>/2d/_collisions/circle_line.html "Circle-Line" +>>/2d/_collisions/rectangle_line.html "Rectangle-Line" +>>/2d/_collisions/pill_line.html "Pill-Line" +🌠 "3D" +🔧 "WebAssembly" +>>/intro/intro.html "Introduction" +🛈 "About" +>>/roadmap.html "Roadmap" diff --git a/frontend/transpiler/transpiler b/frontend/transpiler/transpiler Binary files differnew file mode 100755 index 0000000..2f2d00b --- /dev/null +++ b/frontend/transpiler/transpiler diff --git a/frontend/transpiler/transpiler.cpp b/frontend/transpiler/transpiler.cpp new file mode 100644 index 0000000..4771314 --- /dev/null +++ b/frontend/transpiler/transpiler.cpp @@ -0,0 +1,249 @@ +#include "MyString.h" +#include "List.h" +#include "Logger.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 href=\"%s\">%s</a></li>\n", 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("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</head>\n" + "\t<body>\n" + "\t\t<header>\n" + "\t\t\t<h1>Physics for Games</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); + sb.addStr(bodyContent); + 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; +}
\ No newline at end of file |