Align nicely generated prototypes to ease reading

This commit is contained in:
Doyle 2019-03-24 16:02:41 +11:00
parent a91eb241c4
commit a38ef363db
2 changed files with 444 additions and 348 deletions

View File

@ -266,8 +266,8 @@ struct DqnInspect_Struct
}; };
// NOTE(doyle): For compiler testing // NOTE(doyle): For compiler testing
// #include "../Data/DqnInspect_TestData.h" #include "../Data/DqnInspect_TestData.h"
// #include "../Data/DqnInspect_TestDataGenerated.cpp" #include "../Data/DqnInspect_TestDataGenerated.cpp"
#ifdef DQN_INSPECT_EXECUTABLE_IMPLEMENTATION #ifdef DQN_INSPECT_EXECUTABLE_IMPLEMENTATION
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
@ -278,6 +278,7 @@ struct DqnInspect_Struct
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include <vector>
using usize = size_t; using usize = size_t;
using isize = ptrdiff_t; using isize = ptrdiff_t;
@ -742,35 +743,72 @@ struct MetadataEntry
FixedArray<CPPDeclToMetaValue, 32> cpp_decl_to_val; FixedArray<CPPDeclToMetaValue, 32> cpp_decl_to_val;
}; };
void ParseCPPEnum(CPPTokeniser *tokeniser) enum struct ParsedResultType
{ {
Invalid,
Struct,
Enum,
FunctionPrototype,
};
struct ParsedEnum
{
b32 struct_or_class_decl;
StringLiteral name;
CPPDeclLinkedList<StringLiteral> *members;
};
struct ParsedStruct
{
StringLiteral name;
CPPDeclLinkedList<CPPVariableDecl> *members;
};
struct ParsedFunctionPrototype
{
StringLiteral return_type;
StringLiteral name;
CPPDeclLinkedList<CPPVariableDecl> *members;
};
struct ParsedResult
{
ParsedResultType type;
union
{
ParsedEnum parsed_enum;
ParsedFunctionPrototype parsed_func_prototype;
ParsedStruct parsed_struct;
};
};
b32 ParseCPPEnum(CPPTokeniser *tokeniser, ParsedEnum *parsed_enum)
{
*parsed_enum = {};
CPPToken token = CPPTokeniser_NextToken(tokeniser); CPPToken token = CPPTokeniser_NextToken(tokeniser);
if (!ExpectToken(token, CPPTokenType::Identifier) || !IsIdentifierToken(token, STR_LITERAL("enum"))) if (!ExpectToken(token, CPPTokenType::Identifier) || !IsIdentifierToken(token, STR_LITERAL("enum")))
return; return false;
token = CPPTokeniser_NextToken(tokeniser); token = CPPTokeniser_NextToken(tokeniser);
b32 enum_is_struct_or_class = false;
if (IsIdentifierToken(token, STR_LITERAL("class")) || if (IsIdentifierToken(token, STR_LITERAL("class")) ||
IsIdentifierToken(token, STR_LITERAL("struct"))) IsIdentifierToken(token, STR_LITERAL("struct")))
{ {
enum_is_struct_or_class = true; parsed_enum->struct_or_class_decl = true;
token = CPPTokeniser_NextToken(tokeniser); token = CPPTokeniser_NextToken(tokeniser);
} }
if (!ExpectToken(token, CPPTokenType::Identifier)) if (!ExpectToken(token, CPPTokenType::Identifier))
return; return false;
int original_indent_level = tokeniser->indent_level; int original_indent_level = tokeniser->indent_level;
CPPToken const enum_name = token; CPPToken const enum_name = token;
token = CPPTokeniser_NextToken(tokeniser); token = CPPTokeniser_NextToken(tokeniser);
if (!ExpectToken(token, CPPTokenType::LeftBrace)) if (!ExpectToken(token, CPPTokenType::LeftBrace))
return; return false;
CPPDeclLinkedList<StringLiteral> *enum_members = nullptr;
MemArenaScopedRegion mem_region = MemArena_MakeScopedRegion(&global_main_arena);
parsed_enum->name = StringLiteral(enum_name.str, enum_name.len);
{ {
CPPDeclLinkedList<StringLiteral> *link_iterator = nullptr; CPPDeclLinkedList<StringLiteral> *link_iterator = nullptr;
for (token = CPPTokeniser_NextToken(tokeniser); for (token = CPPTokeniser_NextToken(tokeniser);
@ -781,7 +819,7 @@ void ParseCPPEnum(CPPTokeniser *tokeniser)
{ {
auto *link = MEM_ARENA_ALLOC_STRUCT(&global_main_arena, CPPDeclLinkedList<StringLiteral>); auto *link = MEM_ARENA_ALLOC_STRUCT(&global_main_arena, CPPDeclLinkedList<StringLiteral>);
*link = {}; *link = {};
if (!link_iterator) enum_members = link; // Set members to first linked list entry if (!link_iterator) parsed_enum->members = link; // Set members to first linked list entry
else link_iterator->next = link; else link_iterator->next = link;
link_iterator = link; link_iterator = link;
@ -795,159 +833,7 @@ void ParseCPPEnum(CPPTokeniser *tokeniser)
} }
} }
// return true;
// Write Stringified Enum Array
//
{
CPPTokeniser_SprintfToFile(tokeniser, "char const *DqnInspect_%.*s_Strings[] = {", enum_name.len, enum_name.str);
tokeniser->indent_level++;
for (CPPDeclLinkedList<StringLiteral> *link = enum_members; link; link = link->next)
{
StringLiteral enum_value = link->value;
CPPTokeniser_SprintfToFileNoIndenting(tokeniser, "\"%.*s\", ", enum_value.len, enum_value.str);
}
tokeniser->indent_level--;
CPPTokeniser_SprintfToFile(tokeniser, "};\n\n");
}
//
// Write InspectEnumString Function
//
{
CPPTokeniser_SprintfToFile(tokeniser, "char const *DqnInspect_EnumString(%.*s val)\n{\n", enum_name.len, enum_name.str);
tokeniser->indent_level++;
DEFER
{
CPPTokeniser_SprintfToFile(tokeniser, "return nullptr;\n");
tokeniser->indent_level--;
CPPTokeniser_SprintfToFile(tokeniser, "}\n\n");
};
struct SourceCode
{
StringLiteral decl;
StringLiteral enum_value;
};
LinkedList<SourceCode> src_code = {};
int longest_decl_len = 0;
{
LinkedList<SourceCode> *curr_src_code = nullptr;
char const *fmt = (enum_is_struct_or_class) ? "if (val == %.*s::%.*s) " : "if (val == %.*s) ";
for (CPPDeclLinkedList<StringLiteral> *link = enum_members; link; link = link->next)
{
if (!curr_src_code) curr_src_code = &src_code;
else
{
curr_src_code->next = static_cast<LinkedList<SourceCode> *>( MemArena_Alloc(&global_main_arena, sizeof(*curr_src_code)));
curr_src_code = curr_src_code->next;
}
StringLiteral enum_value = link->value;
int required_len = 0;
if (enum_is_struct_or_class) required_len = snprintf(nullptr, 0, fmt, enum_name.len, enum_name.str, enum_value.len, enum_value.str) + 1;
else required_len = snprintf(nullptr, 0, fmt, enum_value.len, enum_value.str) + 1;
longest_decl_len = INSPECT_MAX(longest_decl_len, required_len);
curr_src_code->value.decl.str = MEM_ARENA_ALLOC_ARRAY(&global_main_arena, char, required_len);
curr_src_code->value.decl.len = required_len;
curr_src_code->value.enum_value = enum_value;
if (enum_is_struct_or_class) snprintf(curr_src_code->value.decl.str, curr_src_code->value.decl.len, fmt, enum_name.len, enum_name.str, enum_value.len, enum_value.str);
else snprintf(curr_src_code->value.decl.str, curr_src_code->value.decl.len, fmt, enum_value.len, enum_value.str);
}
curr_src_code->next = nullptr;
}
int enum_index = 0;
for (LinkedList<SourceCode> *src_code_ptr = &src_code;
src_code_ptr;
src_code_ptr = src_code_ptr->next, ++enum_index)
{
StringLiteral enum_value = src_code_ptr->value.enum_value;
int padding = longest_decl_len - src_code_ptr->value.decl.len;
CPPTokeniser_SprintfToFile(tokeniser, "%.*s%*s", src_code_ptr->value.decl.len, src_code_ptr->value.decl.str, padding, "");
CPPTokeniser_SprintfToFileNoIndenting(tokeniser,
"return DqnInspect_%.*s_Strings[%d]; // \"%.*s\"\n",
enum_name.len, enum_name.str,
enum_index,
enum_value.len, enum_value.str);
}
}
//
// Write User Annotated Metadata Getter Functions
//
{
FixedArray<MetadataEntry, 32> metadata_entries = {};
for (CPPDeclLinkedList<StringLiteral> *link = enum_members;
link;
link = link->next)
{
for (CPPInspectMetadataEntry const &inspect_entry : link->metadata_array)
{
MetadataEntry *metadata_entry_to_append_to = nullptr;
for (MetadataEntry &check_metadata_entry : metadata_entries)
{
if (StrCmp(check_metadata_entry.key, inspect_entry.key))
{
metadata_entry_to_append_to = &check_metadata_entry;
break;
}
}
if (!metadata_entry_to_append_to)
{
metadata_entry_to_append_to = FixedArray_Make(&metadata_entries, 1);
metadata_entry_to_append_to->key = inspect_entry.key;
}
CPPDeclToMetaValue decl_to_val = {};
decl_to_val.cpp_decl = StringLiteral(link->value.str, link->value.len);
decl_to_val.value = inspect_entry.value;
FixedArray_Add(&metadata_entry_to_append_to->cpp_decl_to_val, decl_to_val);
}
}
for (MetadataEntry const &metadata : metadata_entries)
{
CPPTokeniser_SprintfToFile(tokeniser,
"char const *DqnInspect_%.*sMetadata(%.*s val)\n{\n",
metadata.key.len, metadata.key.str,
enum_name.len, enum_name.str);
tokeniser->indent_level++;
DEFER
{
CPPTokeniser_SprintfToFile(tokeniser, "return nullptr;\n");
tokeniser->indent_level--;
CPPTokeniser_SprintfToFile(tokeniser, "}\n\n");
};
for (CPPDeclToMetaValue const &decl_to_val : metadata.cpp_decl_to_val)
{
StringLiteral const *cpp_decl = &decl_to_val.cpp_decl;
StringLiteral const *value = &decl_to_val.value;
if (enum_is_struct_or_class)
{
CPPTokeniser_SprintfToFile(tokeniser,
"if (val == %.*s::%.*s) ",
enum_name.len, enum_name.str,
cpp_decl->len, cpp_decl->str);
}
else
{
CPPTokeniser_SprintfToFile(tokeniser,
"if (val == %.*s) ",
cpp_decl->len, cpp_decl->str);
}
CPPTokeniser_SprintfToFileNoIndenting(tokeniser, "return \"%.*s\";\n", value->len, value->str);
}
}
}
} }
int ConsumeAsterisks(CPPTokeniser *tokeniser) int ConsumeAsterisks(CPPTokeniser *tokeniser)
@ -1043,7 +929,7 @@ b32 ParseCPPVariableType(CPPTokeniser *tokeniser, StringLiteral *type)
} }
return true; return true;
}; }
// NOTE(doyle): Doesn't parse the ending semicolon so we can reuse this function for parsing function arguments // NOTE(doyle): Doesn't parse the ending semicolon so we can reuse this function for parsing function arguments
CPPDeclLinkedList<CPPVariableDecl> *ParseCPPTypeAndVariableDecl(CPPTokeniser *tokeniser, b32 parse_function_param) CPPDeclLinkedList<CPPVariableDecl> *ParseCPPTypeAndVariableDecl(CPPTokeniser *tokeniser, b32 parse_function_param)
@ -1102,11 +988,6 @@ CPPDeclLinkedList<CPPVariableDecl> *ParseCPPTypeAndVariableDecl(CPPTokeniser *to
CPPTokeniser_NextToken(tokeniser); CPPTokeniser_NextToken(tokeniser);
} }
else
{
int break_here = 5;
(void)break_here;
}
// Allocate A Member Declaration // Allocate A Member Declaration
auto *link = MEM_ARENA_ALLOC_STRUCT(&global_main_arena, CPPDeclLinkedList<CPPVariableDecl>); auto *link = MEM_ARENA_ALLOC_STRUCT(&global_main_arena, CPPDeclLinkedList<CPPVariableDecl>);
@ -1154,26 +1035,23 @@ CPPDeclLinkedList<CPPVariableDecl> *ParseCPPTypeAndVariableDecl(CPPTokeniser *to
return result; return result;
} }
void ParseCPPStruct(CPPTokeniser *tokeniser) b32 ParseCPPStruct(CPPTokeniser *tokeniser, ParsedStruct *parsed_struct)
{ {
*parsed_struct = {};
CPPToken token = CPPTokeniser_NextToken(tokeniser); CPPToken token = CPPTokeniser_NextToken(tokeniser);
if (!ExpectToken(token, CPPTokenType::Identifier) || if (!ExpectToken(token, CPPTokenType::Identifier) ||
(!IsIdentifierToken(token, STR_LITERAL("struct")) && !IsIdentifierToken(token, STR_LITERAL("class")))) (!IsIdentifierToken(token, STR_LITERAL("struct")) && !IsIdentifierToken(token, STR_LITERAL("class"))))
return; return false;
int const original_indent_level = tokeniser->indent_level; int const original_indent_level = tokeniser->indent_level;
token = CPPTokeniser_NextToken(tokeniser); token = CPPTokeniser_NextToken(tokeniser);
StringLiteral name = STR_LITERAL("");
if (token.type != CPPTokenType::LeftBrace) if (token.type != CPPTokenType::LeftBrace)
{ {
if (!ExpectToken(token, CPPTokenType::Identifier)) return; if (!ExpectToken(token, CPPTokenType::Identifier)) return false;
name = StringLiteral(token.str, token.len); parsed_struct->name = StringLiteral(token.str, token.len);
} }
CPPDeclLinkedList<CPPVariableDecl> *struct_members = nullptr;
MemArenaScopedRegion mem_region = MemArena_MakeScopedRegion(&global_main_arena);
{ {
CPPDeclLinkedList<CPPVariableDecl> *link_iterator = nullptr; CPPDeclLinkedList<CPPVariableDecl> *link_iterator = nullptr;
for (token = CPPTokeniser_NextToken(tokeniser); for (token = CPPTokeniser_NextToken(tokeniser);
@ -1184,7 +1062,7 @@ void ParseCPPStruct(CPPTokeniser *tokeniser)
{ {
CPPTokeniser_RewindToken(tokeniser); CPPTokeniser_RewindToken(tokeniser);
CPPDeclLinkedList<CPPVariableDecl> *link = ParseCPPTypeAndVariableDecl(tokeniser, false); CPPDeclLinkedList<CPPVariableDecl> *link = ParseCPPTypeAndVariableDecl(tokeniser, false);
if (!struct_members) struct_members = link; if (!parsed_struct->members) parsed_struct->members = link;
if (!link_iterator) link_iterator = link; if (!link_iterator) link_iterator = link;
else else
{ {
@ -1197,108 +1075,10 @@ void ParseCPPStruct(CPPTokeniser *tokeniser)
} }
// TODO(doyle): Don't support anonymous/nameless structs yet // TODO(doyle): Don't support anonymous/nameless structs yet
if (name.len == 0) if (parsed_struct->name.len == 0)
return; return false;
// return true;
// Write DqnInspect_StructMemberMetadata Definition
//
for (CPPDeclLinkedList<CPPVariableDecl> const *member = struct_members; member; member = member->next)
{
CPPVariableDecl const *decl = &member->value;
if (member->metadata_array.len <= 0)
continue;
CPPTokeniser_SprintfToFile(
tokeniser,
"DqnInspect_StructMemberMetadata const DqnInspect_%.*s_%.*s_StructMemberMetadata[] =\n{\n",
name.len,
name.str,
decl->name.len,
decl->name.str);
tokeniser->indent_level++;
for (CPPInspectMetadataEntry const &entry : member->metadata_array)
{
CPPTokeniser_SprintfToFile(tokeniser, "{\n");
tokeniser->indent_level++;
CPPTokeniser_SprintfToFile(tokeniser, "DqnInspect_StructMemberMetadataType::String,\n");
// metadata->key
CPPTokeniser_SprintfToFile(tokeniser, "STR_AND_LEN(\"%.*s\"), ", entry.key.len, entry.key.str);
// metadata->value
CPPTokeniser_SprintfToFileNoIndenting(tokeniser, "STR_AND_LEN(\"%.*s\"),\n", entry.value.len, entry.value.str);
tokeniser->indent_level--;
CPPTokeniser_SprintfToFile(tokeniser, "},\n");
}
tokeniser->indent_level--;
CPPTokeniser_SprintfToFile(tokeniser, "};\n\n");
}
//
// Write DqnInspect_StructMembers Definition
//
{
CPPTokeniser_SprintfToFile(tokeniser, "DqnInspect_StructMember const DqnInspect_%.*s_StructMembers[] =\n{\n", name.len, name.str);
tokeniser->indent_level++;
for (CPPDeclLinkedList<CPPVariableDecl> const *member = struct_members; member; member = member->next)
{
CPPVariableDecl const *decl = &member->value;
CPPTokeniser_SprintfToFile(tokeniser, "{\n");
tokeniser->indent_level++;
CPPTokeniser_SprintfToFile(tokeniser, "STR_AND_LEN(\"%.*s\"), ", decl->type.len, decl->type.str);
CPPTokeniser_SprintfToFileNoIndenting(tokeniser, "STR_AND_LEN(\"%.*s\"),\n", decl->name.len, decl->name.str);
if (decl->template_expr.len <= 0)
CPPTokeniser_SprintfToFile(tokeniser, "nullptr, 0, // template_expr and template_expr_len\n");
else
CPPTokeniser_SprintfToFile(tokeniser, "STR_AND_LEN(\"%.*s\"), // template_expr\n", decl->template_expr.len, decl->template_expr.str);
if (member->metadata_array.len <= 0) CPPTokeniser_SprintfToFile(tokeniser, "nullptr, 0, // metadata and metadata_len\n");
else CPPTokeniser_SprintfToFile(tokeniser, "DqnInspect_%.*s_%.*s_StructMemberMetadata, %d,\n", name.len, name.str, decl->name.len, decl->name.str, member->metadata_array.len);
CPPTokeniser_SprintfToFile(tokeniser, "%d // array_dimensions\n", decl->array_dimensions);
tokeniser->indent_level--;
CPPTokeniser_SprintfToFile(tokeniser, "},\n");
}
tokeniser->indent_level--;
CPPTokeniser_SprintfToFile(tokeniser, "};\n\n");
}
//
// Write DqnInspect_Struct Definition
//
{
CPPTokeniser_SprintfToFile(tokeniser, "DqnInspect_Struct const DqnInspect_%.*s_Struct =\n{\n", name.len, name.str);
tokeniser->indent_level++;
CPPTokeniser_SprintfToFile(tokeniser, "STR_AND_LEN(\"%.*s\"),\n", name.len, name.str);
CPPTokeniser_SprintfToFile(tokeniser, "DqnInspect_%.*s_StructMembers, // members\n", name.len, name.str);
CPPTokeniser_SprintfToFile(tokeniser, "ARRAY_COUNT(DqnInspect_%.*s_StructMembers) // members_len\n", name.len, name.str);
tokeniser->indent_level--;
CPPTokeniser_SprintfToFile(tokeniser, "};\n\n");
assert(tokeniser->indent_level == 0);
}
//
// Write DqnInspect_Struct getter
//
{
CPPTokeniser_SprintfToFile(tokeniser, "DqnInspect_Struct const *DqnInspect_GetStruct(%.*s const *val)\n", name.len, name.str);
CPPTokeniser_SprintfToFile(tokeniser, "{\n");
tokeniser->indent_level++;
CPPTokeniser_SprintfToFile(tokeniser, "(void)val;\n");
CPPTokeniser_SprintfToFile(tokeniser, "DqnInspect_Struct const *result = &DqnInspect_%.*s_Struct;\n", name.len, name.str);
CPPTokeniser_SprintfToFile(tokeniser, "return result;\n");
tokeniser->indent_level--;
CPPTokeniser_SprintfToFile(tokeniser, "}\n\n");
}
} }
void SkipFunctionParam(CPPTokeniser *tokeniser) void SkipFunctionParam(CPPTokeniser *tokeniser)
@ -1344,11 +1124,12 @@ void SkipFunctionParam(CPPTokeniser *tokeniser)
} }
} }
void ParseCPPInspectPrototype(CPPTokeniser *tokeniser) b32 ParseCPPInspectPrototype(CPPTokeniser *tokeniser, ParsedFunctionPrototype *parsed_func)
{ {
*parsed_func = {};
CPPToken token = CPPTokeniser_NextToken(tokeniser); CPPToken token = CPPTokeniser_NextToken(tokeniser);
if (!ExpectToken(token, CPPTokenType::InspectGeneratePrototype)) if (!ExpectToken(token, CPPTokenType::InspectGeneratePrototype))
return; return false;
struct FunctionDefaultParam struct FunctionDefaultParam
{ {
@ -1356,12 +1137,14 @@ void ParseCPPInspectPrototype(CPPTokeniser *tokeniser)
StringLiteral value; StringLiteral value;
}; };
//
// NOTE: Parse default params in the inspect prototype macro
//
LinkedList<FunctionDefaultParam> *default_param_list = nullptr; LinkedList<FunctionDefaultParam> *default_param_list = nullptr;
MemArenaScopedRegion mem_region = MemArena_MakeScopedRegion(&global_main_arena);
{ {
LinkedList<FunctionDefaultParam> *link_iterator = nullptr; LinkedList<FunctionDefaultParam> *link_iterator = nullptr;
if (!CPPTokeniser_AcceptTokenIfType(tokeniser, CPPTokenType::OpenParen, &token)) if (!CPPTokeniser_AcceptTokenIfType(tokeniser, CPPTokenType::OpenParen, &token))
return; return false;
for (token = CPPTokeniser_NextToken(tokeniser); for (token = CPPTokeniser_NextToken(tokeniser);
token.type != CPPTokenType::CloseParen && token.type != CPPTokenType::EndOfStream; token.type != CPPTokenType::CloseParen && token.type != CPPTokenType::EndOfStream;
@ -1419,19 +1202,17 @@ void ParseCPPInspectPrototype(CPPTokeniser *tokeniser)
StringLiteral default_value; StringLiteral default_value;
}; };
StringLiteral return_type = {};
StringLiteral function_name = {};
// Grab return type token // Grab return type token
{ {
token = CPPTokeniser_PeekToken(tokeniser); token = CPPTokeniser_PeekToken(tokeniser);
if (!ExpectToken(token, CPPTokenType::Identifier)) return; if (!ExpectToken(token, CPPTokenType::Identifier)) return false;
if (!ParseCPPVariableType(tokeniser, &return_type)) return; if (!ParseCPPVariableType(tokeniser, &parsed_func->return_type)) return false;
} }
// Grab function name token // Grab function name token
{ {
token = CPPTokeniser_PeekToken(tokeniser); token = CPPTokeniser_PeekToken(tokeniser);
if (!ExpectToken(token, CPPTokenType::Identifier)) return; if (!ExpectToken(token, CPPTokenType::Identifier)) return false;
char *name_start = token.str; char *name_start = token.str;
while (token.type != CPPTokenType::OpenParen && token.type != CPPTokenType::EndOfStream) while (token.type != CPPTokenType::OpenParen && token.type != CPPTokenType::EndOfStream)
@ -1440,16 +1221,18 @@ void ParseCPPInspectPrototype(CPPTokeniser *tokeniser)
token = CPPTokeniser_PeekToken(tokeniser); token = CPPTokeniser_PeekToken(tokeniser);
} }
if (!ExpectToken(token, CPPTokenType::OpenParen)) return; if (!ExpectToken(token, CPPTokenType::OpenParen)) return false;
char *name_end = token.str; char *name_end = token.str;
function_name = StringLiteral(name_start, static_cast<int>(name_end - name_start)); parsed_func->name = StringLiteral(name_start, static_cast<int>(name_end - name_start));
} }
token = CPPTokeniser_PeekToken(tokeniser); token = CPPTokeniser_PeekToken(tokeniser);
if (!ExpectToken(token, CPPTokenType::OpenParen)) if (!ExpectToken(token, CPPTokenType::OpenParen))
return; return false;
CPPDeclLinkedList<CPPVariableDecl> *param_list = nullptr; //
// NOTE: Parse CPP Function Parameters
//
{ {
CPPDeclLinkedList<CPPVariableDecl> *link_iterator = nullptr; CPPDeclLinkedList<CPPVariableDecl> *link_iterator = nullptr;
token = CPPTokeniser_NextToken(tokeniser); token = CPPTokeniser_NextToken(tokeniser);
@ -1461,7 +1244,7 @@ void ParseCPPInspectPrototype(CPPTokeniser *tokeniser)
{ {
CPPTokeniser_RewindToken(tokeniser); CPPTokeniser_RewindToken(tokeniser);
CPPDeclLinkedList<CPPVariableDecl> *link = ParseCPPTypeAndVariableDecl(tokeniser, true); CPPDeclLinkedList<CPPVariableDecl> *link = ParseCPPTypeAndVariableDecl(tokeniser, true);
if (!param_list) param_list = link; if (!parsed_func->members) parsed_func->members = link;
if (!link_iterator) link_iterator = link; if (!link_iterator) link_iterator = link;
else else
{ {
@ -1473,10 +1256,13 @@ void ParseCPPInspectPrototype(CPPTokeniser *tokeniser)
} }
} }
//
// NOTE: Map Default Parameters in the inspect prototype macro to the actual declaration in the CPP Prototype
//
for (LinkedList<FunctionDefaultParam> const *default_link = default_param_list; default_link; default_link = default_link->next) for (LinkedList<FunctionDefaultParam> const *default_link = default_param_list; default_link; default_link = default_link->next)
{ {
FunctionDefaultParam const *default_param = &default_link->value; FunctionDefaultParam const *default_param = &default_link->value;
for (CPPDeclLinkedList<CPPVariableDecl> *param_link = param_list; param_link; param_link = param_link->next) for (CPPDeclLinkedList<CPPVariableDecl> *param_link = parsed_func->members; param_link; param_link = param_link->next)
{ {
CPPVariableDecl *decl = &param_link->value; CPPVariableDecl *decl = &param_link->value;
if (StrCmp(decl->name, default_param->name)) if (StrCmp(decl->name, default_param->name))
@ -1487,42 +1273,7 @@ void ParseCPPInspectPrototype(CPPTokeniser *tokeniser)
} }
} }
if (return_type.str[return_type.len-1] == '*') // NOTE(doyle): Align the pointer to the name return true;
CPPTokeniser_SprintfToFile(tokeniser, "%.*s%.*s(", return_type.len, return_type.str, function_name.len, function_name.str);
else
CPPTokeniser_SprintfToFile(tokeniser, "%.*s %.*s(", return_type.len, return_type.str, function_name.len, function_name.str);
for (CPPDeclLinkedList<CPPVariableDecl> *param_link = param_list; param_link; param_link = param_link->next)
{
// TODO(doyle): HACK. We should parse ptrs into the CPPVariableDecl, fixed size arrays into the name and const-ness into the type
CPPVariableDecl *decl = &param_link->value;
StringLiteral *type = &decl->type;
char *type_end = (decl->template_expr.len > 0) ? decl->template_expr.str + decl->template_expr.len + 1 // +1 for the ending ">" on the template
: type->str + type->len;
StringLiteral *name = &decl->name;
StringLiteral hack_decl_name = {};
if (name->len > 0)
{
char *name_start = type_end + 1;
char *name_end = name->str + name->len;
hack_decl_name = StringLiteral(name_start, static_cast<int>(name_end - name_start));
}
CPPTokeniser_SprintfToFileNoIndenting(tokeniser, "%.*s", type->len, type->str);
if (decl->template_expr.len > 0)
CPPTokeniser_SprintfToFileNoIndenting(tokeniser, "<%.*s>", decl->template_expr.len, decl->template_expr.str);
if (hack_decl_name.len > 0)
CPPTokeniser_SprintfToFileNoIndenting(tokeniser, " %.*s", hack_decl_name.len, hack_decl_name.str);
if (decl->default_value.len > 0)
CPPTokeniser_SprintfToFileNoIndenting(tokeniser, " = %.*s", decl->default_value.len, decl->default_value.str);
if (param_link->next)
CPPTokeniser_SprintfToFileNoIndenting(tokeniser, ", ", return_type.len, return_type.str, function_name.len, function_name.str);
}
CPPTokeniser_SprintfToFileNoIndenting(tokeniser, ");\n");
} }
enum struct InspectMode enum struct InspectMode
@ -1763,11 +1514,6 @@ int main(int argc, char *argv[])
"\n" "\n"
"#ifndef DQN_INSPECT_%.*s\n" "#ifndef DQN_INSPECT_%.*s\n"
"#define DQN_INSPECT_%.*s\n" "#define DQN_INSPECT_%.*s\n"
"\n"
" // NOTE: These macros are undefined at the end of the file so to not pollute namespace\n"
"#define ARRAY_COUNT(array) sizeof(array)/sizeof((array)[0])\n"
"#define CHAR_COUNT(str) (ARRAY_COUNT(str) - 1)\n"
"#define STR_AND_LEN(str) str, CHAR_COUNT(str)\n"
"\n", "\n",
file_name, file_name,
file_include_contents_hash_define_len, file_include_contents_hash_define_len,
@ -1776,6 +1522,17 @@ int main(int argc, char *argv[])
file_include_contents_hash_define file_include_contents_hash_define
); );
if (mode == InspectMode::All || mode == InspectMode::Code)
{
fprintf(output_file,
" // NOTE: These macros are undefined at the end of the file so to not pollute namespace\n"
"#define ARRAY_COUNT(array) sizeof(array)/sizeof((array)[0])\n"
"#define CHAR_COUNT(str) (ARRAY_COUNT(str) - 1)\n"
"#define STR_AND_LEN(str) str, CHAR_COUNT(str)\n"
"\n"
);
}
CPPTokeniser tokeniser = {}; CPPTokeniser tokeniser = {};
tokeniser.spaces_per_indent = 4; tokeniser.spaces_per_indent = 4;
tokeniser.output_file = output_file; tokeniser.output_file = output_file;
@ -1828,10 +1585,16 @@ int main(int argc, char *argv[])
CPPToken *sentinel = CPPTokeniser_MakeToken(&tokeniser); CPPToken *sentinel = CPPTokeniser_MakeToken(&tokeniser);
sentinel->type = CPPTokenType::EndOfStream; sentinel->type = CPPTokenType::EndOfStream;
std::vector<ParsedResult> parsing_results;
parsing_results.reserve(1024);
int max_func_return_type_decl_len = 0;
int max_func_name_decl_len = 0;
for (CPPToken token = CPPTokeniser_PeekToken(&tokeniser); for (CPPToken token = CPPTokeniser_PeekToken(&tokeniser);
; ;
token = CPPTokeniser_PeekToken(&tokeniser)) token = CPPTokeniser_PeekToken(&tokeniser))
{ {
ParsedResult parse_result = {};
if (token.type == CPPTokenType::InspectCode || token.type == CPPTokenType::InspectGeneratePrototype) if (token.type == CPPTokenType::InspectCode || token.type == CPPTokenType::InspectGeneratePrototype)
{ {
if (token.type == CPPTokenType::InspectCode) if (token.type == CPPTokenType::InspectCode)
@ -1841,16 +1604,23 @@ int main(int argc, char *argv[])
if (IsIdentifierToken(token, STR_LITERAL("enum"))) if (IsIdentifierToken(token, STR_LITERAL("enum")))
{ {
ParseCPPEnum(&tokeniser); if (ParseCPPEnum(&tokeniser, &parse_result.parsed_enum))
parse_result.type = ParsedResultType::Enum;
} }
else if (IsIdentifierToken(token, STR_LITERAL("struct")) || IsIdentifierToken(token, STR_LITERAL("class"))) else if (IsIdentifierToken(token, STR_LITERAL("struct")) || IsIdentifierToken(token, STR_LITERAL("class")))
{ {
ParseCPPStruct(&tokeniser); if (ParseCPPStruct(&tokeniser, &parse_result.parsed_struct))
parse_result.type = ParsedResultType::Struct;
} }
} }
else else
{ {
ParseCPPInspectPrototype(&tokeniser); if (ParseCPPInspectPrototype(&tokeniser, &parse_result.parsed_func_prototype))
{
parse_result.type = ParsedResultType::FunctionPrototype;
max_func_return_type_decl_len = INSPECT_MAX(max_func_return_type_decl_len, parse_result.parsed_func_prototype.return_type.len);
max_func_name_decl_len = INSPECT_MAX(max_func_name_decl_len, parse_result.parsed_func_prototype.name.len);
}
} }
} }
else else
@ -1858,10 +1628,336 @@ int main(int argc, char *argv[])
token = CPPTokeniser_NextToken(&tokeniser); token = CPPTokeniser_NextToken(&tokeniser);
} }
if (parse_result.type != ParsedResultType::Invalid)
parsing_results.push_back(parse_result);
if (token.type == CPPTokenType::EndOfStream) if (token.type == CPPTokenType::EndOfStream)
break; break;
} }
for (ParsedResult &parser : parsing_results)
{
switch(parser.type)
{
case ParsedResultType::Enum:
{
ParsedEnum const *parsed_enum = &parser.parsed_enum;
//
// NOTE: Write Stringified Enum Array
//
{
CPPTokeniser_SprintfToFile(&tokeniser, "char const *DqnInspect_%.*s_Strings[] = {", parsed_enum->name.len, parsed_enum->name.str);
tokeniser.indent_level++;
for (CPPDeclLinkedList<StringLiteral> const *link = parsed_enum->members; link; link = link->next)
{
StringLiteral const enum_value = link->value;
CPPTokeniser_SprintfToFileNoIndenting(&tokeniser, "\"%.*s\", ", enum_value.len, enum_value.str);
}
tokeniser.indent_level--;
CPPTokeniser_SprintfToFile(&tokeniser, "};\n\n");
}
//
// Write InspectEnumString Function
//
{
CPPTokeniser_SprintfToFile(&tokeniser, "char const *DqnInspect_EnumString(%.*s val)\n{\n", parsed_enum->name.len, parsed_enum->name.str);
tokeniser.indent_level++;
DEFER
{
CPPTokeniser_SprintfToFile(&tokeniser, "return nullptr;\n");
tokeniser.indent_level--;
CPPTokeniser_SprintfToFile(&tokeniser, "}\n\n");
};
struct SourceCode
{
StringLiteral decl;
StringLiteral enum_value;
};
LinkedList<SourceCode> src_code = {};
int longest_decl_len = 0;
{
LinkedList<SourceCode> *curr_src_code = nullptr;
char const *fmt = (parsed_enum->struct_or_class_decl) ? "if (val == %.*s::%.*s) " : "if (val == %.*s) ";
for (CPPDeclLinkedList<StringLiteral> *link = parsed_enum->members; link; link = link->next)
{
if (!curr_src_code) curr_src_code = &src_code;
else
{
curr_src_code->next = static_cast<LinkedList<SourceCode> *>( MemArena_Alloc(&global_main_arena, sizeof(*curr_src_code)));
curr_src_code = curr_src_code->next;
}
StringLiteral enum_value = link->value;
int required_len = 0;
if (parsed_enum->struct_or_class_decl) required_len = snprintf(nullptr, 0, fmt, parsed_enum->name.len, parsed_enum->name.str, enum_value.len, enum_value.str) + 1;
else required_len = snprintf(nullptr, 0, fmt, enum_value.len, enum_value.str) + 1;
longest_decl_len = INSPECT_MAX(longest_decl_len, required_len);
curr_src_code->value.decl.str = MEM_ARENA_ALLOC_ARRAY(&global_main_arena, char, required_len);
curr_src_code->value.decl.len = required_len;
curr_src_code->value.enum_value = enum_value;
if (parsed_enum->struct_or_class_decl) snprintf(curr_src_code->value.decl.str, curr_src_code->value.decl.len, fmt, parsed_enum->name.len, parsed_enum->name.str, enum_value.len, enum_value.str);
else snprintf(curr_src_code->value.decl.str, curr_src_code->value.decl.len, fmt, enum_value.len, enum_value.str);
}
curr_src_code->next = nullptr;
}
int enum_index = 0;
for (LinkedList<SourceCode> *src_code_ptr = &src_code;
src_code_ptr;
src_code_ptr = src_code_ptr->next, ++enum_index)
{
StringLiteral enum_value = src_code_ptr->value.enum_value;
int padding = longest_decl_len - src_code_ptr->value.decl.len;
CPPTokeniser_SprintfToFile(&tokeniser, "%.*s%*s", src_code_ptr->value.decl.len, src_code_ptr->value.decl.str, padding, "");
CPPTokeniser_SprintfToFileNoIndenting(&tokeniser,
"return DqnInspect_%.*s_Strings[%d]; // \"%.*s\"\n",
parsed_enum->name.len, parsed_enum->name.str,
enum_index,
enum_value.len, enum_value.str);
}
}
//
// Write User Annotated Metadata Getter Functions
//
{
FixedArray<MetadataEntry, 32> metadata_entries = {};
for (CPPDeclLinkedList<StringLiteral> *link = parsed_enum->members;
link;
link = link->next)
{
for (CPPInspectMetadataEntry const &inspect_entry : link->metadata_array)
{
MetadataEntry *metadata_entry_to_append_to = nullptr;
for (MetadataEntry &check_metadata_entry : metadata_entries)
{
if (StrCmp(check_metadata_entry.key, inspect_entry.key))
{
metadata_entry_to_append_to = &check_metadata_entry;
break;
}
}
if (!metadata_entry_to_append_to)
{
metadata_entry_to_append_to = FixedArray_Make(&metadata_entries, 1);
metadata_entry_to_append_to->key = inspect_entry.key;
}
CPPDeclToMetaValue decl_to_val = {};
decl_to_val.cpp_decl = StringLiteral(link->value.str, link->value.len);
decl_to_val.value = inspect_entry.value;
FixedArray_Add(&metadata_entry_to_append_to->cpp_decl_to_val, decl_to_val);
}
}
for (MetadataEntry const &metadata : metadata_entries)
{
CPPTokeniser_SprintfToFile(&tokeniser,
"char const *DqnInspect_%.*sMetadata(%.*s val)\n{\n",
metadata.key.len, metadata.key.str,
parsed_enum->name.len, parsed_enum->name.str);
tokeniser.indent_level++;
DEFER
{
CPPTokeniser_SprintfToFile(&tokeniser, "return nullptr;\n");
tokeniser.indent_level--;
CPPTokeniser_SprintfToFile(&tokeniser, "}\n\n");
};
for (CPPDeclToMetaValue const &decl_to_val : metadata.cpp_decl_to_val)
{
StringLiteral const *cpp_decl = &decl_to_val.cpp_decl;
StringLiteral const *value = &decl_to_val.value;
if (parsed_enum->struct_or_class_decl)
{
CPPTokeniser_SprintfToFile(&tokeniser,
"if (val == %.*s::%.*s) ",
parsed_enum->name.len, parsed_enum->name.str,
cpp_decl->len, cpp_decl->str);
}
else
{
CPPTokeniser_SprintfToFile(&tokeniser,
"if (val == %.*s) ",
cpp_decl->len, cpp_decl->str);
}
CPPTokeniser_SprintfToFileNoIndenting(&tokeniser, "return \"%.*s\";\n", value->len, value->str);
}
}
}
}
break;
case ParsedResultType::Struct:
{
ParsedStruct const *parsed_struct = &parser.parsed_struct;
//
// NOTE: Write DqnInspect_StructMemberMetadata Definition
//
for (CPPDeclLinkedList<CPPVariableDecl> const *member = parsed_struct->members; member; member = member->next)
{
CPPVariableDecl const *decl = &member->value;
if (member->metadata_array.len <= 0)
continue;
CPPTokeniser_SprintfToFile(
&tokeniser,
"DqnInspect_StructMemberMetadata const DqnInspect_%.*s_%.*s_StructMemberMetadata[] =\n{\n",
parsed_struct->name.len,
parsed_struct->name.str,
decl->name.len,
decl->name.str);
tokeniser.indent_level++;
for (CPPInspectMetadataEntry const &entry : member->metadata_array)
{
CPPTokeniser_SprintfToFile(&tokeniser, "{\n");
tokeniser.indent_level++;
CPPTokeniser_SprintfToFile(&tokeniser, "DqnInspect_StructMemberMetadataType::String,\n");
// metadata->key
CPPTokeniser_SprintfToFile(&tokeniser, "STR_AND_LEN(\"%.*s\"), ", entry.key.len, entry.key.str);
// metadata->value
CPPTokeniser_SprintfToFileNoIndenting(&tokeniser, "STR_AND_LEN(\"%.*s\"),\n", entry.value.len, entry.value.str);
tokeniser.indent_level--;
CPPTokeniser_SprintfToFile(&tokeniser, "},\n");
}
tokeniser.indent_level--;
CPPTokeniser_SprintfToFile(&tokeniser, "};\n\n");
}
//
// Write DqnInspect_StructMembers Definition
//
{
CPPTokeniser_SprintfToFile(&tokeniser, "DqnInspect_StructMember const DqnInspect_%.*s_StructMembers[] =\n{\n", parsed_struct->name.len, parsed_struct->name.str);
tokeniser.indent_level++;
for (CPPDeclLinkedList<CPPVariableDecl> const *member = parsed_struct->members; member; member = member->next)
{
CPPVariableDecl const *decl = &member->value;
CPPTokeniser_SprintfToFile(&tokeniser, "{\n");
tokeniser.indent_level++;
CPPTokeniser_SprintfToFile(&tokeniser, "STR_AND_LEN(\"%.*s\"), ", decl->type.len, decl->type.str);
CPPTokeniser_SprintfToFileNoIndenting(&tokeniser, "STR_AND_LEN(\"%.*s\"),\n", decl->name.len, decl->name.str);
if (decl->template_expr.len <= 0)
CPPTokeniser_SprintfToFile(&tokeniser, "nullptr, 0, // template_expr and template_expr_len\n");
else
CPPTokeniser_SprintfToFile(&tokeniser, "STR_AND_LEN(\"%.*s\"), // template_expr\n", decl->template_expr.len, decl->template_expr.str);
if (member->metadata_array.len <= 0) CPPTokeniser_SprintfToFile(&tokeniser, "nullptr, 0, // metadata and metadata_len\n");
else CPPTokeniser_SprintfToFile(&tokeniser, "DqnInspect_%.*s_%.*s_StructMemberMetadata, %d,\n", parsed_struct->name.len, parsed_struct->name.str, decl->name.len, decl->name.str, member->metadata_array.len);
CPPTokeniser_SprintfToFile(&tokeniser, "%d // array_dimensions\n", decl->array_dimensions);
tokeniser.indent_level--;
CPPTokeniser_SprintfToFile(&tokeniser, "},\n");
}
tokeniser.indent_level--;
CPPTokeniser_SprintfToFile(&tokeniser, "};\n\n");
}
//
// Write DqnInspect_Struct Definition
//
{
CPPTokeniser_SprintfToFile(&tokeniser, "DqnInspect_Struct const DqnInspect_%.*s_Struct =\n{\n", parsed_struct->name.len, parsed_struct->name.str);
tokeniser.indent_level++;
CPPTokeniser_SprintfToFile(&tokeniser, "STR_AND_LEN(\"%.*s\"),\n", parsed_struct->name.len, parsed_struct->name.str);
CPPTokeniser_SprintfToFile(&tokeniser, "DqnInspect_%.*s_StructMembers, // members\n", parsed_struct->name.len, parsed_struct->name.str);
CPPTokeniser_SprintfToFile(&tokeniser, "ARRAY_COUNT(DqnInspect_%.*s_StructMembers) // members_len\n", parsed_struct->name.len, parsed_struct->name.str);
tokeniser.indent_level--;
CPPTokeniser_SprintfToFile(&tokeniser, "};\n\n");
assert(tokeniser.indent_level == 0);
}
//
// Write DqnInspect_Struct getter
//
{
CPPTokeniser_SprintfToFile(&tokeniser, "DqnInspect_Struct const *DqnInspect_GetStruct(%.*s const *val)\n", parsed_struct->name.len, parsed_struct->name.str);
CPPTokeniser_SprintfToFile(&tokeniser, "{\n");
tokeniser.indent_level++;
CPPTokeniser_SprintfToFile(&tokeniser, "(void)val;\n");
CPPTokeniser_SprintfToFile(&tokeniser, "DqnInspect_Struct const *result = &DqnInspect_%.*s_Struct;\n", parsed_struct->name.len, parsed_struct->name.str);
CPPTokeniser_SprintfToFile(&tokeniser, "return result;\n");
tokeniser.indent_level--;
CPPTokeniser_SprintfToFile(&tokeniser, "}\n\n");
}
}
break;
case ParsedResultType::FunctionPrototype:
{
ParsedFunctionPrototype *parsed_func = &parser.parsed_func_prototype;
{
StringLiteral return_type = parsed_func->return_type;
StringLiteral func_name = parsed_func->name;
int spaces_remaining = max_func_return_type_decl_len - return_type.len;
CPPTokeniser_SprintfToFile(&tokeniser, "%.*s ", return_type.len, return_type.str);
for (int i = 0; i < spaces_remaining; ++i) CPPTokeniser_SprintfToFileNoIndenting(&tokeniser, " ");
spaces_remaining = max_func_name_decl_len - func_name.len;
CPPTokeniser_SprintfToFile(&tokeniser, "%.*s", func_name.len, func_name.str);
for (int i = 0; i < spaces_remaining; ++i) CPPTokeniser_SprintfToFileNoIndenting(&tokeniser, " ");
CPPTokeniser_SprintfToFile(&tokeniser, "(");
}
for (CPPDeclLinkedList<CPPVariableDecl> *param_link = parsed_func->members; param_link; param_link = param_link->next)
{
// TODO(doyle): HACK. We should parse ptrs into the CPPVariableDecl, fixed size arrays into the name and const-ness into the type
CPPVariableDecl *decl = &param_link->value;
StringLiteral *type = &decl->type;
char *type_end = (decl->template_expr.len > 0)
? decl->template_expr.str + decl->template_expr.len + 1 // +1 for the ending ">" on the template
: type->str + type->len;
StringLiteral *name = &decl->name;
StringLiteral hack_decl_name = {};
if (name->len > 0)
{
char *name_start = type_end + 1;
char *name_end = name->str + name->len;
hack_decl_name = StringLiteral(name_start, static_cast<int>(name_end - name_start));
}
CPPTokeniser_SprintfToFileNoIndenting(&tokeniser, "%.*s", type->len, type->str);
if (decl->template_expr.len > 0)
CPPTokeniser_SprintfToFileNoIndenting(&tokeniser, "<%.*s>", decl->template_expr.len, decl->template_expr.str);
if (hack_decl_name.len > 0)
CPPTokeniser_SprintfToFileNoIndenting(&tokeniser, " %.*s", hack_decl_name.len, hack_decl_name.str);
if (decl->default_value.len > 0)
CPPTokeniser_SprintfToFileNoIndenting(&tokeniser, " = %.*s", decl->default_value.len, decl->default_value.str);
if (param_link->next)
CPPTokeniser_SprintfToFileNoIndenting(&tokeniser, ", ", parsed_func->return_type.len, parsed_func->return_type.str, parsed_func->name.len, parsed_func->name.str);
}
CPPTokeniser_SprintfToFileNoIndenting(&tokeniser, ");\n");
}
break;
}
}
fprintf(output_file, fprintf(output_file,
"\n#undef ARRAY_COUNT\n" "\n#undef ARRAY_COUNT\n"
"#undef CHAR_COUNT\n" "#undef CHAR_COUNT\n"