more codegen

This commit is contained in:
Asuro
2025-03-10 02:47:43 +01:00
parent b307165a6f
commit 29bb1d0208
11 changed files with 409 additions and 121 deletions

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
project(MiniDefProj) project(MiniDefProj)
add_executable(minidef "${CMAKE_CURRENT_SOURCE_DIR}/src/MiniDef.cpp") add_executable(minidef "${CMAKE_CURRENT_SOURCE_DIR}/src/MiniDef.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/Logging.cpp")
target_include_directories(minidef PRIVATE target_include_directories(minidef PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/../bgfx.cmake/bx/include/" "${CMAKE_CURRENT_SOURCE_DIR}/../bgfx.cmake/bx/include/"
"${CMAKE_CURRENT_SOURCE_DIR}/../bgfx.cmake/bx/include/compat/msvc/" "${CMAKE_CURRENT_SOURCE_DIR}/../bgfx.cmake/bx/include/compat/msvc/"

View File

@@ -0,0 +1,18 @@
#pragma once
#include <cstdint>
#define LOG(line, fmt, ...) Logging::Log(Logging::ELogType::Log, line, fmt, ##__VA_ARGS__)
#define LOG_WARN(line, fmt, ...) Logging::Log(Logging::ELogType::Warn, line, fmt, ##__VA_ARGS__)
#define LOG_ERROR(line, fmt, ...) Logging::Log(Logging::ELogType::Error, line, fmt, ##__VA_ARGS__)
struct Logging
{
enum class ELogType
{
Log,
Warn,
Error,
};
static void Log(ELogType logType, uint32_t line, const char* format, ...);
};

View File

@@ -1,11 +1,17 @@
type Test
{
u32 Number
}
type Texture type Texture
{ {
u32 Width u32 Width
u32 Height u32 Height
str Test Arr(3) str StrTest Arr(3)
Test T
} }
enum KnownType enum KnownType(u8)
{ {
i8 CName("int8_t") i8 CName("int8_t")
i16 CName("int16_t") i16 CName("int16_t")
@@ -15,6 +21,7 @@ enum KnownType
u16 CName("uint16_t") u16 CName("uint16_t")
u32 CName("uint32_t") u32 CName("uint32_t")
u64 CName("uint64_t") u64 CName("uint64_t")
b CName("bool")
f32 CName("float") f32 CName("float")
f64 CName("double") f64 CName("double")
str CName("char") str CName("char")

View File

@@ -3,16 +3,21 @@
namespace Generated namespace Generated
{ {
struct Test
{
uint32_t Number = {};
};
struct Texture struct Texture
{ {
uint32_t Width = {}; uint32_t Width = {};
uint32_t Height = {}; uint32_t Height = {};
char Test[3] = {}; char StrTest[3] = {};
Test T = {};
}; };
struct KnownType struct KnownType
{ {
static constexpr int32_t EntryCount = 11; static constexpr int32_t EntryCount = 12;
enum class Enum enum class Enum : int32_t
{ {
i8, i8,
i16, i16,
@@ -22,6 +27,7 @@ namespace Generated
u16, u16,
u32, u32,
u64, u64,
b,
f32, f32,
f64, f64,
str, str,
@@ -36,6 +42,7 @@ namespace Generated
"u16", "u16",
"u32", "u32",
"u64", "u64",
"b",
"f32", "f32",
"f64", "f64",
"str", "str",
@@ -50,6 +57,7 @@ namespace Generated
"uint16_t", "uint16_t",
"uint32_t", "uint32_t",
"uint64_t", "uint64_t",
"bool",
"float", "float",
"double", "double",
"char", "char",

View File

@@ -0,0 +1,34 @@
#include "Logging.h"
#include "bx/string.h"
#define WIN32_LEAN_AND_MEAN
#include "Windows.h"
#define ESC "\x1B["
#define YELLOW ESC "33m"
#define RED ESC "31m"
#define END ESC "39m"
namespace
{
char LineBuffer[1024]{0};
char OutBuffer[1024]{0};
constexpr char LogFormat[]{"Line %u: %s\n"};
constexpr char WarnFormat[]{YELLOW "Line %u: %s" END "\n"};
constexpr char ErrorFormat[]{RED "Line %u: %s" END "\n"};
} // namespace
void Logging::Log(ELogType logType, uint32_t line, const char* format, ...)
{
const char* LineFormat = LogFormat;
if (logType == ELogType::Warn) LineFormat = WarnFormat;
if (logType == ELogType::Error) LineFormat = ErrorFormat;
va_list args;
va_start(args, format);
bx::snprintf(LineBuffer, sizeof(LineBuffer), LineFormat, line, format);
bx::vprintf(LineBuffer, args);
bx::vsnprintf(OutBuffer, sizeof(OutBuffer), LineBuffer, args);
va_end(args);
OutputDebugStringA(OutBuffer);
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include <cstdint>
#define LOG(line, fmt, ...) Logging::Log(Logging::ELogType::Log, line, fmt, ##__VA_ARGS__)
#define LOG_WARN(line, fmt, ...) Logging::Log(Logging::ELogType::Warn, line, fmt, ##__VA_ARGS__)
#define LOG_ERROR(line, fmt, ...) Logging::Log(Logging::ELogType::Error, line, fmt, ##__VA_ARGS__)
struct Logging
{
enum class ELogType
{
Log,
Warn,
Error,
};
static bool Assert(bool Condition, const char* Text);
static void Log(ELogType logType, uint32_t line, const char* format, ...);
};

View File

@@ -1,4 +1,7 @@
#include "Gen/Generated.h"
#include "Logging.h"
#include "MiniDef.h" #include "MiniDef.h"
#include "bx/string.h" #include "bx/string.h"
#include <bx/filepath.h> #include <bx/filepath.h>
#include <ctype.h> #include <ctype.h>
@@ -27,11 +30,11 @@ namespace Generated
R"END( }; R"END( };
)END"; )END";
constexpr char EnumHeader2[] = constexpr char EnumHeader3[] =
R"END( struct %s R"END( struct %s
{ {
static constexpr int32_t EntryCount = %u; static constexpr int32_t EntryCount = %u;
enum class Enum enum class Enum : %s
{ {
)END"; )END";
@@ -59,51 +62,37 @@ namespace Generated
)END"; )END";
} // namespace WriteTemplates } // namespace WriteTemplates
void DefinitionFile::PrintTypeName(char* buf, int32_t bufSize, Def::TypeUnion type) void DefinitionFile::PrintTypeName(char* buf, int32_t bufSize, const Def::FieldType& type)
{ {
if (int32_t(type.Known) < Generated::KnownType::EntryCount) if (type.FieldKind == Def::EFieldType::Native)
{ {
bx::strCopy(buf, bufSize, Generated::KnownType::CName[size_t(type.Known)]); if (int32_t(type.Native) < Generated::KnownType::EntryCount)
{
bx::strCopy(buf, bufSize, Generated::KnownType::CName[size_t(type.Native)]);
}
else
{
LOG_ERROR(0, "Unknown native type index: %u", type.Native);
}
}
else if (type.FieldKind == Def::EFieldType::DefinedClass)
{
bx::strCopy(buf, bufSize, Types[type.TypeIdx].Name);
}
else if (type.FieldKind == Def::EFieldType::DefinedEnum)
{
bx::strCopy(buf, bufSize, Enums[type.TypeIdx].Name);
} }
} }
void DefinitionFile::GenerateCpp(const bx::FilePath& outDir) void DefinitionFile::WriteEnums(TemplateWriter& Template)
{ {
bx::Error error;
bx::FileWriter writer;
bx::FilePath writePath = outDir;
std::filesystem::create_directory(outDir.getCPtr());
writePath.join("Generated.h");
writer.open(writePath, false, &error);
TemplateWriter Template{writer, error};
Template.Write(WriteTemplates::FileHeader);
for (int32_t typeIdx = 0; typeIdx < TypeCount; ++typeIdx)
{
Def::Type& t = Types[typeIdx];
Template.Write(WriteTemplates::StructHeader1, t.Name);
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
{
char Type[64]{0};
PrintTypeName(Type, sizeof(Type), t.FieldTypes[fieldIdx]);
char Array[32]{0};
uint32_t ArraySize = t.FieldArraySizes[fieldIdx];
if (ArraySize > 0)
{
bx::snprintf(Array, sizeof(Array), "[%u]", ArraySize);
}
Template.Write(WriteTemplates::StructField4, Type, t.FieldNames[fieldIdx], Array, "{}");
}
Template.Write(WriteTemplates::StructEnd);
}
for (int32_t enumIdx = 0; enumIdx < EnumCount; ++enumIdx) for (int32_t enumIdx = 0; enumIdx < EnumCount; ++enumIdx)
{ {
Def::Enum& e = Enums[enumIdx]; Def::Enum& e = Enums[enumIdx];
Template.Write(WriteTemplates::EnumHeader2, e.Name, e.EntryCount); Template.Write(
WriteTemplates::EnumHeader3, e.Name, e.EntryCount, Generated::KnownType::CName[(int32_t)e.EnumType.Native]);
for (int32_t entryIdx = 0; entryIdx < e.EntryCount; ++entryIdx) for (int32_t entryIdx = 0; entryIdx < e.EntryCount; ++entryIdx)
{ {
Template.Write(WriteTemplates::EnumField1, e.EntryNames[entryIdx]); Template.Write(WriteTemplates::EnumField1, e.EntryNames[entryIdx]);
@@ -126,29 +115,85 @@ void DefinitionFile::GenerateCpp(const bx::FilePath& outDir)
Template.Write(WriteTemplates::EnumNamesEnd); Template.Write(WriteTemplates::EnumNamesEnd);
} }
}
void DefinitionFile::WriteTypes(TemplateWriter& Template)
{
for (int32_t typeIdx = 0; typeIdx < TypeCount; ++typeIdx)
{
Def::Type& t = Types[typeIdx];
Template.Write(WriteTemplates::StructHeader1, t.Name);
for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx)
{
char Type[64]{0};
PrintTypeName(Type, sizeof(Type), t.FieldTypes[fieldIdx]);
char Array[32]{0};
uint32_t ArraySize = t.FieldArraySizes[fieldIdx];
if (ArraySize > 0)
{
bx::snprintf(Array, sizeof(Array), "[%u]", ArraySize);
}
Template.Write(WriteTemplates::StructField4, Type, t.FieldNames[fieldIdx], Array, "{}");
}
Template.Write(WriteTemplates::StructEnd);
}
}
void DefinitionFile::GenerateCpp(const bx::FilePath& outDir)
{
LOG(0, "Generating...");
bx::Error error;
bx::FileWriter writer;
bx::FilePath writePath = outDir;
std::filesystem::create_directory(outDir.getCPtr());
writePath.join("Generated.h");
writer.open(writePath, false, &error);
TemplateWriter Template{writer, error};
Template.Write(WriteTemplates::FileHeader);
WriteEnums(Template);
WriteTypes(Template);
Template.Write(WriteTemplates::FileEnd); Template.Write(WriteTemplates::FileEnd);
writer.close(); writer.close();
} }
bool Parser::CmpAdvance(bx::StringView expect, Result& Res) bool Parser::CmpAdvance(bx::StringView expect, Result& Res, bool RequireGap)
{ {
uint32_t size = expect.getLength(); uint32_t size = expect.getLength();
const char* ptr = expect.getPtr();
// abort if expect longer than remaining text
if (size > GetRemaining()) if (size > GetRemaining())
{ {
std::cout << "Failed to match " << expect.getPtr() << ", " << size << "<" << GetRemaining() << std::endl;
return false; return false;
} }
// start matching
int32_t i = 0; int32_t i = 0;
for (; i < size; ++i) for (; i < size; ++i)
{ {
// if expect has 0 byte, go back one idx, we succeded
if (expect.getPtr()[i] == 0) if (expect.getPtr()[i] == 0)
{ {
i--; i--;
break; break;
} }
// check match
if (expect.getPtr()[i] != ReadPtr[i]) return false; if (expect.getPtr()[i] != ReadPtr[i]) return false;
} }
// check for following whitespace or symbols
if (RequireGap && GetRemaining() > size)
{
char next = ReadPtr[i];
if (isgraph(next) && next != '{' && next != '}' && next != '(' && next != ')')
{
return false;
}
}
Res = Advance(i); Res = Advance(i);
return true; return true;
} }
@@ -158,7 +203,8 @@ Parser::Result Parser::ExpectChar(bx::StringView expect)
Result Res = OK; Result Res = OK;
if (!CmpAdvance(expect, Res)) if (!CmpAdvance(expect, Res))
{ {
std::cout << "Expected " << expect.getPtr() << std::endl; LOG_ERROR(Line, "Expected: %s", expect.getPtr());
ErrorLine();
return Error; return Error;
} }
return Res; return Res;
@@ -170,7 +216,11 @@ Parser::Result Parser::SkipWhitespace(bool* SkippedNewLine)
for (int32_t i = 0; i < Remaining; ++i) for (int32_t i = 0; i < Remaining; ++i)
{ {
if (*ReadPtr == 0) return EndOfFile; if (*ReadPtr == 0) return EndOfFile;
if (SkippedNewLine != nullptr && (*ReadPtr == '\r' || *ReadPtr == '\n')) *SkippedNewLine = true; if (SkippedNewLine != nullptr && (*ReadPtr == '\r' || *ReadPtr == '\n'))
{
if (*ReadPtr == '\n') ++Line;
*SkippedNewLine = true;
}
if (isgraph(*ReadPtr)) return OK; if (isgraph(*ReadPtr)) return OK;
ReadPtr++; ReadPtr++;
} }
@@ -236,19 +286,19 @@ Parser::Result Parser::Parse()
Parser::Result Parser::HandleFileStart() Parser::Result Parser::HandleFileStart()
{ {
Result Res = OK; Result Res = OK;
if (CmpAdvance("type", Res) && Res == OK) if (CmpAdvance("type", Res, true) && Res == OK)
{ {
return HandleType(); return HandleType();
} }
if (Res != OK) return Res; if (Res != OK) return Res;
if (CmpAdvance("enum", Res) && Res == OK) if (CmpAdvance("enum", Res, true) && Res == OK)
{ {
return HandleEnum(); return HandleEnum();
} }
if (Res != OK) return Res; if (Res != OK) return Res;
std::cout << "Only valid here: type or enum!"; LOG(Line, "Only valid here: type or enum!");
return Error; return Error;
} }
@@ -260,7 +310,8 @@ Parser::Result Parser::HandleType()
if (Definitions.TypeCount >= DefinitionFile::MaxTypes) if (Definitions.TypeCount >= DefinitionFile::MaxTypes)
{ {
std::cout << "Too many types!" << std::endl; LOG_ERROR(Line, "Too many types!");
ErrorLine();
return Error; return Error;
} }
Def::Type& t = Definitions.Types[Definitions.TypeCount]; Def::Type& t = Definitions.Types[Definitions.TypeCount];
@@ -274,7 +325,8 @@ Parser::Result Parser::HandleType()
{ {
if (t.FieldCount >= Def::MaxFields) if (t.FieldCount >= Def::MaxFields)
{ {
std::cout << "Too many fields in type!" << std::endl; LOG_ERROR(Line, "Too many fields in type!");
ErrorLine();
return Error; return Error;
} }
CHECK(ReadTypeToken()); CHECK(ReadTypeToken());
@@ -287,7 +339,7 @@ Parser::Result Parser::HandleType()
if (!NewLine) if (!NewLine)
{ {
Result Res; Result Res;
if (CmpAdvance("Arr", Res) && Res == Result::OK) if (CmpAdvance("Arr", Res, true) && Res == Result::OK)
{ {
CHECK(ExpectChar("(")); CHECK(ExpectChar("("));
CHECK(ReadUint(t.FieldArraySizes[t.FieldCount])); CHECK(ReadUint(t.FieldArraySizes[t.FieldCount]));
@@ -310,21 +362,31 @@ Parser::Result Parser::HandleEnum()
if (Definitions.EnumCount >= DefinitionFile::MaxTypes) if (Definitions.EnumCount >= DefinitionFile::MaxTypes)
{ {
std::cout << "Too many enums!" << std::endl; LOG_ERROR(Line, "Too many enums!");
ErrorLine();
return Error; return Error;
} }
Def::Enum& e = Definitions.Enums[Definitions.EnumCount]; Def::Enum& e = Definitions.Enums[Definitions.EnumCount];
CHECK(ReadName(e.Name)); CHECK(ReadName(e.Name));
CHECK(SkipWhitespace()); CHECK(SkipWhitespace());
if (CmpAdvance("(", Res) && Res == OK)
{
CHECK(SkipWhitespace());
Def::FieldType field;
CHECK(ReadNativeFieldType(field));
CHECK(SkipWhitespace());
CHECK(ExpectChar(")"));
CHECK(SkipWhitespace());
}
CHECK(ExpectChar("{")); CHECK(ExpectChar("{"));
CHECK(SkipWhitespace()); CHECK(SkipWhitespace());
while (!CmpAdvance("}", Res)) while (!CmpAdvance("}", Res))
{ {
if (e.EntryCount >= Def::MaxFields) if (e.EntryCount >= Def::MaxFields)
{ {
std::cout << "Too many fields in enum!" << std::endl; LOG_ERROR(Line, "Too many fields in enum!");
return Error; return Error;
} }
CHECK(ReadName(e.EntryNames[e.EntryCount])); CHECK(ReadName(e.EntryNames[e.EntryCount]));
@@ -345,7 +407,8 @@ Parser::Result Parser::ReadName(char* Target)
{ {
if (i == 0) if (i == 0)
{ {
std::cout << "Empty names are not allowed!" << std::endl; LOG_ERROR(Line, "Empty names are not allowed!");
ErrorLine();
return Error; return Error;
} }
return OK; return OK;
@@ -356,7 +419,8 @@ Parser::Result Parser::ReadName(char* Target)
} }
else else
{ {
std::cout << "Name too long!" << std::endl; LOG_ERROR(Line, "Name too long!");
ErrorLine();
return Error; return Error;
} }
ReadPtr++; ReadPtr++;
@@ -381,30 +445,68 @@ Parser::Result Parser::ReadUint(uint32_t& Out)
} }
if (Written == 0) if (Written == 0)
{ {
std::cout << "No digits for uint: " << PrintLine() << std::endl; LOG_ERROR(Line, "No digits for uint!");
ErrorLine();
return Result::Error; return Result::Error;
} }
if (!bx::fromString(&Out, DigitBuf)) if (!bx::fromString(&Out, DigitBuf))
{ {
std::cout << "Failed to parse uint: " << PrintLine() << std::endl; LOG_ERROR(Line, "Failed to parse uint!");
ErrorLine();
return Result::Error; return Result::Error;
} }
return Result::OK; return Result::OK;
} }
Parser::Result Parser::ReadTypeToken() Parser::Result Parser::ReadTypeToken()
{
Result Res = OK;
Def::Type& t = Definitions.Types[Definitions.TypeCount];
if (ReadNativeFieldType(t.FieldTypes[t.FieldCount]) == OK) return OK;
if (ReadDefinedFieldType(t.FieldTypes[t.FieldCount]) == OK) return OK;
LOG_ERROR(Line, "Unknown type token!");
ErrorLine();
return Error;
}
Parser::Result Parser::ReadNativeFieldType(Def::FieldType& FieldT)
{ {
Result Res = OK; Result Res = OK;
for (int32_t i = 0; i < Generated::KnownType::EntryCount; ++i) for (int32_t i = 0; i < Generated::KnownType::EntryCount; ++i)
{ {
if (CmpAdvance(Generated::KnownType::EntryNames[i], Res) && Res == OK) if (CmpAdvance(Generated::KnownType::EntryNames[i], Res, true) && Res == OK)
{ {
Def::Type& t = Definitions.Types[Definitions.TypeCount]; FieldT.FieldKind = Def::EFieldType::Native;
t.FieldTypes[t.FieldCount].Known = Generated::KnownType::Enum(i); FieldT.Native = Generated::KnownType::Enum(i);
return OK;
}
}
return Error;
}
Parser::Result Parser::ReadDefinedFieldType(Def::FieldType& FieldT)
{
Result Res = OK;
for (uint16_t i = 0; i < Definitions.TypeCount; ++i)
{
if (CmpAdvance(Definitions.Types[i].Name, Res, true) && Res == OK)
{
Def::Type& t = Definitions.Types[Definitions.TypeCount];
FieldT.FieldKind = Def::EFieldType::DefinedClass;
FieldT.TypeIdx = i;
return OK;
}
}
for (uint16_t i = 0; i < Definitions.EnumCount; ++i)
{
if (CmpAdvance(Definitions.Enums[i].Name, Res, true) && Res == OK)
{
Def::Type& t = Definitions.Types[Definitions.TypeCount];
FieldT.FieldKind = Def::EFieldType::DefinedEnum;
FieldT.TypeIdx = i;
return OK; return OK;
} }
} }
std::cout << "Unknown type token:" << std::endl << PrintLine() << std::endl;
return Error; return Error;
} }
@@ -441,7 +543,8 @@ Parser::Result Parser::ReadOptionalEnumValues(Def::Enum& Enum, int32_t EntryIdx)
if (SkippedNewLine) return Res; if (SkippedNewLine) return Res;
} }
std::cout << "Too many extra enum fields!" << std::endl; LOG_ERROR(Line, "Too many extra enum fields!");
ErrorLine();
return Error; return Error;
} }
@@ -450,16 +553,6 @@ int32_t Parser::GetRemaining()
return &Buffer[BufferSize] - ReadPtr; return &Buffer[BufferSize] - ReadPtr;
} }
bool Log::Assert(bool Condition, const char* Text)
{
if (!Condition)
{
std::cout << "Assertion failed: " << Text << std::endl;
bx::debugBreak();
}
return !Condition;
}
char WriteBuffer[1024 * 1024]{0}; char WriteBuffer[1024 * 1024]{0};
void TemplateWriter::Write(const char* Template, ...) void TemplateWriter::Write(const char* Template, ...)
{ {
@@ -473,9 +566,11 @@ void TemplateWriter::Write(const char* Template, ...)
Parser TestParser; Parser TestParser;
int main(int argc, const char** argv) int main(int argc, const char** argv)
{ {
LOG(0, "Hello");
if (argc != 3) if (argc != 3)
{ {
std::cout << "invalid number of arguments!" << std::endl; LOG(0, "invalid number of arguments!");
return 1; return 1;
} }
bx::FilePath defPath(argv[1]); bx::FilePath defPath(argv[1]);
@@ -485,18 +580,24 @@ int main(int argc, const char** argv)
bx::Error error; bx::Error error;
if (!reader.open(defPath, &error)) if (!reader.open(defPath, &error))
{ {
std::cout << "failed to find def file at " << error.getMessage().getCPtr() << std::endl; LOG(0, "failed to find def file at %s", error.getMessage().getCPtr());
return 1; return 1;
} }
TestParser.BufferSize = bx::read(&reader, TestParser.Buffer, Parser::MaxBufferSize, &error); TestParser.BufferSize = bx::read(&reader, TestParser.Buffer, Parser::MaxBufferSize, &error);
Parser::Result Res = TestParser.Parse(); Parser::Result Res = TestParser.Parse();
if (Res == Parser::EndOfFile) if (Res == Parser::OK)
{ {
std::cout << "Success!" << std::endl; LOG_WARN(0, "Ending not at end of file, this is strange...");
TestParser.Definitions.GenerateCpp(outPath);
} }
else if (Res == Parser::Error)
{
LOG_ERROR(0, "Aborting with error, not generating file.");
return 1;
}
LOG(0, "Finished parsing!");
TestParser.Definitions.GenerateCpp(outPath);
return 0; return 0;
} }

View File

@@ -1,16 +1,13 @@
#pragma once #pragma once
#include <bx/file.h> #include <bx/file.h>
#include <cctype>
#include <cstdint> #include <cstdint>
#include <iostream> #include <string>
#include "Gen/Generated.h" #include "Gen/Generated.h"
#include "Logging.h"
#include "bx/string.h" #include "bx/string.h"
struct Log
{
static bool Assert(bool Condition, const char* Text);
};
enum class TokenType : uint8_t enum class TokenType : uint8_t
{ {
StartOfFile, StartOfFile,
@@ -33,35 +30,62 @@ struct ParseStack
} }
bool Push(TokenType T) bool Push(TokenType T)
{ {
if (Log::Assert(StackIdx < MaxSize - 1, "Inbalanced Push/Pop!")) return false; if (StackIdx >= MaxSize - 1)
{
return false;
}
StackIdx++; StackIdx++;
Stack[StackIdx] = T; Stack[StackIdx] = T;
return true; return true;
} }
TokenType Pop() TokenType Pop()
{ {
if (Log::Assert(StackIdx == 0, "Inbalanced Push/Pop!")) return TokenType::StartOfFile; if (StackIdx != 0)
{
return TokenType::StartOfFile;
}
TokenType T = Stack[StackIdx]; TokenType T = Stack[StackIdx];
StackIdx--; StackIdx--;
return T; return T;
} }
}; };
class TemplateWriter
{
private:
bx::WriterI& Writer;
bx::Error& Error;
public:
TemplateWriter(bx::WriterI& W, bx::Error& E) : Writer(W), Error(E)
{
}
void Write(const char* Template, ...);
};
namespace Def namespace Def
{ {
constexpr int32_t MaxNameLength = 64; constexpr int32_t MaxNameLength = 64;
constexpr int32_t MaxFields = 64; constexpr int32_t MaxFields = 64;
constexpr int32_t MaxExtraEnumFields = 1; constexpr int32_t MaxExtraEnumFields = 1;
union TypeUnion enum class EFieldType
{ {
Generated::KnownType::Enum Known; Native,
uint32_t TypeIdx; DefinedClass,
DefinedEnum
};
struct FieldType
{
EFieldType FieldKind = EFieldType::Native;
Generated::KnownType::Enum Native = Generated::KnownType::Enum::i32;
uint16_t TypeIdx = UINT16_MAX;
}; };
struct Type struct Type
{ {
int32_t FieldCount = 0; int32_t FieldCount = 0;
TypeUnion FieldTypes[MaxFields]; FieldType FieldTypes[MaxFields];
char FieldNames[MaxFields][MaxNameLength]; char FieldNames[MaxFields][MaxNameLength];
uint32_t FieldArraySizes[MaxFields]{0}; uint32_t FieldArraySizes[MaxFields]{0};
char Name[MaxNameLength]{0}; char Name[MaxNameLength]{0};
@@ -69,6 +93,7 @@ namespace Def
struct Enum struct Enum
{ {
FieldType EnumType;
int32_t EntryCount = 0; int32_t EntryCount = 0;
char EntryNames[MaxFields][MaxNameLength]; char EntryNames[MaxFields][MaxNameLength];
int32_t ExtraStringFieldCount = 0; int32_t ExtraStringFieldCount = 0;
@@ -81,11 +106,13 @@ namespace Def
struct DefinitionFile struct DefinitionFile
{ {
static constexpr int32_t MaxTypes = 256; static constexpr int32_t MaxTypes = 256;
void PrintTypeName(char* buf, int32_t bufSize, Def::TypeUnion type); void PrintTypeName(char* buf, int32_t bufSize, const Def::FieldType& type);
void WriteEnums(TemplateWriter& Template);
void WriteTypes(TemplateWriter& Template);
void GenerateCpp(const bx::FilePath& outDir); void GenerateCpp(const bx::FilePath& outDir);
Def::Type Types[MaxTypes]; Def::Type Types[MaxTypes];
int32_t TypeCount = 0; uint16_t TypeCount = 0;
Def::Enum Enums[MaxTypes]; Def::Enum Enums[MaxTypes];
int32_t EnumCount = 0; int32_t EnumCount = 0;
}; };
@@ -110,6 +137,7 @@ class Parser
int32_t BufferSize = 0; int32_t BufferSize = 0;
char Buffer[MaxBufferSize]{0}; char Buffer[MaxBufferSize]{0};
char* ReadPtr = &Buffer[0]; char* ReadPtr = &Buffer[0];
uint32_t Line = 0;
DefinitionFile Definitions; DefinitionFile Definitions;
ParseStack Stack; ParseStack Stack;
@@ -121,7 +149,7 @@ class Parser
int32_t GetRemaining(); int32_t GetRemaining();
Result SkipWhitespace(bool* SkippedNewLine = nullptr); Result SkipWhitespace(bool* SkippedNewLine = nullptr);
Result SkipLine(); Result SkipLine();
bool CmpAdvance(bx::StringView expect, Result& Res); bool CmpAdvance(bx::StringView expect, Result& Res, bool RequireGap = false);
Result ExpectChar(bx::StringView expect); Result ExpectChar(bx::StringView expect);
Result Advance(int32_t Amount); Result Advance(int32_t Amount);
Result HandleFileStart(); Result HandleFileStart();
@@ -129,10 +157,12 @@ class Parser
Result HandleEnum(); Result HandleEnum();
Result ReadName(char* Target); Result ReadName(char* Target);
Result ReadUint(uint32_t& Out); Result ReadUint(uint32_t& Out);
Result ReadNativeFieldType(Def::FieldType& FieldT);
Result ReadDefinedFieldType(Def::FieldType& FieldT);
Result ReadTypeToken(); Result ReadTypeToken();
Result ReadOptionalEnumValues(Def::Enum& Enum, int32_t EntryIdx); Result ReadOptionalEnumValues(Def::Enum& Enum, int32_t EntryIdx);
std::string PrintLine() void ErrorLine()
{ {
char line[64]{0}; char line[64]{0};
for (int32_t i = 0; i < sizeof(line) - 1; ++i) for (int32_t i = 0; i < sizeof(line) - 1; ++i)
@@ -141,20 +171,6 @@ class Parser
if (Advance(1) != Result::OK) break; if (Advance(1) != Result::OK) break;
if (*ReadPtr == '\n' || *ReadPtr == '\r') break; if (*ReadPtr == '\n' || *ReadPtr == '\r') break;
} }
return std::string{line}; LOG_ERROR(Line, "%s", line);
} }
}; };
class TemplateWriter
{
private:
bx::WriterI& Writer;
bx::Error& Error;
public:
TemplateWriter(bx::WriterI& W, bx::Error& E) : Writer(W), Error(E)
{
}
void Write(const char* Template, ...);
};

View File

@@ -10,16 +10,16 @@ type ElemPos
u8 ElemIdx u8 ElemIdx
} }
enum PuzzleElementType Type(u8) enum PuzzleElementType(u8)
{ {
None, None GameName("Empty")
WaterIn, WaterIn GameName("Water Source")
WaterGoal, WaterGoal GameName("Water Goal")
WaterChannel, WaterChannel GameName("Water Channel")
ElectricIn, ElectricIn GameName("Electricity Source")
ElectricGoal, ElectricGoal GameName("Electricity Goal")
Blocked, Blocked GameName("Blocked")
Bridge, Bridge GameName("Bridge")
} }
type PuzzleNode type PuzzleNode
@@ -45,6 +45,14 @@ type PuzzleCardStack
u8 UsedCount u8 UsedCount
} }
type PlacedPuzzleCard
{
StaticPuzzleCardHandle RefCard
PuzPos Position
u8 Rotation
b IsLocked
}
type PuzzleData type PuzzleData
{ {
u8 WidthTiles u8 WidthTiles

View File

@@ -3,12 +3,89 @@
namespace Generated namespace Generated
{ {
struct PuzzleElementType
{
static constexpr int32_t EntryCount = 8;
enum class Enum : int32_t
{
None,
WaterIn,
WaterGoal,
WaterChannel,
ElectricIn,
ElectricGoal,
Blocked,
Bridge,
};
static constexpr char EntryNames[EntryCount][64]
{
"None",
"WaterIn",
"WaterGoal",
"WaterChannel",
"ElectricIn",
"ElectricGoal",
"Blocked",
"Bridge",
};
static constexpr char GameName[EntryCount][64]
{
"Empty",
"Water Source",
"Water Goal",
"Water Channel",
"Electricity Source",
"Electricity Goal",
"Blocked",
"Bridge",
};
};
struct PuzPos
{
int8_t X = {};
int8_t Y = {};
};
struct ElemPos
{
PuzPos Position = {};
uint8_t ElemIdx = {};
};
struct PuzzleNode
{
PuzzleElementType PlacedTypes = {};
};
struct StaticPuzzleCard
{
PuzzleNode Nodes[8] = {};
uint16_t ModelHandle = {};
};
struct StaticPuzzleCardHandle
{
uint16_t Idx = {};
};
struct PuzzleCardStack
{
StaticPuzzleCardHandle RefCard = {};
uint8_t MaxAvailableCount = {};
uint8_t UsedCount = {};
};
struct PlacedPuzzleCard
{
StaticPuzzleCardHandle RefCard = {};
PuzPos Position = {};
uint8_t Rotation = {};
bool IsLocked = {};
};
struct PuzzleData struct PuzzleData
{ {
uint8_t WidthTiles = {}; uint8_t WidthTiles = {};
uint8_t HeightTiles = {}; uint8_t HeightTiles = {};
uint32_t AvailableCardCount = {}; uint32_t AvailableCardCount = {};
PuzzleCardStack AvailableCards[8] = {};
uint32_t PlacedCardCount = {}; uint32_t PlacedCardCount = {};
PlacedPuzzleCard PlacedCards[8] = {};
PuzzleNode PlacedNodes[8] = {};
uint32_t GoalPositionCount = {}; uint32_t GoalPositionCount = {};
ElemPos GoalPositions = {};
}; };
} }

Binary file not shown.