Add basic CPP struct reflection

This commit is contained in:
Doyle 2019-02-22 23:15:39 +11:00
parent 28a1fe8b24
commit 2cd7acaacb
2 changed files with 196 additions and 29 deletions

View File

@ -4,6 +4,22 @@
#define DQN_REFLECT #define DQN_REFLECT
#define DQN_REFLECT_META(...) #define DQN_REFLECT_META(...)
struct DqnReflect_StructMember
{
char const *type;
int type_len;
char const *name;
int name_len;
};
struct DqnReflect_Struct
{
char const *name;
int name_len;
DqnReflect_StructMember *members;
int members_len;
};
// //
// HOW TO REFLECT ANNOTATED CODE // HOW TO REFLECT ANNOTATED CODE
// Define in the preprocessor, DQN_REFLECT_IMPLEMENTATION and compile // Define in the preprocessor, DQN_REFLECT_IMPLEMENTATION and compile
@ -313,6 +329,7 @@ b32 StrCmp(StringLiteral a, StringLiteral b)
X(SemiColon, ";") \ X(SemiColon, ";") \
X(Identifier, "Identifier") \ X(Identifier, "Identifier") \
X(Number, "[0-9]") \ X(Number, "[0-9]") \
X(Asterisks, "*") \
X(Hash, "#") X(Hash, "#")
#define X(decl, str) decl, #define X(decl, str) decl,
@ -381,12 +398,22 @@ void CPPTokeniser_SprintfToFileNoIndenting(CPPTokeniser *tokeniser, char const *
va_end(va); va_end(va);
} }
CPPToken CPPTokeniser_NextToken(CPPTokeniser *tokeniser) CPPToken CPPTokeniser_NextToken(CPPTokeniser *tokeniser, int amount = 1)
{ {
CPPToken result = tokeniser->tokens[tokeniser->tokens_index++]; CPPToken result = tokeniser->tokens[tokeniser->tokens_index];
if (result.type == CPPTokenType::LeftBrace) tokeniser->indent_level++; if (result.type != CPPTokenType::EndOfStream)
else if (result.type == CPPTokenType::RightBrace) tokeniser->indent_level--; {
assert(tokeniser->indent_level >= 0); for (int i = 0; i < amount; i++)
{
result = tokeniser->tokens[tokeniser->tokens_index++];
if (result.type == CPPTokenType::LeftBrace) tokeniser->indent_level++;
else if (result.type == CPPTokenType::RightBrace) tokeniser->indent_level--;
assert(tokeniser->indent_level >= 0);
if (result.type == CPPTokenType::EndOfStream)
break;
}
}
return result; return result;
} }
@ -446,9 +473,12 @@ CPPReflectMetadataArray ParseCPPReflectMeta(CPPTokeniser *tokeniser)
{ {
CPPReflectMetadataArray result = {}; CPPReflectMetadataArray result = {};
CPPToken token = CPPTokeniser_NextToken(tokeniser); CPPToken token = CPPTokeniser_NextToken(tokeniser);
if (!ExpectToken(token, CPPTokenType::OpenParen)) if (!ExpectToken(token, CPPTokenType::Identifier) || !IsIdentifierToken(token, STR_LITERAL("DQN_REFLECT_META")))
return result; return result;
token = CPPTokeniser_NextToken(tokeniser);
if (!ExpectToken(token, CPPTokenType::OpenParen)) return result;
for (token = CPPTokeniser_NextToken(tokeniser); for (token = CPPTokeniser_NextToken(tokeniser);
token.type != CPPTokenType::EndOfStream && token.type != CPPTokenType::CloseParen; token.type != CPPTokenType::EndOfStream && token.type != CPPTokenType::CloseParen;
token = CPPTokeniser_NextToken(tokeniser)) token = CPPTokeniser_NextToken(tokeniser))
@ -478,14 +508,16 @@ CPPReflectMetadataArray ParseCPPReflectMeta(CPPTokeniser *tokeniser)
while (token.type != CPPTokenType::EndOfStream && token.type != CPPTokenType::Comma) while (token.type != CPPTokenType::EndOfStream && token.type != CPPTokenType::Comma)
token = CPPTokeniser_NextToken(tokeniser); token = CPPTokeniser_NextToken(tokeniser);
if (token.type == CPPTokenType::EndOfStream)
CPPTokeniser_RewindToken(tokeniser);
return result; return result;
} }
void ParseCPPEnum(CPPTokeniser *tokeniser) void ParseCPPEnum(CPPTokeniser *tokeniser)
{ {
CPPToken token = CPPTokeniser_NextToken(tokeniser); CPPToken token = CPPTokeniser_NextToken(tokeniser);
if (!ExpectToken(token, CPPTokenType::Identifier) || !IsIdentifierToken(token, STR_LITERAL("enum")))
return;
token = CPPTokeniser_NextToken(tokeniser);
b32 enum_is_struct_or_class = false; b32 enum_is_struct_or_class = false;
if (IsIdentifierToken(token, STR_LITERAL("class")) || if (IsIdentifierToken(token, STR_LITERAL("class")) ||
@ -514,9 +546,9 @@ void ParseCPPEnum(CPPTokeniser *tokeniser)
if (token.type == CPPTokenType::Identifier) if (token.type == CPPTokenType::Identifier)
{ {
CPPToken enum_value = token; CPPToken enum_value = token;
token = CPPTokeniser_NextToken(tokeniser); CPPToken peek_token = CPPTokeniser_PeekToken(tokeniser);
CPPReflectMetadataArray metadata_array = {}; CPPReflectMetadataArray metadata_array = {};
if (IsIdentifierToken(token, STR_LITERAL("DQN_REFLECT_META"))) if (IsIdentifierToken(peek_token, STR_LITERAL("DQN_REFLECT_META")))
{ {
has_metadata = true; has_metadata = true;
metadata_array = ParseCPPReflectMeta(tokeniser); metadata_array = ParseCPPReflectMeta(tokeniser);
@ -626,7 +658,7 @@ void ParseCPPEnum(CPPTokeniser *tokeniser)
// //
if (has_metadata) if (has_metadata)
{ {
struct CPPDeclToValue struct CPPDeclToMetaValue
{ {
StringLiteral cpp_decl; StringLiteral cpp_decl;
StringLiteral value; StringLiteral value;
@ -634,8 +666,8 @@ void ParseCPPEnum(CPPTokeniser *tokeniser)
struct MetadataEntry struct MetadataEntry
{ {
StringLiteral key; StringLiteral key;
FixedArray<CPPDeclToValue, 32> cpp_decl_to_val; FixedArray<CPPDeclToMetaValue, 32> cpp_decl_to_val;
}; };
FixedArray<MetadataEntry, 32> metadata_entries = {}; FixedArray<MetadataEntry, 32> metadata_entries = {};
@ -661,7 +693,7 @@ void ParseCPPEnum(CPPTokeniser *tokeniser)
metadata_entry_to_append_to->key = reflect_entry.key; metadata_entry_to_append_to->key = reflect_entry.key;
} }
CPPDeclToValue decl_to_val = {}; CPPDeclToMetaValue decl_to_val = {};
decl_to_val.cpp_decl = StringLiteral(link->value.str, link->value.len); decl_to_val.cpp_decl = StringLiteral(link->value.str, link->value.len);
decl_to_val.value = reflect_entry.value; decl_to_val.value = reflect_entry.value;
FixedArray_Add(&metadata_entry_to_append_to->cpp_decl_to_val, decl_to_val); FixedArray_Add(&metadata_entry_to_append_to->cpp_decl_to_val, decl_to_val);
@ -683,7 +715,7 @@ void ParseCPPEnum(CPPTokeniser *tokeniser)
CPPTokeniser_SprintfToFile(tokeniser, "}\n\n"); CPPTokeniser_SprintfToFile(tokeniser, "}\n\n");
}; };
for (CPPDeclToValue const &decl_to_val : metadata.cpp_decl_to_val) for (CPPDeclToMetaValue const &decl_to_val : metadata.cpp_decl_to_val)
{ {
StringLiteral const *cpp_decl = &decl_to_val.cpp_decl; StringLiteral const *cpp_decl = &decl_to_val.cpp_decl;
StringLiteral const *value = &decl_to_val.value; StringLiteral const *value = &decl_to_val.value;
@ -707,6 +739,101 @@ void ParseCPPEnum(CPPTokeniser *tokeniser)
} }
} }
struct CPPVariableDecl
{
StringLiteral type;
StringLiteral name;
b32 is_array;
int array_len;
};
void ParseCPPStruct(CPPTokeniser *tokeniser)
{
CPPToken token = CPPTokeniser_NextToken(tokeniser);
if (!ExpectToken(token, CPPTokenType::Identifier) ||
(!IsIdentifierToken(token, STR_LITERAL("struct")) && !IsIdentifierToken(token, STR_LITERAL("class"))))
return;
int const original_indent_level = tokeniser->indent_level;
token = CPPTokeniser_NextToken(tokeniser);
StringLiteral name = STR_LITERAL("");
if (token.type != CPPTokenType::LeftBrace)
{
if (!ExpectToken(token, CPPTokenType::Identifier)) return;
name = StringLiteral(token.str, token.len);
}
FixedArray<CPPVariableDecl, 128> struct_members = {};
for (token = CPPTokeniser_NextToken(tokeniser);
tokeniser->indent_level != original_indent_level && token.type != CPPTokenType::EndOfStream;
token = CPPTokeniser_NextToken(tokeniser))
{
if (token.type == CPPTokenType::Identifier)
{
#if 0
int asterisks_count = 0;
for (;; ++asterisks_count)
{
Token peek_token = CPPTokeniser_PeekToken(tokeniser);
if (peek_token == CPPTokenType::Asterisks) CPPTokeniser_NextToken(tokeniser);
else break;
}
#endif
CPPToken peek_token = CPPTokeniser_PeekToken(tokeniser);
if (peek_token.type == CPPTokenType::Identifier)
{
CPPVariableDecl *decl = FixedArray_Make(&struct_members, 1);
decl->type = StringLiteral(token.str, token.len);
decl->name = StringLiteral(peek_token.str, peek_token.len);
CPPTokeniser_NextToken(tokeniser);
peek_token = CPPTokeniser_PeekToken(tokeniser);
CPPReflectMetadataArray metadata_array = {};
if (IsIdentifierToken(token, STR_LITERAL("DQN_REFLECT_META")))
{
metadata_array = ParseCPPReflectMeta(tokeniser);
}
}
}
}
if (name.len == 0)
return;
CPPTokeniser_SprintfToFile(tokeniser, "DqnReflect_Struct DqnReflect_Struct%.*s =\n{\n", name.len, name.str);
tokeniser->indent_level++;
CPPTokeniser_SprintfToFile(tokeniser, "\"%.*s\", // name \n", name.len, name.str);
CPPTokeniser_SprintfToFile(tokeniser, "DQN_REFLECT_CHAR_COUNT(\"%.*s\"), // name_len \n", name.len, name.str);
CPPTokeniser_SprintfToFile(tokeniser, "{ // members \n");
tokeniser->indent_level++;
for (CPPVariableDecl const &decl : struct_members)
{
CPPTokeniser_SprintfToFile(tokeniser, "{\n");
tokeniser->indent_level++;
CPPTokeniser_SprintfToFile(tokeniser, "\"%.*s\",\n", decl.type.len, decl.type.str);
CPPTokeniser_SprintfToFile(tokeniser, "DQN_REFLECT_CHAR_COUNT(\"%.*s\"),\n", decl.type.len, decl.type.str);
CPPTokeniser_SprintfToFile(tokeniser, "\"%.*s\",\n", decl.name.len, decl.name.str);
CPPTokeniser_SprintfToFile(tokeniser, "DQN_REFLECT_CHAR_COUNT(\"%.*s\"),\n", decl.name.len, decl.name.str);
tokeniser->indent_level--;
CPPTokeniser_SprintfToFile(tokeniser, "},\n");
}
tokeniser->indent_level--;
CPPTokeniser_SprintfToFile(tokeniser, "},\n");
CPPTokeniser_SprintfToFile(tokeniser, "%d // members_len \n", (int)struct_members.len);
tokeniser->indent_level--;
CPPTokeniser_SprintfToFile(tokeniser, "};\n");
int break_here = 5;
(void)break_here;
assert(tokeniser->indent_level == 0);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
if (argc < 1) if (argc < 1)
@ -728,6 +855,9 @@ int main(int argc, char *argv[])
"#ifndef DQN_REFLECT_GENERATED_H\n" "#ifndef DQN_REFLECT_GENERATED_H\n"
"#define DQN_REFLECT_GENERATED_H\n\n" "#define DQN_REFLECT_GENERATED_H\n\n"
"// This is an auto generated file using Dqn_Reflect\n" "// This is an auto generated file using Dqn_Reflect\n"
"\n"
"#define DQN_REFLECT_ARRAY_COUNT(array) sizeof(array)/sizeof((array)[0])\n"
"#define DQN_REFLECT_CHAR_COUNT(str) (DQN_REFLECT_ARRAY_COUNT(str) - 1)\n"
"\n"); "\n");
for (usize arg_index = 1; arg_index < argc; ++arg_index) for (usize arg_index = 1; arg_index < argc; ++arg_index)
@ -798,6 +928,8 @@ int main(int argc, char *argv[])
ptr = StrFind(buffer, REFLECT_MARKER)) ptr = StrFind(buffer, REFLECT_MARKER))
{ {
ptr += REFLECT_MARKER.len; ptr += REFLECT_MARKER.len;
int indent_level = 0;
bool started_lexing_scope = false;
for (; ptr;) for (; ptr;)
{ {
while (CharIsWhitespace(ptr[0])) ptr++; while (CharIsWhitespace(ptr[0])) ptr++;
@ -808,8 +940,8 @@ int main(int argc, char *argv[])
token->len = 1; token->len = 1;
switch(token->str[0]) switch(token->str[0])
{ {
case '{': { token->type = CPPTokenType::LeftBrace; } break; case '{': { token->type = CPPTokenType::LeftBrace; started_lexing_scope = true; indent_level++; } break;
case '}': { token->type = CPPTokenType::RightBrace; } break; case '}': { token->type = CPPTokenType::RightBrace; indent_level--; } break;
case '(': { token->type = CPPTokenType::OpenParen; } break; case '(': { token->type = CPPTokenType::OpenParen; } break;
case ')': { token->type = CPPTokenType::CloseParen; } break; case ')': { token->type = CPPTokenType::CloseParen; } break;
case ',': { token->type = CPPTokenType::Comma; } break; case ',': { token->type = CPPTokenType::Comma; } break;
@ -818,11 +950,13 @@ int main(int argc, char *argv[])
case '<': { token->type = CPPTokenType::LessThan; } break; case '<': { token->type = CPPTokenType::LessThan; } break;
case '>': { token->type = CPPTokenType::GreaterThan; } break; case '>': { token->type = CPPTokenType::GreaterThan; } break;
case ':': { token->type = CPPTokenType::Colon; } break; case ':': { token->type = CPPTokenType::Colon; } break;
case '*': { token->type = CPPTokenType::Asterisks; } break;
case '/': case '/':
{ {
token->type = CPPTokenType::FwdSlash; token->type = CPPTokenType::FwdSlash;
if (ptr[0] == '/') if (ptr[0] == '/')
{ {
ptr++;
while (ptr[0] == ' ' || ptr[0] == '\t') ptr++; while (ptr[0] == ' ' || ptr[0] == '\t') ptr++;
token->str = ptr; token->str = ptr;
while (ptr[0] != '\n') ptr++; while (ptr[0] != '\n') ptr++;
@ -880,9 +1014,10 @@ int main(int argc, char *argv[])
*token = {}; *token = {};
tokeniser.tokens_len--; tokeniser.tokens_len--;
} }
else if (token->type == CPPTokenType::SemiColon) else
{ {
break; if (started_lexing_scope && indent_level == 0)
break;
} }
} }
@ -893,20 +1028,30 @@ int main(int argc, char *argv[])
CPPToken *sentinel = CPPTokeniser_MakeToken(&tokeniser); CPPToken *sentinel = CPPTokeniser_MakeToken(&tokeniser);
sentinel->type = CPPTokenType::EndOfStream; sentinel->type = CPPTokenType::EndOfStream;
for (CPPToken token = CPPTokeniser_NextToken(&tokeniser); for (CPPToken token = CPPTokeniser_PeekToken(&tokeniser);
token.type != CPPTokenType::EndOfStream; ;
token = CPPTokeniser_NextToken(&tokeniser)) token = CPPTokeniser_PeekToken(&tokeniser))
{ {
#if 0 #if 0
Token const *token = tokens + index; Token const *token = tokens + index;
fprintf(stdout, "%.*s", token->len, token->str); fprintf(stdout, "%.*s", token->len, token->str);
if (index < (tokens_index - 1)) fprintf(stdout, " -> "); if (index < (tokens_index - 1)) fprintf(stdout, " -> ");
#endif #endif
if (token.type == CPPTokenType::Identifier) if (IsIdentifierToken(token, STR_LITERAL("enum")))
{ {
if (StrCmp(StringLiteral(token.str, token.len), STR_LITERAL("enum"))) ParseCPPEnum(&tokeniser);
ParseCPPEnum(&tokeniser);
} }
else if (IsIdentifierToken(token, STR_LITERAL("struct")) || IsIdentifierToken(token, STR_LITERAL("class")))
{
ParseCPPStruct(&tokeniser);
}
else
{
token = CPPTokeniser_NextToken(&tokeniser);
}
if (token.type == CPPTokenType::EndOfStream)
break;
} }
fprintf(output_file, "#endif // DQN_REFLECT_DISABLE_%.*s\n\n", fprintf(output_file, "#endif // DQN_REFLECT_DISABLE_%.*s\n\n",

View File

@ -1,6 +1,28 @@
DQN_REFLECT enum struct OpenGLShader enum struct OpenGLShader
{ {
Invalid, Invalid,
Rect DQN_REFLECT_META(VertexShaderFilePath = "Rect.vert", FragmentShaderFilePath = "Rect.frag"), Rect (VertexShaderFilePath = "Rect.vert", FragmentShaderFilePath = "Rect.frag"),
Text DQN_REFLECT_META(VertexShaderFilePath = "Text.vert", FragmentShaderFilePath = "Text.frag"), Text (VertexShaderFilePath = "Text.vert", FragmentShaderFilePath = "Text.frag"),
};
#if 0
#define EXAMPLE_MACRO \
X(EndOfStream, "End Of Stream") \
X(Hash, "#")
#define MAXIMUM_MACRO(a, b) (a > b) ? (a) : (b)
#endif
DQN_REFLECT struct OpenGLState
{
// #if 0
// #endif
// u32 ebo, vbo, vao;
// u32 shaders[(int)OpenGLShader::Count];
V4 draw_color;
V3 lighting_ambient_coeff;
// u8 **bitmaps;
// FixedArray<RendererLight, 32> lights;
// FixedArray<Mat4, 32> camera_matrixes;
int draw_call_count;
}; };