Add support for funciton default param initialiser

This commit is contained in:
Doyle 2019-03-23 16:08:12 +11:00
parent 2f750ecc52
commit b61ad4a51a
3 changed files with 187 additions and 165 deletions

View File

@ -265,6 +265,10 @@ struct DqnInspect_Struct
int members_len; int members_len;
}; };
// NOTE(doyle): For compiler testing
// #include "../Data/DqnInspect_TestData.h"
// #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
@ -1288,9 +1292,41 @@ void ParseCPPStruct(CPPTokeniser *tokeniser)
void SkipFunctionParam(CPPTokeniser *tokeniser) void SkipFunctionParam(CPPTokeniser *tokeniser)
{ {
CPPToken token = CPPTokeniser_PeekToken(tokeniser); CPPToken token = CPPTokeniser_PeekToken(tokeniser);
while (token.type != CPPTokenType::EndOfStream && token.type != CPPTokenType::Comma && while (token.type != CPPTokenType::EndOfStream)
token.type != CPPTokenType::CloseParen)
{ {
if (token.type == CPPTokenType::OpenParen)
{
for (int level = 1; level != 0;)
{
CPPTokeniser_NextToken(tokeniser);
token = CPPTokeniser_PeekToken(tokeniser);
if (token.type == CPPTokenType::OpenParen) level++;
if (token.type == CPPTokenType::CloseParen) level--;
}
CPPTokeniser_NextToken(tokeniser);
token = CPPTokeniser_PeekToken(tokeniser);
}
if (token.type == CPPTokenType::LeftBrace)
{
for (int level = 1; level != 0;)
{
CPPTokeniser_NextToken(tokeniser);
token = CPPTokeniser_PeekToken(tokeniser);
if (token.type == CPPTokenType::LeftBrace) level++;
if (token.type == CPPTokenType::RightBrace) level--;
}
CPPTokeniser_NextToken(tokeniser);
token = CPPTokeniser_PeekToken(tokeniser);
}
if (token.type == CPPTokenType::CloseParen)
break;
if (token.type == CPPTokenType::Comma)
break;
CPPTokeniser_NextToken(tokeniser); CPPTokeniser_NextToken(tokeniser);
token = CPPTokeniser_PeekToken(tokeniser); token = CPPTokeniser_PeekToken(tokeniser);
} }
@ -1312,9 +1348,8 @@ void ParseCPPInspectPrototype(CPPTokeniser *tokeniser)
MemArenaScopedRegion mem_region = MemArena_MakeScopedRegion(&global_main_arena); MemArenaScopedRegion mem_region = MemArena_MakeScopedRegion(&global_main_arena);
{ {
LinkedList<FunctionDefaultParam> *link_iterator = nullptr; LinkedList<FunctionDefaultParam> *link_iterator = nullptr;
token = CPPTokeniser_PeekToken(tokeniser); if (!CPPTokeniser_AcceptTokenIfType(tokeniser, CPPTokenType::OpenParen, &token))
if (!ExpectToken(token, CPPTokenType::OpenParen)) return; return;
token = CPPTokeniser_NextToken(tokeniser);
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;
@ -1337,20 +1372,18 @@ void ParseCPPInspectPrototype(CPPTokeniser *tokeniser)
continue; continue;
} }
token = CPPTokeniser_NextToken(tokeniser); token = CPPTokeniser_PeekToken(tokeniser);
char *default_param_start = token.str; char *default_value_start = token.str;
// NOTE(doyle): Include the quotes in the param value if (token.type == CPPTokenType::String) // NOTE(doyle): Include the quotes in the param value
CPPToken prev_token = CPPTokeniser_PrevToken(tokeniser); default_value_start--;
if (prev_token.type == CPPTokenType::String)
default_param_start--;
SkipFunctionParam(tokeniser); SkipFunctionParam(tokeniser);
CPPToken peek_token = CPPTokeniser_PeekToken(tokeniser); CPPToken peek_token = CPPTokeniser_PeekToken(tokeniser);
if (peek_token.type != CPPTokenType::Comma && peek_token.type != CPPTokenType::CloseParen) if (peek_token.type != CPPTokenType::Comma && peek_token.type != CPPTokenType::CloseParen)
continue; continue;
char *default_param_end = peek_token.str; char *default_value_end = peek_token.str;
auto *link = MEM_ARENA_ALLOC_STRUCT(&global_main_arena, LinkedList<FunctionDefaultParam>); auto *link = MEM_ARENA_ALLOC_STRUCT(&global_main_arena, LinkedList<FunctionDefaultParam>);
*link = {}; *link = {};
@ -1359,7 +1392,7 @@ void ParseCPPInspectPrototype(CPPTokeniser *tokeniser)
link_iterator = link; link_iterator = link;
link->value.name = default_param_name; link->value.name = default_param_name;
link->value.value = StringLiteral(default_param_start, static_cast<int>(default_param_end - default_param_start)); link->value.value = StringLiteral(default_value_start, static_cast<int>(default_value_end - default_value_start));
} }
} }
@ -1483,121 +1516,127 @@ enum struct InspectMode
char *EnumOrStructOrFunctionLexer(CPPTokeniser *tokeniser, char *ptr, b32 lexing_function) char *EnumOrStructOrFunctionLexer(CPPTokeniser *tokeniser, char *ptr, b32 lexing_function)
{ {
int indent_level = 0; // NOTE(doyle): If we're lexing a function we're doing DQN_INSPECT_GENERATE_PROTOTYPE()
bool started_lexing_brace_scope = false; // Where we want to lex the macro and then the function following it, so 2 iterations
bool started_lexing_function = false; int iterations = lexing_function ? 2 : 1;
int open_paren_level = 0;
int close_paren_level = 0; for (int i = 0; i < iterations; ++i)
for (; ptr;)
{ {
while (CharIsWhitespace(ptr[0])) ptr++; int indent_level = 0;
if (!ptr[0]) break; bool started_lexing_brace_scope = false;
bool started_lexing_function = false;
CPPToken *token = CPPTokeniser_MakeToken(tokeniser); int paren_level = 0;
token->str = ptr++; for (; ptr;)
token->len = 1;
switch(token->str[0])
{ {
case '{': { token->type = CPPTokenType::LeftBrace; started_lexing_brace_scope = true; indent_level++; } break; while (CharIsWhitespace(ptr[0])) ptr++;
case '}': { token->type = CPPTokenType::RightBrace; indent_level--; } break; if (!ptr[0]) break;
case '[': { token->type = CPPTokenType::LeftSqBracket; } break;
case ']': { token->type = CPPTokenType::RightSqBracket; } break; CPPToken *token = CPPTokeniser_MakeToken(tokeniser);
case '(': { token->type = CPPTokenType::OpenParen; started_lexing_function = true; open_paren_level++; } break; token->str = ptr++;
case ')': { token->type = CPPTokenType::CloseParen; close_paren_level++; } break; token->len = 1;
case ',': { token->type = CPPTokenType::Comma; } break; switch(token->str[0])
case ';': { token->type = CPPTokenType::SemiColon; } break;
case '=': { token->type = CPPTokenType::Equals; } break;
case '<': { token->type = CPPTokenType::LessThan; } break;
case '>': { token->type = CPPTokenType::GreaterThan; } break;
case ':': { token->type = CPPTokenType::Colon; } break;
case '*': { token->type = CPPTokenType::Asterisks; } break;
case '/':
{ {
token->type = CPPTokenType::FwdSlash; case '{': { token->type = CPPTokenType::LeftBrace; started_lexing_brace_scope = true; indent_level++; } break;
if (ptr[0] == '/' || ptr[0] == '*') case '}': { token->type = CPPTokenType::RightBrace; indent_level--; } break;
case '[': { token->type = CPPTokenType::LeftSqBracket; } break;
case ']': { token->type = CPPTokenType::RightSqBracket; } break;
case '(': { token->type = CPPTokenType::OpenParen; started_lexing_function = true; paren_level++; } break;
case ')': { token->type = CPPTokenType::CloseParen; paren_level--; } break;
case ',': { token->type = CPPTokenType::Comma; } break;
case ';': { token->type = CPPTokenType::SemiColon; } break;
case '=': { token->type = CPPTokenType::Equals; } break;
case '<': { token->type = CPPTokenType::LessThan; } break;
case '>': { token->type = CPPTokenType::GreaterThan; } break;
case ':': { token->type = CPPTokenType::Colon; } break;
case '*': { token->type = CPPTokenType::Asterisks; } break;
case '/':
{ {
token->type = CPPTokenType::Comment; token->type = CPPTokenType::FwdSlash;
if (ptr[0] == '/') if (ptr[0] == '/' || ptr[0] == '*')
{ {
while (ptr[0] == ' ' || ptr[0] == '\t') ptr++; token->type = CPPTokenType::Comment;
token->str = ptr; if (ptr[0] == '/')
while (ptr[0] != '\n') ptr++;
}
else
{
for (;;)
{ {
while (ptr[0] != '*') ptr++; while (ptr[0] == ' ' || ptr[0] == '\t') ptr++;
ptr++; token->str = ptr;
if (ptr[0] == '\\') break; while (ptr[0] != '\n') ptr++;
token->len = static_cast<int>(ptr - token->str); }
else
{
for (;;)
{
while (ptr[0] != '*') ptr++;
ptr++;
if (ptr[0] == '\\') break;
token->len = static_cast<int>(ptr - token->str);
}
} }
}
token->len = static_cast<int>(ptr - token->str);
}
}
break;
default:
{
ptr--;
if (ptr[0] == '"')
{
token->type = CPPTokenType::String;
for (token->str = ++ptr;;)
{
while (ptr[0] != '"') ptr++;
token->len = static_cast<int>(ptr - token->str); token->len = static_cast<int>(ptr - token->str);
if (ptr[-1] != '\\')
{
ptr++;
break;
}
} }
} }
else break;
{
if (CharIsDigit(ptr[0]))
{
while (CharIsDigit(ptr[0]) || ptr[0] == 'x' || ptr[0] == 'b' || ptr[0] == 'e' || ptr[0] == '.' || ptr[0] == 'f')
ptr++;
token->type = CPPTokenType::Number; default:
{
ptr--;
if (ptr[0] == '"')
{
token->type = CPPTokenType::String;
for (token->str = ++ptr;;)
{
while (ptr[0] != '"') ptr++;
token->len = static_cast<int>(ptr - token->str);
if (ptr[-1] != '\\')
{
ptr++;
break;
}
}
} }
else else
{ {
token->type = CPPTokenType::Identifier; if (CharIsDigit(ptr[0]))
if (CharIsAlpha(ptr[0]) || ptr[0] == '_')
{ {
ptr++; while (CharIsDigit(ptr[0]) || ptr[0] == 'x' || ptr[0] == 'b' || ptr[0] == 'e' || ptr[0] == '.' || ptr[0] == 'f')
while (CharIsAlphaNum(ptr[0]) || ptr[0] == '_') ptr++; ptr++;
token->type = CPPTokenType::Number;
} }
else
{
token->type = CPPTokenType::Identifier;
if (CharIsAlpha(ptr[0]) || ptr[0] == '_')
{
ptr++;
while (CharIsAlphaNum(ptr[0]) || ptr[0] == '_') ptr++;
}
}
token->len = static_cast<int>(ptr - token->str);
} }
token->len = static_cast<int>(ptr - token->str);
} }
break;
} }
break;
}
if (token->len == 0) if (token->len == 0)
{
*token = {};
tokeniser->tokens_len--;
}
else
{
if (lexing_function)
{ {
if (started_lexing_function && open_paren_level == close_paren_level && open_paren_level == 2) *token = {};
return ptr; tokeniser->tokens_len--;
} }
else else
{ {
if (started_lexing_brace_scope && indent_level == 0) if (lexing_function)
return ptr; {
if (started_lexing_function && paren_level == 0)
break;
}
else
{
if (started_lexing_brace_scope && indent_level == 0)
break;
}
} }
} }
} }
@ -1683,45 +1722,25 @@ int main(int argc, char *argv[])
file_include_contents_hash_define_len = extracted_file_name_len; file_include_contents_hash_define_len = extracted_file_name_len;
} }
if (mode == InspectMode::Code) fprintf(output_file,
{ "//\n"
fprintf(output_file, "// %s\n"
"//\n" "//\n"
"// %s\n" "\n"
"//\n" "#ifndef DQN_INSPECT_%.*s\n"
"\n" "#define DQN_INSPECT_%.*s\n"
"#ifndef DQN_INSPECT_%.*s\n" "\n"
"#define DQN_INSPECT_%.*s\n" " // NOTE: These macros are undefined at the end of the file so to not pollute namespace\n"
"\n" "#define ARRAY_COUNT(array) sizeof(array)/sizeof((array)[0])\n"
" // NOTE: These macros are undefined at the end of the file so to not pollute namespace\n" "#define CHAR_COUNT(str) (ARRAY_COUNT(str) - 1)\n"
"#define ARRAY_COUNT(array) sizeof(array)/sizeof((array)[0])\n" "#define STR_AND_LEN(str) str, CHAR_COUNT(str)\n"
"#define CHAR_COUNT(str) (ARRAY_COUNT(str) - 1)\n" "\n",
"#define STR_AND_LEN(str) str, CHAR_COUNT(str)\n" file_name,
"\n", file_include_contents_hash_define_len,
file_name, file_include_contents_hash_define,
file_include_contents_hash_define_len, file_include_contents_hash_define_len,
file_include_contents_hash_define, file_include_contents_hash_define
file_include_contents_hash_define_len, );
file_include_contents_hash_define
);
}
else
{
fprintf(output_file,
"//\n"
"// %s\n"
"//\n"
"\n"
"#ifndef DQN_INSPECT_%.*s\n"
"#define DQN_INSPECT_%.*s\n"
"\n",
file_name,
file_include_contents_hash_define_len,
file_include_contents_hash_define,
file_include_contents_hash_define_len,
file_include_contents_hash_define
);
}
CPPTokeniser tokeniser = {}; CPPTokeniser tokeniser = {};
tokeniser.spaces_per_indent = 4; tokeniser.spaces_per_indent = 4;
@ -1809,23 +1828,13 @@ int main(int argc, char *argv[])
break; break;
} }
if (mode == InspectMode::Code) fprintf(output_file,
{ "\n#undef ARRAY_COUNT\n"
fprintf(output_file, "#undef CHAR_COUNT\n"
"\n#undef ARRAY_COUNT\n" "#undef STR_AND_LEN\n"
"#undef CHAR_COUNT\n" "#endif // DQN_INSPECT_%.*s\n\n",
"#undef STR_AND_LEN\n" file_include_contents_hash_define_len,
"#endif // DQN_INSPECT_%.*s\n\n", file_include_contents_hash_define);
file_include_contents_hash_define_len,
file_include_contents_hash_define);
}
else
{
fprintf(output_file,
"\n#endif // DQN_INSPECT_%.*s\n\n",
file_include_contents_hash_define_len,
file_include_contents_hash_define);
}
} }
fclose(output_file); fclose(output_file);

View File

@ -4,12 +4,14 @@ DQN_INSPECT enum struct EnumWithMetadata
Count, Count,
}; };
struct V3 { float test; }; struct V3 { V3(float a, float b) { (void)a; (void)b; } float test; };
struct V4 { float test; }; struct V4 { float test; };
template <typename T, int Size> template <typename T, int Size>
struct Array { T data[Size]; }; struct Array { T data[Size]; };
enum struct OpenGLShader { Vertex, Count, };
DQN_INSPECT struct SampleStruct DQN_INSPECT struct SampleStruct
{ {
// #if 0 // #if 0
@ -34,10 +36,13 @@ DQN_INSPECT struct SampleStruct
}; };
DQN_INSPECT_GENERATE_PROTOTYPE(b = {}, c = nullptr, e = false, f = 1, g = "Hello world") DQN_INSPECT_GENERATE_PROTOTYPE(b = {}, c = nullptr, e = false, f = 1, g = "Hello world")
void Function1(int a, float b, char const *c, bool e, int f, char *g) { } void Function1(int a, float b, char const *c, bool e, int f, char *g)
{
(void)a; (void)b; (void)c; (void)e; (void)f; (void)g;
}
DQN_INSPECT_GENERATE_PROTOTYPE(foo = V3(10, 20), bar = {120, 150})
void *Function2(V3 foo, V3 bar) { (void)foo; (void)bar; return nullptr; }
DQN_INSPECT_GENERATE_PROTOTYPE() DQN_INSPECT_GENERATE_PROTOTYPE()
void *Function2() { } Array<int const *, 3> const *const Function3(Array<int, 32> const *foobar) { (void)foobar; return {}; }
DQN_INSPECT_GENERATE_PROTOTYPE()
Array<int const *, 3> const *const Function3(Array<int, 32> const *foobar) { }

View File

@ -7,6 +7,11 @@
#ifndef DQN_INSPECT_DQNINSPECT_TESTDATA_H #ifndef DQN_INSPECT_DQNINSPECT_TESTDATA_H
#define DQN_INSPECT_DQNINSPECT_TESTDATA_H #define DQN_INSPECT_DQNINSPECT_TESTDATA_H
// NOTE: These macros are undefined at the end of the file so to not pollute namespace
#define ARRAY_COUNT(array) sizeof(array)/sizeof((array)[0])
#define CHAR_COUNT(str) (ARRAY_COUNT(str) - 1)
#define STR_AND_LEN(str) str, CHAR_COUNT(str)
char const *DqnInspect_EnumWithMetadata_Strings[] = {"Rect", "Count", }; char const *DqnInspect_EnumWithMetadata_Strings[] = {"Rect", "Count", };
char const *DqnInspect_EnumString(EnumWithMetadata val) char const *DqnInspect_EnumString(EnumWithMetadata val)
@ -225,8 +230,11 @@ DqnInspect_Struct const *DqnInspect_GetStruct(SampleStruct const *val)
} }
void Function1(int a, float b = {}, char const *c = nullptr, bool e = false, int f = 1, char *g = "Hello world"); void Function1(int a, float b = {}, char const *c = nullptr, bool e = false, int f = 1, char *g = "Hello world");
void *Function2(); void *Function2(V3 foo = V3(10, 20), V3 bar = {120, 150});
Array<int const *, 3> const *const Function3(Array<int, 32> const *foobar); Array<int const *, 3> const *const Function3(Array<int, 32> const *foobar);
#undef ARRAY_COUNT
#undef CHAR_COUNT
#undef STR_AND_LEN
#endif // DQN_INSPECT_DQNINSPECT_TESTDATA_H #endif // DQN_INSPECT_DQNINSPECT_TESTDATA_H