Compare commits

...

6 Commits

Author SHA1 Message Date
Ed_
f90c0a59b6 inital implemention of UE library variant generator completed 2024-10-25 05:01:37 -04:00
Ed_
33f992ef56 Updated generated ast_inlines.hpp so that operator defs have the inline explicit
* Added support for parsing/serializing specifiers for OpCast roughtly.. Doesn't have constraints on what specifiers beyond whats expected in global nspace scope..
* Minor adjustments to hashtable to avoid UE compile errors
* Make sure scanner.cpp is being made by bootstrap
2024-10-25 04:08:20 -04:00
Ed_
0542204b35 progress on unreal variant generator 2024-10-25 03:00:07 -04:00
Ed_
e5616c5879 generated code update + reverting some fixes for now... 2024-10-25 02:59:56 -04:00
Ed_
40a256f6c3 initial setup for generating a library compatible for usage as an Unreal thirdyparty module. 2024-10-25 01:04:48 -04:00
Ed_
b8e1aa6eb7 WIP : Fixes and other changes
* Number literals weren't getting properly lexed
* Fixes for compiler errors with Unreal Engine configuration.
* Support for "post-name" macros in parameters
* Support for variables initializing directly using constructor syntax.
* Explicitly added inline keyword to header inlines for compiling compile library in multiple translation units.
2024-10-25 01:04:17 -04:00
39 changed files with 1353 additions and 552 deletions

9
.vscode/launch.json vendored
View File

@ -41,6 +41,15 @@
"cwd": "${workspaceFolder}/singleheader/", "cwd": "${workspaceFolder}/singleheader/",
"visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" "visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis"
}, },
{
"type": "cppvsdbg",
"request": "launch",
"name": "Debug unreal vsdbg",
"program": "${workspaceFolder}/unreal_engine/build/unreal.exe",
"args": [],
"cwd": "${workspaceFolder}/unreal_engine/",
"visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis"
},
{ {
"type": "cppvsdbg", "type": "cppvsdbg",
"request": "launch", "request": "launch",

View File

@ -48,7 +48,7 @@ void Builder::print_fmt( char const* fmt, ... )
void Builder::write() void Builder::write()
{ {
bool result = file_write( & File, Buffer, Buffer.length() ); b32 result = file_write( & File, Buffer, Buffer.length() );
if ( result == false ) if ( result == false )
log_failure("gen::File::write - Failed to write to file: %s\n", file_name( & File ) ); log_failure("gen::File::write - Failed to write to file: %s\n", file_name( & File ) );

View File

@ -1,3 +1,5 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES #ifdef GEN_INTELLISENSE_DIRECTIVES
# include "scanner.hpp" # include "scanner.hpp"
#endif #endif

View File

@ -6,6 +6,7 @@
// This is a simple file reader that reads the entire file into memory. // This is a simple file reader that reads the entire file into memory.
// It has an extra option to skip the first few lines for undesired includes. // It has an extra option to skip the first few lines for undesired includes.
// This is done so that includes can be kept in dependency and component files so that intellisense works. // This is done so that includes can be kept in dependency and component files so that intellisense works.
inline
Code scan_file( char const* path ) Code scan_file( char const* path )
{ {
FileInfo file; FileInfo file;

View File

@ -283,6 +283,7 @@ int gen_main()
} }
// gen_scanner.cpp // gen_scanner.cpp
if (1)
{ {
Code parsing = scan_file( "dependencies/parsing.cpp" ); Code parsing = scan_file( "dependencies/parsing.cpp" );
Code scanner = scan_file( "auxillary/scanner.cpp" ); Code scanner = scan_file( "auxillary/scanner.cpp" );
@ -293,7 +294,7 @@ int gen_main()
src.print( def_include( txt("gen.scanner.hpp") ) ); src.print( def_include( txt("gen.scanner.hpp") ) );
src.print_fmt( "\nGEN_NS_BEGIN\n" ); src.print_fmt( "\nGEN_NS_BEGIN\n" );
src.print( parsing ); src.print( parsing );
src.print( scanner ); // src.print( scanner );
src.print_fmt( "GEN_NS_END\n" ); src.print_fmt( "GEN_NS_END\n" );
src.write(); src.write();
} }

View File

@ -339,13 +339,14 @@ struct AST
}; };
union { union {
AST* ArrExpr; // Typename AST* ArrExpr; // Typename
AST* Body; // Class, Constructr, Destructor, Enum, Friend, Function, Namespace, Struct, Union AST* Body; // Class, Constructor, Destructor, Enum, Friend, Function, Namespace, Struct, Union
AST* Declaration; // Friend, Template AST* Declaration; // Friend, Template
AST* Value; // Parameter, Variable AST* Value; // Parameter, Variable
}; };
union { union {
AST* NextVar; // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = NextVar->Value ) AST* NextVar; // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = NextVar->Value )
AST* SuffixSpecs; // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed ) AST* SuffixSpecs; // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed )
AST* PostNameMacro; // Only used with parameters for specifically UE_REQUIRES (Thanks Unreal)
}; };
}; };
StringCached Content; // Attributes, Comment, Execution, Include StringCached Content; // Attributes, Comment, Execution, Include
@ -375,6 +376,7 @@ struct AST
OperatorT Op; OperatorT Op;
AccessSpec ParentAccess; AccessSpec ParentAccess;
s32 NumEntries; s32 NumEntries;
s32 VarConstructorInit; // Used by variables to know that initialization is using a constructor expression instead of an assignment expression.
}; };
}; };
@ -407,6 +409,7 @@ struct AST_POD
union { union {
AST* NextVar; // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = NextVar->Value ) AST* NextVar; // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = NextVar->Value )
AST* SuffixSpecs; // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed ) AST* SuffixSpecs; // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed )
AST* PostNameMacro; // Only used with parameters for specifically UE_REQUIRES (Thanks Unreal)
}; };
}; };
StringCached Content; // Attributes, Comment, Execution, Include StringCached Content; // Attributes, Comment, Execution, Include
@ -436,6 +439,7 @@ struct AST_POD
OperatorT Op; OperatorT Op;
AccessSpec ParentAccess; AccessSpec ParentAccess;
s32 NumEntries; s32 NumEntries;
s32 VarConstructorInit; // Used by variables to know that initialization is using a constructor expression instead of an assignment expression.
}; };
}; };

View File

@ -644,7 +644,8 @@ struct AST_Param
CodeType ValueType; CodeType ValueType;
Code Macro; Code Macro;
Code Value; Code Value;
char _PAD_PROPERTIES_3_[ sizeof(AST*) ]; Code PostNameMacro; // Thanks Unreal
// char _PAD_PROPERTIES_3_[sizeof( AST* )];
}; };
}; };
CodeParam Last; CodeParam Last;
@ -1115,7 +1116,7 @@ struct AST_Var
StringCached Name; StringCached Name;
CodeT Type; CodeT Type;
ModuleFlag ModuleFlags; ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ]; s32 VarConstructorInit;
}; };
static_assert( sizeof(AST_Var) == sizeof(AST), "ERROR: AST_Var is not the same size as AST"); static_assert( sizeof(AST_Var) == sizeof(AST), "ERROR: AST_Var is not the same size as AST");

View File

@ -480,7 +480,7 @@ void CodeFn::to_string_def( String& result )
if ( ast->Attributes ) if ( ast->Attributes )
result.append_fmt( " %S ", ast->Attributes.to_string() ); result.append_fmt( " %S ", ast->Attributes.to_string() );
b32 prefix_specs = false; bool prefix_specs = false;
if ( ast->Specs ) if ( ast->Specs )
{ {
for ( SpecifierT spec : ast->Specs ) for ( SpecifierT spec : ast->Specs )
@ -764,7 +764,14 @@ void CodeOpCast::to_string_def( String& result )
{ {
if ( ast->Specs ) if ( ast->Specs )
{ {
// TODO : Add support for specifies before the operator keyword for ( SpecifierT spec : ast->Specs )
{
if ( ! ESpecifier::is_trailing( spec ) )
{
StrC spec_str = ESpecifier::to_str( spec );
result.append_fmt( "%*s ", spec_str.Len, spec_str.Ptr );
}
}
if ( ast->Name && ast->Name.length() ) if ( ast->Name && ast->Name.length() )
result.append_fmt( "%Soperator %S()", ast->Name, ast->ValueType.to_string() ); result.append_fmt( "%Soperator %S()", ast->Name, ast->ValueType.to_string() );
@ -794,7 +801,14 @@ void CodeOpCast::to_string_fwd( String& result )
{ {
if ( ast->Specs ) if ( ast->Specs )
{ {
// TODO : Add support for specifies before the operator keyword for ( SpecifierT spec : ast->Specs )
{
if ( ! ESpecifier::is_trailing( spec ) )
{
StrC spec_str = ESpecifier::to_str( spec );
result.append_fmt( "%*s ", spec_str.Len, spec_str.Ptr );
}
}
result.append_fmt( "operator %S()", ast->ValueType.to_string() ); result.append_fmt( "operator %S()", ast->ValueType.to_string() );
@ -847,6 +861,11 @@ void CodeParam::to_string( String& result )
else if ( ast->ValueType ) else if ( ast->ValueType )
result.append_fmt( " %S", ast->ValueType.to_string() ); result.append_fmt( " %S", ast->ValueType.to_string() );
if ( ast->PostNameMacro )
{
result.append_fmt(" %S", ast->PostNameMacro.to_string() );
}
if ( ast->Value ) if ( ast->Value )
result.append_fmt( " = %S", ast->Value.to_string() ); result.append_fmt( " = %S", ast->Value.to_string() );
@ -1096,7 +1115,7 @@ String CodeType::to_string()
void CodeType::to_string( String& result ) void CodeType::to_string( String& result )
{ {
#if GEN_USE_NEW_TYPENAME_PARSING #if defined(GEN_USE_NEW_TYPENAME_PARSING)
if ( ast->ReturnType && ast->Params ) if ( ast->ReturnType && ast->Params )
{ {
if ( ast->Attributes ) if ( ast->Attributes )
@ -1253,7 +1272,7 @@ void CodeVar::to_string( String& result )
result.append( ast->Name ); result.append( ast->Name );
if ( ast->ValueType && ast->ValueType->ArrExpr ) if ( ast->ValueType->ArrExpr )
{ {
result.append_fmt( "[ %S ]", ast->ValueType->ArrExpr.to_string() ); result.append_fmt( "[ %S ]", ast->ValueType->ArrExpr.to_string() );
@ -1266,12 +1285,20 @@ void CodeVar::to_string( String& result )
} }
if ( ast->Value ) if ( ast->Value )
result.append_fmt( " = %S", ast->Value.to_string() ); {
if ( ast->VarConstructorInit )
result.append_fmt( "( %S ", ast->Value.to_string() );
else
result.append_fmt( " = %S", ast->Value.to_string() );
}
// Keep the chain going... // Keep the chain going...
if ( ast->NextVar ) if ( ast->NextVar )
result.append_fmt( ", %S", ast->NextVar.to_string() ); result.append_fmt( ", %S", ast->NextVar.to_string() );
if ( ast->VarConstructorInit )
result.append( " )");
return; return;
} }
@ -1304,11 +1331,19 @@ void CodeVar::to_string( String& result )
result.append_fmt( " : %S", ast->BitfieldSize.to_string() ); result.append_fmt( " : %S", ast->BitfieldSize.to_string() );
if ( ast->Value ) if ( ast->Value )
result.append_fmt( " = %S", ast->Value.to_string() ); {
if ( ast->VarConstructorInit )
result.append_fmt( "( %S ", ast->Value.to_string() );
else
result.append_fmt( " = %S", ast->Value.to_string() );
}
if ( ast->NextVar ) if ( ast->NextVar )
result.append_fmt( ", %S", ast->NextVar.to_string() ); result.append_fmt( ", %S", ast->NextVar.to_string() );
if ( ast->VarConstructorInit )
result.append( " )");
if ( ast->InlineCmt ) if ( ast->InlineCmt )
result.append_fmt("; %S", ast->InlineCmt->Content); result.append_fmt("; %S", ast->InlineCmt->Content);
else else
@ -1336,11 +1371,19 @@ void CodeVar::to_string( String& result )
result.append_fmt( "%S %S", ast->ValueType.to_string(), ast->Name ); result.append_fmt( "%S %S", ast->ValueType.to_string(), ast->Name );
if ( ast->Value ) if ( ast->Value )
result.append_fmt( " = %S", ast->Value.to_string() ); {
if ( ast->VarConstructorInit )
result.append_fmt( "( %S ", ast->Value.to_string() );
else
result.append_fmt( " = %S", ast->Value.to_string() );
}
if ( ast->NextVar ) if ( ast->NextVar )
result.append_fmt( ", %S", ast->NextVar.to_string() ); result.append_fmt( ", %S", ast->NextVar.to_string() );
if ( ast->VarConstructorInit )
result.append( " )");
result.append( ";" ); result.append( ";" );
if ( ast->InlineCmt ) if ( ast->InlineCmt )

File diff suppressed because it is too large Load Diff

View File

@ -72,7 +72,7 @@ namespace ECode
NumTypes NumTypes
}; };
StrC to_str( Type type ) inline StrC to_str( Type type )
{ {
local_persist StrC lookup[] { local_persist StrC lookup[] {
{ sizeof( "Invalid" ), "Invalid" }, { sizeof( "Invalid" ), "Invalid" },

View File

@ -59,7 +59,7 @@ namespace EOperator
NumOps NumOps
}; };
StrC to_str( Type op ) inline StrC to_str( Type op )
{ {
local_persist StrC lookup[] { local_persist StrC lookup[] {
{ sizeof( "INVALID" ), "INVALID" }, { sizeof( "INVALID" ), "INVALID" },

View File

@ -38,12 +38,12 @@ namespace ESpecifier
NumSpecifiers NumSpecifiers
}; };
bool is_trailing( Type specifier ) inline bool is_trailing( Type specifier )
{ {
return specifier > Virtual; return specifier > Virtual;
} }
StrC to_str( Type type ) inline StrC to_str( Type type )
{ {
local_persist StrC lookup[] { local_persist StrC lookup[] {
{ sizeof( "INVALID" ), "INVALID" }, { sizeof( "INVALID" ), "INVALID" },
@ -76,7 +76,7 @@ namespace ESpecifier
return lookup[type]; return lookup[type];
} }
Type to_type( StrC str ) inline Type to_type( StrC str )
{ {
local_persist u32 keymap[NumSpecifiers]; local_persist u32 keymap[NumSpecifiers];
do_once_start for ( u32 index = 0; index < NumSpecifiers; index++ ) do_once_start for ( u32 index = 0; index < NumSpecifiers; index++ )

View File

@ -113,7 +113,7 @@ namespace parser
NumTokens NumTokens
}; };
StrC to_str( Type type ) inline StrC to_str( Type type )
{ {
local_persist StrC lookup[] { local_persist StrC lookup[] {
{ sizeof( "__invalid__" ), "__invalid__" }, { sizeof( "__invalid__" ), "__invalid__" },
@ -217,7 +217,7 @@ namespace parser
return lookup[type]; return lookup[type];
} }
Type to_type( StrC str ) inline Type to_type( StrC str )
{ {
local_persist u32 keymap[NumTokens]; local_persist u32 keymap[NumTokens];
do_once_start for ( u32 index = 0; index < NumTokens; index++ ) do_once_start for ( u32 index = 0; index < NumTokens; index++ )

View File

@ -63,7 +63,6 @@ extern CodeAttributes attrib_api_import;
extern Code module_global_fragment; extern Code module_global_fragment;
extern Code module_private_fragment; extern Code module_private_fragment;
// Exposed, but this is really used for parsing.
extern Code fmt_newline; extern Code fmt_newline;
extern CodePragma pragma_once; extern CodePragma pragma_once;

View File

@ -3,6 +3,7 @@
#include "interface.hpp" #include "interface.hpp"
#endif #endif
inline
void AST::append( AST* other ) void AST::append( AST* other )
{ {
if ( other->Parent ) if ( other->Parent )
@ -27,6 +28,7 @@ void AST::append( AST* other )
NumEntries++; NumEntries++;
} }
inline
Code& AST::entry( u32 idx ) Code& AST::entry( u32 idx )
{ {
AST** current = & Front; AST** current = & Front;
@ -42,21 +44,25 @@ Code& AST::entry( u32 idx )
return * rcast( Code*, current); return * rcast( Code*, current);
} }
inline
bool AST::has_entries() bool AST::has_entries()
{ {
return NumEntries; return NumEntries > 0;
} }
inline
char const* AST::type_str() char const* AST::type_str()
{ {
return ECode::to_str( Type ); return ECode::to_str( Type );
} }
inline
AST::operator Code() AST::operator Code()
{ {
return { this }; return { this };
} }
inline
Code& Code::operator ++() Code& Code::operator ++()
{ {
if ( ast ) if ( ast )
@ -65,6 +71,7 @@ Code& Code::operator ++()
return *this; return *this;
} }
inline
void CodeClass::add_interface( CodeType type ) void CodeClass::add_interface( CodeType type )
{ {
CodeType possible_slot = ast->ParentType; CodeType possible_slot = ast->ParentType;
@ -84,6 +91,7 @@ void CodeClass::add_interface( CodeType type )
possible_slot.ast = type.ast; possible_slot.ast = type.ast;
} }
inline
void CodeParam::append( CodeParam other ) void CodeParam::append( CodeParam other )
{ {
AST* self = (AST*) ast; AST* self = (AST*) ast;
@ -107,6 +115,7 @@ void CodeParam::append( CodeParam other )
self->NumEntries++; self->NumEntries++;
} }
inline
CodeParam CodeParam::get( s32 idx ) CodeParam CodeParam::get( s32 idx )
{ {
CodeParam param = *this; CodeParam param = *this;
@ -115,24 +124,27 @@ CodeParam CodeParam::get( s32 idx )
if ( ! ++ param ) if ( ! ++ param )
return { nullptr }; return { nullptr };
return { (AST_Param*) param.raw()->Next }; param = { (AST_Param*) param.raw()->Next };
} }
while ( --idx ); while ( --idx );
return { nullptr }; return param;
} }
inline
bool CodeParam::has_entries() bool CodeParam::has_entries()
{ {
return ast->NumEntries > 0; return ast->NumEntries > 0;
} }
inline
CodeParam& CodeParam::operator ++() CodeParam& CodeParam::operator ++()
{ {
ast = ast->Next.ast; ast = ast->Next.ast;
return * this; return * this;
} }
inline
void CodeStruct::add_interface( CodeType type ) void CodeStruct::add_interface( CodeType type )
{ {
CodeType possible_slot = ast->ParentType; CodeType possible_slot = ast->ParentType;
@ -152,6 +164,7 @@ void CodeStruct::add_interface( CodeType type )
possible_slot.ast = type.ast; possible_slot.ast = type.ast;
} }
inline
CodeBody def_body( CodeT type ) CodeBody def_body( CodeT type )
{ {
switch ( type ) switch ( type )
@ -179,6 +192,7 @@ CodeBody def_body( CodeT type )
return (CodeBody)result; return (CodeBody)result;
} }
inline
StrC token_fmt_impl( sw num, ... ) StrC token_fmt_impl( sw num, ... )
{ {
local_persist thread_local local_persist thread_local

View File

@ -374,7 +374,7 @@ AllocatorInfo get_string_allocator( s32 str_length )
uw size_req = str_length + sizeof(String::Header) + sizeof(char*); uw size_req = str_length + sizeof(String::Header) + sizeof(char*);
if ( last->TotalUsed + size_req > last->TotalSize ) if ( last->TotalUsed + sw(size_req) > last->TotalSize )
{ {
Arena new_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena ); Arena new_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena );

View File

@ -1202,6 +1202,26 @@ TokArray lex( StrC content )
move_forward(); move_forward();
token.Length++; token.Length++;
} }
// Handle number literal suffixes in a botched way
if (left && (
current == 'l' || current == 'L' || // long/long long
current == 'u' || current == 'U' || // unsigned
current == 'f' || current == 'F' || // float
current == 'i' || current == 'I' || // imaginary
current == 'z' || current == 'Z')) // complex
{
char prev = current;
move_forward();
token.Length++;
// Handle 'll'/'LL' as a special case when we just processed an 'l'/'L'
if (left && (prev == 'l' || prev == 'L') && (current == 'l' || current == 'L'))
{
move_forward();
token.Length++;
}
}
} }
goto FoundToken; goto FoundToken;

View File

@ -481,7 +481,7 @@ Code parse_array_decl()
if ( check( TokType::Operator ) && currtok.Text[0] == '[' && currtok.Text[1] == ']' ) if ( check( TokType::Operator ) && currtok.Text[0] == '[' && currtok.Text[1] == ']' )
{ {
Code array_expr = untyped_str( get_cached_string(txt(" ")) ); Code array_expr = untyped_str( currtok );
eat( TokType::Operator ); eat( TokType::Operator );
// [] // []
@ -554,44 +554,6 @@ Code parse_array_decl()
return { nullptr }; return { nullptr };
} }
internal inline
Code parse_assignment_expression()
{
Code expr = { nullptr };
eat( TokType::Operator );
// <Attributes> <Specifiers> <ValueType> <Name> =
Token expr_tok = currtok;
if ( currtok.Type == TokType::Statement_End && currtok.Type != TokType::Comma )
{
log_failure( "Expected expression after assignment operator\n%s", Context.to_string() );
Context.pop();
return CodeInvalid;
}
s32 level = 0;
while ( left && currtok.Type != TokType::Statement_End && (currtok.Type != TokType::Comma || level > 0) )
{
if (currtok.Type == TokType::BraceCurly_Open )
level++;
if (currtok.Type == TokType::BraceCurly_Close )
level--;
if (currtok.Type == TokType::Capture_Start)
level++;
else if (currtok.Type == TokType::Capture_End)
level--;
eat( currtok.Type );
}
expr_tok.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )expr_tok.Text - 1;
expr = untyped_str( expr_tok );
// = <Expression>
return expr;
}
internal inline internal inline
CodeAttributes parse_attributes() CodeAttributes parse_attributes()
{ {
@ -1349,17 +1311,14 @@ CodeDefine parse_define()
eat( TokType::Identifier ); eat( TokType::Identifier );
// #define <Name> // #define <Name>
// Defines don't necessarily need content.
#if 0
if ( ! check( TokType::Preprocess_Content )) if ( ! check( TokType::Preprocess_Content ))
{ {
log_failure( "Error, expected content after #define %s\n%s", define->Name, Context.to_string() ); log_failure( "Error, expected content after #define %s\n%s", define->Name, Context.to_string() );
Context.pop(); Context.pop();
return CodeInvalid; return CodeInvalid;
} }
#endif
if ( check(TokType::Preprocess_Content) && currtok.Length != 0 ) if ( currtok.Length == 0 )
{ {
define->Content = get_cached_string( currtok ); define->Content = get_cached_string( currtok );
eat( TokType::Preprocess_Content ); eat( TokType::Preprocess_Content );
@ -1377,6 +1336,44 @@ CodeDefine parse_define()
return define; return define;
} }
internal inline
Code parse_assignment_expression()
{
Code expr = { nullptr };
eat( TokType::Operator );
// <Attributes> <Specifiers> <ValueType> <Name> =
Token expr_tok = currtok;
if ( currtok.Type == TokType::Statement_End && currtok.Type != TokType::Comma )
{
log_failure( "Expected expression after assignment operator\n%s", Context.to_string() );
Context.pop();
return CodeInvalid;
}
s32 level = 0;
while ( left && currtok.Type != TokType::Statement_End && (currtok.Type != TokType::Comma || level > 0) )
{
if (currtok.Type == TokType::BraceCurly_Open )
level++;
if (currtok.Type == TokType::BraceCurly_Close )
level--;
if (currtok.Type == TokType::Capture_Start)
level++;
else if (currtok.Type == TokType::Capture_End)
level--;
eat( currtok.Type );
}
expr_tok.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )expr_tok.Text - 1;
expr = untyped_str( expr_tok );
// = <Expression>
return expr;
}
internal inline internal inline
Code parse_forward_or_definition( TokType which, bool is_inplace ) Code parse_forward_or_definition( TokType which, bool is_inplace )
{ {
@ -1407,8 +1404,6 @@ Code parse_forward_or_definition( TokType which, bool is_inplace )
return CodeInvalid; return CodeInvalid;
} }
return CodeInvalid;
} }
// Function parsing is handled in multiple places because its initial signature is shared with variable parsing // Function parsing is handled in multiple places because its initial signature is shared with variable parsing
@ -1755,7 +1750,6 @@ CodeBody parse_global_nspace( CodeT which )
case TokType::Spec_Internal_Linkage: case TokType::Spec_Internal_Linkage:
case TokType::Spec_NeverInline: case TokType::Spec_NeverInline:
case TokType::Spec_Static: case TokType::Spec_Static:
case TokType::Spec_ThreadLocal:
{ {
SpecifierT specs_found[16] { ESpecifier::NumSpecifiers }; SpecifierT specs_found[16] { ESpecifier::NumSpecifiers };
s32 NumSpecifiers = 0; s32 NumSpecifiers = 0;
@ -1779,7 +1773,6 @@ CodeBody parse_global_nspace( CodeT which )
case ESpecifier::NeverInline: case ESpecifier::NeverInline:
case ESpecifier::Static: case ESpecifier::Static:
case ESpecifier::Volatile: case ESpecifier::Volatile:
case ESpecifier::Thread_Local:
break; break;
case ESpecifier::Consteval: case ESpecifier::Consteval:
@ -1857,7 +1850,7 @@ CodeBody parse_global_nspace( CodeT which )
if ( found_operator_cast_outside_class_implmentation ) if ( found_operator_cast_outside_class_implmentation )
{ {
member = parse_operator_cast(); member = parse_operator_cast( specifiers );
// <Attributes> <Specifiers> <Name>::operator <Type>() { ... } // <Attributes> <Specifiers> <Name>::operator <Type>() { ... }
break; break;
} }
@ -2300,7 +2293,7 @@ CodeOperator parse_operator_after_ret_type(
case '<': case '<':
{ {
if ( currtok.Text[1] == '=' ) if ( currtok.Text[1] == '=' )
op = LesserEqual; op = LEqual;
else if ( currtok.Text[1] == '<' ) else if ( currtok.Text[1] == '<' )
{ {
@ -2540,7 +2533,14 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes
Token name = parse_identifier(); Token name = parse_identifier();
Context.Scope->Name = name; Context.Scope->Name = name;
if ( check( TokType::Capture_Start) ) bool detected_capture = check( TokType::Capture_Start );
// Check three tokens ahead to make sure that were not dealing with a constructor initialization...
// ( 350.0f , <--- Could be the scenario
// Example : <Capture_Start> <Value> <Comma>
// idx +1 +2
bool detected_comma = Context.Tokens.Arr[ Context.Tokens.Idx + 2 ].Type == TokType::Comma;
if ( detected_capture && ! detected_comma )
{ {
// Dealing with a function // Dealing with a function
result = parse_function_after_name( ModuleFlag::None, attributes, specifiers, type, name ); result = parse_function_after_name( ModuleFlag::None, attributes, specifiers, type, name );
@ -2625,10 +2625,11 @@ CodeParam parse_params( bool use_template_capture )
return { nullptr }; return { nullptr };
} }
Code macro = { nullptr }; Code macro = { nullptr };
CodeType type = { nullptr }; CodeType type = { nullptr };
Code value = { nullptr }; Code value = { nullptr };
Token name = NullToken; Token name = NullToken;
Code post_name_macro = { nullptr };
if ( check( TokType::Varadic_Argument ) ) if ( check( TokType::Varadic_Argument ) )
{ {
@ -2670,6 +2671,15 @@ CodeParam parse_params( bool use_template_capture )
// ( <Macro> <ValueType> <Name> // ( <Macro> <ValueType> <Name>
} }
// Unreal has yet another type of macro:
// template<class T UE_REQUIRES(TPointerIsConvertibleFromTo<T, UInterface>::Value)>
// class T ... and then ^this^ UE_REQUIRES shows up
// So we need to consume that.
if ( check( TokType::Preprocess_Macro ))
{
post_name_macro = parse_simple_preprocess( ETokType::Preprocess_Macro );
}
// In template captures you can have a typename have direct assignment without a name // In template captures you can have a typename have direct assignment without a name
// typename = typename ... // typename = typename ...
// Which would result in a static value type from a struct expansion (traditionally) // Which would result in a static value type from a struct expansion (traditionally)
@ -2689,7 +2699,7 @@ CodeParam parse_params( bool use_template_capture )
s32 capture_level = 0; s32 capture_level = 0;
s32 template_level = 0; s32 template_level = 0;
while ( left && (currtok.Type != TokType::Comma) && template_level >= 0 && (CheckEndParams() || capture_level > 0 || template_level > 0) ) while ( (left && ( currtok.Type != TokType::Comma ) && template_level >= 0 && CheckEndParams()) || (capture_level > 0 || template_level > 0) )
{ {
if (currtok.Text[ 0 ] == '<') if (currtok.Text[ 0 ] == '<')
++ template_level; ++ template_level;
@ -2773,6 +2783,15 @@ CodeParam parse_params( bool use_template_capture )
// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name> // ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name>
} }
// Unreal has yet another type of macro:
// template<class T UE_REQUIRES(TPointerIsConvertibleFromTo<T, UInterface>::Value)>
// class T ... and then ^this^ UE_REQUIRES shows up
// So we need to consume that.
if ( check( TokType::Preprocess_Macro ))
{
post_name_macro = parse_simple_preprocess( ETokType::Preprocess_Macro );
}
// In template captures you can have a typename have direct assignment without a name // In template captures you can have a typename have direct assignment without a name
// typename = typename ... // typename = typename ...
// Which would result in a static value type from a struct expansion (traditionally) // Which would result in a static value type from a struct expansion (traditionally)
@ -2792,10 +2811,10 @@ CodeParam parse_params( bool use_template_capture )
s32 capture_level = 0; s32 capture_level = 0;
s32 template_level = 0; s32 template_level = 0;
while ( left while ( (left
&& currtok.Type != TokType::Comma && currtok.Type != TokType::Comma
&& template_level >= 0 && template_level >= 0
&& (CheckEndParams() || capture_level > 0 || template_level > 0) ) && CheckEndParams()) || (capture_level > 0 || template_level > 0) )
{ {
if (currtok.Text[ 0 ] == '<') if (currtok.Text[ 0 ] == '<')
++ template_level; ++ template_level;
@ -2829,7 +2848,8 @@ CodeParam parse_params( bool use_template_capture )
if ( name.Length > 0 ) if ( name.Length > 0 )
param->Name = get_cached_string( name ); param->Name = get_cached_string( name );
param->ValueType = type; param->PostNameMacro = post_name_macro;
param->ValueType = type;
if ( value ) if ( value )
param->Value = value; param->Value = value;
@ -2872,7 +2892,7 @@ CodePreprocessCond parse_preprocess_cond()
CodePreprocessCond CodePreprocessCond
cond = (CodePreprocessCond) make_code(); cond = (CodePreprocessCond) make_code();
cond->Type = scast(CodeT, currtok.Type - (s32(ETokType::Preprocess_If) - s32(ECode::Preprocess_If)) ); cond->Type = scast(CodeT, currtok.Type - ( TokType::Preprocess_If - ECode::Preprocess_If ) );
eat( currtok.Type ); eat( currtok.Type );
// #<Conditional> // #<Conditional>
@ -3067,6 +3087,8 @@ CodeVar parse_variable_after_name(
Code expr = { nullptr }; Code expr = { nullptr };
Code bitfield_expr = { nullptr }; Code bitfield_expr = { nullptr };
b32 using_constructor_initializer = false;
if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) ) if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) )
{ {
// <Attributes> <Specifiers> <ValueType> <Name> = <Expression> // <Attributes> <Specifiers> <ValueType> <Name> = <Expression>
@ -3098,6 +3120,33 @@ CodeVar parse_variable_after_name(
// <Attributes> <Specifiers> <ValueType> <Name> = { <Expression> } // <Attributes> <Specifiers> <ValueType> <Name> = { <Expression> }
} }
if ( currtok.Type == TokType::Capture_Start )
{
eat( TokType:: Capture_Start);
// <Attributes> <Specifiers> <ValueType> <Name> (
Token expr_token = currtok;
using_constructor_initializer = true;
s32 level = 0;
while ( left && ( currtok.Type != TokType::Capture_End || level > 0 ) )
{
if ( currtok.Type == TokType::Capture_Start )
level++;
else if ( currtok.Type == TokType::Capture_End && level > 0 )
level--;
eat( currtok.Type );
}
expr_token.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)expr_token.Text;
expr = untyped_str( expr_token );
eat( TokType::Capture_End );
// <Attributes> <Specifiers> <ValueType> <Name> ( <Expression> )
}
if ( currtok.Type == TokType::Assign_Classifer ) if ( currtok.Type == TokType::Assign_Classifer )
{ {
eat( TokType::Assign_Classifer ); eat( TokType::Assign_Classifer );
@ -3192,6 +3241,8 @@ CodeVar parse_variable_after_name(
result->NextVar->Parent = result; result->NextVar->Parent = result;
} }
result->VarConstructorInit = using_constructor_initializer;
Context.pop(); Context.pop();
return result; return result;
} }
@ -3246,7 +3297,7 @@ CodeVar parse_variable_declaration_list()
break; break;
} }
eat(currtok.Type); // eat(currtok.Type);
if ( specifiers ) if ( specifiers )
specifiers.append( spec ); specifiers.append( spec );
@ -3650,11 +3701,11 @@ CodeEnum parse_enum( bool inplace_def )
} }
// Consume inline comments // Consume inline comments
if ( currtok.Type == TokType::Comment && prevtok.Line == currtok.Line ) // if ( currtok.Type == TokType::Comment && prevtok.Line == currtok.Line )
{ // {
eat( TokType::Comment ); // eat( TokType::Comment );
// <Name> = <Expression> <Macro>, // <Inline Comment> // <Name> = <Expression> <Macro>, // <Inline Comment>
} // }
entry.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)entry.Text; entry.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)entry.Text;
@ -4029,8 +4080,6 @@ CodeOpCast parse_operator_cast( CodeSpecifiers specifiers )
{ {
push_scope(); push_scope();
// TODO : Specifiers attributed to the cast
// Operator's namespace if not within same class. // Operator's namespace if not within same class.
Token name = NullToken; Token name = NullToken;
if ( check( TokType::Identifier ) ) if ( check( TokType::Identifier ) )
@ -4399,13 +4448,10 @@ CodeType parse_type( bool from_template, bool* typedef_is_function )
else if ( currtok.Type == TokType::Decl_Class || currtok.Type == TokType::Decl_Enum || currtok.Type == TokType::Decl_Struct else if ( currtok.Type == TokType::Decl_Class || currtok.Type == TokType::Decl_Enum || currtok.Type == TokType::Decl_Struct
|| currtok.Type == TokType::Decl_Union ) || currtok.Type == TokType::Decl_Union )
{ {
Token fwd_key = currtok;
eat( currtok.Type ); eat( currtok.Type );
// <Attributes> <Specifiers> <class, enum, struct, union> // <Attributes> <Specifiers> <class, enum, struct, union>
name = parse_identifier(); name = parse_identifier();
fwd_key.Length = sptr(name.Text + name.Length) - sptr(fwd_key.Text);
name = fwd_key;
// name.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )name.Text; // name.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )name.Text;
// eat( TokType::Identifier ); // eat( TokType::Identifier );
@ -4462,6 +4508,18 @@ else if ( currtok.Type == TokType::DeclType )
name = currtok; name = currtok;
eat(TokType::Type_Typename); eat(TokType::Type_Typename);
// <typename> // <typename>
if ( ! from_template )
{
name = parse_identifier();
Context.Scope->Name = name;
if ( ! name )
{
log_failure( "Error, failed to type signature\n%s", Context.to_string() );
Context.pop();
return CodeInvalid;
}
}
} }
// The usual Identifier type signature that may have namespace qualifiers // The usual Identifier type signature that may have namespace qualifiers

View File

@ -9,4 +9,3 @@
#ifndef GEN_ROLL_OWN_DEPENDENCIES #ifndef GEN_ROLL_OWN_DEPENDENCIES
# include "gen.dep.cpp" # include "gen.dep.cpp"
#endif #endif

View File

@ -71,6 +71,7 @@ enum class ModuleFlag : u32
Invalid, Invalid,
}; };
inline
StrC to_str( ModuleFlag flag ) StrC to_str( ModuleFlag flag )
{ {
local_persist local_persist
@ -86,6 +87,7 @@ StrC to_str( ModuleFlag flag )
return lookup[ (u32)flag ]; return lookup[ (u32)flag ];
} }
inline
ModuleFlag operator|( ModuleFlag A, ModuleFlag B) ModuleFlag operator|( ModuleFlag A, ModuleFlag B)
{ {
return (ModuleFlag)( (u32)A | (u32)B ); return (ModuleFlag)( (u32)A | (u32)B );

View File

@ -50,6 +50,11 @@ struct Array
return 2 * value + 8; return 2 * value + 8;
} }
bool append( Array other )
{
return append( other, other.num() );
}
bool append( Type value ) bool append( Type value )
{ {
Header* header = get_header(); Header* header = get_header();
@ -158,7 +163,7 @@ struct Array
if ( begin < 0 || end > header.Num ) if ( begin < 0 || end > header.Num )
return false; return false;
for ( sw idx = begin; idx < end; idx++ ) for ( sw idx = sw(begin); idx < sw(end); idx++ )
{ {
Data[ idx ] = value; Data[ idx ] = value;
} }
@ -365,7 +370,7 @@ struct HashTable
{ {
GEN_ASSERT_NOT_NULL( map_proc ); GEN_ASSERT_NOT_NULL( map_proc );
for ( sw idx = 0; idx < Entries.num(); idx++ ) for ( sw idx = 0; idx < sw(Entries.num()); ++idx )
{ {
map_proc( Entries[ idx ].Key, Entries[ idx ].Value ); map_proc( Entries[ idx ].Key, Entries[ idx ].Value );
} }
@ -377,7 +382,7 @@ struct HashTable
{ {
GEN_ASSERT_NOT_NULL( map_proc ); GEN_ASSERT_NOT_NULL( map_proc );
for ( sw idx = 0; idx < Entries.num(); idx++ ) for ( sw idx = 0; idx < sw(Entries.num()); ++idx )
{ {
map_proc( Entries[ idx ].Key, & Entries[ idx ].Value ); map_proc( Entries[ idx ].Key, & Entries[ idx ].Value );
} }
@ -394,7 +399,7 @@ struct HashTable
sw last_added_index; sw last_added_index;
HashTable<Type> new_ht = init_reserve( Hashes.get_header()->Allocator, new_num ); HashTable<Type> new_ht = init_reserve( Hashes.get_header()->Allocator, new_num );
for ( sw idx = 0; idx < Entries.num(); ++idx ) for ( sw idx = 0; idx < sw(Entries.num()); ++idx )
{ {
FindResult find_result; FindResult find_result;
@ -419,13 +424,13 @@ struct HashTable
{ {
sw idx; sw idx;
for ( idx = 0; idx < Entries.num(); idx++ ) for ( idx = 0; idx < sw(Entries.num()); idx++ )
Entries[ idx ].Next = -1; Entries[ idx ].Next = -1;
for ( idx = 0; idx < Hashes.num(); idx++ ) for ( idx = 0; idx < sw(Hashes.num()); idx++ )
Hashes[ idx ] = -1; Hashes[ idx ] = -1;
for ( idx = 0; idx < Entries.num(); idx++ ) for ( idx = 0; idx < sw(Entries.num()); idx++ )
{ {
Entry* entry; Entry* entry;
FindResult find_result; FindResult find_result;
@ -491,7 +496,7 @@ struct HashTable
sw slot( u64 key ) sw slot( u64 key )
{ {
for ( sw idx = 0; idx < Hashes.num(); ++idx ) for ( sw idx = 0; idx < sw(Hashes.num()); ++idx )
if ( Hashes[ idx ] == key ) if ( Hashes[ idx ] == key )
return idx; return idx;

View File

@ -594,7 +594,7 @@ internal GEN_FILE_WRITE_AT_PROC( _memory_file_write )
{ {
Array<u8> arr = { d->buf }; Array<u8> arr = { d->buf };
if ( arr.get_header()->Capacity < new_cap ) if ( arr.get_header()->Capacity < uw(new_cap) )
{ {
if ( ! arr.grow( ( s64 )( new_cap ) ) ) if ( ! arr.grow( ( s64 )( new_cap ) ) )
return false; return false;

View File

@ -13,6 +13,7 @@
#define internal static // Internal linkage #define internal static // Internal linkage
#define local_persist static // Local Persisting variables #define local_persist static // Local Persisting variables
#pragma region ForceInline Definition
#ifdef GEN_COMPILER_MSVC #ifdef GEN_COMPILER_MSVC
# define forceinline __forceinline # define forceinline __forceinline
# define neverinline __declspec( noinline ) # define neverinline __declspec( noinline )
@ -31,18 +32,23 @@
# define forceinline # define forceinline
# define neverinline # define neverinline
#endif #endif
#pragma endregion ForceInline Definition
// Bits // Bits
#ifndef bit
#define bit( Value ) ( 1 << Value ) #define bit( Value ) ( 1 << Value )
#define bitfield_is_equal( Type, Field, Mask ) ( (Type(Mask) & Type(Field)) == Type(Mask) ) #define bitfield_is_equal( Type, Field, Mask ) ( (Type(Mask) & Type(Field)) == Type(Mask) )
#endif
// Casting // Casting
#ifndef ccast
#define ccast( Type, Value ) ( * const_cast< Type* >( & (Value) ) ) #define ccast( Type, Value ) ( * const_cast< Type* >( & (Value) ) )
#define pcast( Type, Value ) ( * reinterpret_cast< Type* >( & ( Value ) ) ) #define pcast( Type, Value ) ( * reinterpret_cast< Type* >( & ( Value ) ) )
#define rcast( Type, Value ) reinterpret_cast< Type >( Value ) #define rcast( Type, Value ) reinterpret_cast< Type >( Value )
#define scast( Type, Value ) static_cast< Type >( Value ) #define scast( Type, Value ) static_cast< Type >( Value )
#endif
// Num Arguments (Varadics) // Num Arguments (Varadics)
// #if defined(__GNUC__) || defined(__clang__) // #if defined(__GNUC__) || defined(__clang__)

View File

@ -445,10 +445,14 @@ struct Arena
return alignment_offset; return alignment_offset;
} }
// This id is defined by Unreal for asserts
#pragma push_macro("check")
#undef check
void check() void check()
{ {
GEN_ASSERT( TempCount == 0 ); GEN_ASSERT( TempCount == 0 );
} }
#pragma pop_macro("check")
void free() void free()
{ {

View File

@ -36,7 +36,7 @@ u8 adt_destroy_branch( ADT_Node* node )
GEN_ASSERT_NOT_NULL( node ); GEN_ASSERT_NOT_NULL( node );
if ( ( node->type == EADT_TYPE_OBJECT || node->type == EADT_TYPE_ARRAY ) && node->nodes ) if ( ( node->type == EADT_TYPE_OBJECT || node->type == EADT_TYPE_ARRAY ) && node->nodes )
{ {
for ( sw i = 0; i < node->nodes.num(); ++i ) for ( sw i = 0; i < scast(sw, node->nodes.num()); ++i )
{ {
adt_destroy_branch( node->nodes + i ); adt_destroy_branch( node->nodes + i );
} }
@ -66,7 +66,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search )
return NULL; return NULL;
} }
for ( sw i = 0; i < node->nodes.num(); i++ ) for ( sw i = 0; i < scast(sw, node->nodes.num()); i++ )
{ {
if ( ! str_compare( node->nodes[ i ].name, name ) ) if ( ! str_compare( node->nodes[ i ].name, name ) )
{ {
@ -76,7 +76,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search )
if ( deep_search ) if ( deep_search )
{ {
for ( sw i = 0; i < node->nodes.num(); i++ ) for ( sw i = 0; i < scast(sw, node->nodes.num()); i++ )
{ {
ADT_Node* res = adt_find( node->nodes + i, name, deep_search ); ADT_Node* res = adt_find( node->nodes + i, name, deep_search );
@ -132,7 +132,7 @@ internal ADT_Node* _adt_get_value( ADT_Node* node, char const* value )
internal ADT_Node* _adt_get_field( ADT_Node* node, char* name, char* value ) internal ADT_Node* _adt_get_field( ADT_Node* node, char* name, char* value )
{ {
for ( sw i = 0; i < node->nodes.num(); i++ ) for ( sw i = 0; i < scast(sw, node->nodes.num()); i++ )
{ {
if ( ! str_compare( node->nodes[ i ].name, name ) ) if ( ! str_compare( node->nodes[ i ].name, name ) )
{ {
@ -207,7 +207,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri )
/* run a value comparison against any child that is an object node */ /* run a value comparison against any child that is an object node */
else if ( node->type == EADT_TYPE_ARRAY ) else if ( node->type == EADT_TYPE_ARRAY )
{ {
for ( sw i = 0; i < node->nodes.num(); i++ ) for ( sw i = 0; i < scast(sw, node->nodes.num()); i++ )
{ {
ADT_Node* child = &node->nodes[ i ]; ADT_Node* child = &node->nodes[ i ];
if ( child->type != EADT_TYPE_OBJECT ) if ( child->type != EADT_TYPE_OBJECT )
@ -225,7 +225,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri )
/* [value] */ /* [value] */
else else
{ {
for ( sw i = 0; i < node->nodes.num(); i++ ) for ( sw i = 0; i < scast(sw, node->nodes.num()); i++ )
{ {
ADT_Node* child = &node->nodes[ i ]; ADT_Node* child = &node->nodes[ i ];
if ( _adt_get_value( child, l_b2 ) ) if ( _adt_get_value( child, l_b2 ) )
@ -257,7 +257,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri )
else else
{ {
sw idx = ( sw )str_to_i64( buf, NULL, 10 ); sw idx = ( sw )str_to_i64( buf, NULL, 10 );
if ( idx >= 0 && idx < node->nodes.num() ) if ( idx >= 0 && idx < scast(sw, node->nodes.num()) )
{ {
found_node = &node->nodes[ idx ]; found_node = &node->nodes[ idx ];
@ -282,7 +282,7 @@ ADT_Node* adt_alloc_at( ADT_Node* parent, sw index )
if ( ! parent->nodes ) if ( ! parent->nodes )
return NULL; return NULL;
if ( index < 0 || index > parent->nodes.num() ) if ( index < 0 || index > scast(sw, parent->nodes.num()) )
return NULL; return NULL;
ADT_Node o = { 0 }; ADT_Node o = { 0 };
@ -946,7 +946,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b
} }
} }
if ( columnIndex >= root->nodes.num() ) if ( columnIndex >= scast(sw, root->nodes.num()) )
{ {
adt_append_arr( root, NULL ); adt_append_arr( root, NULL );
} }
@ -989,7 +989,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b
/* consider first row as a header. */ /* consider first row as a header. */
if ( has_header ) if ( has_header )
{ {
for ( sw i = 0; i < root->nodes.num(); i++ ) for ( sw i = 0; i < scast(sw, root->nodes.num()); i++ )
{ {
CSV_Object* col = root->nodes + i; CSV_Object* col = root->nodes + i;
CSV_Object* hdr = col->nodes; CSV_Object* hdr = col->nodes;

View File

@ -124,7 +124,7 @@ bool String::make_space_for( char const* str, sw add_len )
Data = rcast( char*, header + 1 ); Data = rcast( char*, header + 1 );
return str; return true;
} }
} }
#pragma endregion String #pragma endregion String

View File

@ -18,6 +18,7 @@ struct StrC
#define cast_to_strc( str ) * rcast( StrC*, (str) - sizeof(sw) ) #define cast_to_strc( str ) * rcast( StrC*, (str) - sizeof(sw) )
#define txt( text ) StrC { sizeof( text ) - 1, ( text ) } #define txt( text ) StrC { sizeof( text ) - 1, ( text ) }
inline
StrC to_str( char const* str ) StrC to_str( char const* str )
{ {
return { str_len( str ), str }; return { str_len( str ), str };
@ -139,7 +140,7 @@ struct String
header.Length = curr_len + length; header.Length = curr_len + length;
} }
return str; return str != nullptr;
} }
bool append( StrC str) bool append( StrC str)
@ -353,7 +354,7 @@ struct String
operator bool() operator bool()
{ {
return Data; return Data != nullptr;
} }
operator char* () operator char* ()

View File

@ -35,6 +35,7 @@ CodeBody gen_ecode( char const* path )
#pragma push_macro("local_persist") #pragma push_macro("local_persist")
#undef local_persist #undef local_persist
CodeFn to_str = parse_function( token_fmt( "entries", (StrC)to_str_entries, stringize( CodeFn to_str = parse_function( token_fmt( "entries", (StrC)to_str_entries, stringize(
inline
StrC to_str( Type type ) StrC to_str( Type type )
{ {
local_persist local_persist
@ -89,6 +90,7 @@ CodeBody gen_eoperator( char const* path )
#pragma push_macro("local_persist") #pragma push_macro("local_persist")
#undef local_persist #undef local_persist
CodeFn to_str = parse_function(token_fmt("entries", (StrC)to_str_entries, stringize( CodeFn to_str = parse_function(token_fmt("entries", (StrC)to_str_entries, stringize(
inline
StrC to_str( Type op ) StrC to_str( Type op )
{ {
local_persist local_persist
@ -142,6 +144,7 @@ CodeBody gen_especifier( char const* path )
))); )));
CodeFn is_trailing = parse_function(token_fmt("specifier", (StrC)to_str_entries, stringize( CodeFn is_trailing = parse_function(token_fmt("specifier", (StrC)to_str_entries, stringize(
inline
bool is_trailing( Type specifier ) bool is_trailing( Type specifier )
{ {
return specifier > Virtual; return specifier > Virtual;
@ -159,6 +162,7 @@ CodeBody gen_especifier( char const* path )
#undef forceinline #undef forceinline
#undef neverinline #undef neverinline
CodeFn to_str = parse_function(token_fmt("entries", (StrC)to_str_entries, stringize( CodeFn to_str = parse_function(token_fmt("entries", (StrC)to_str_entries, stringize(
inline
StrC to_str( Type type ) StrC to_str( Type type )
{ {
local_persist local_persist
@ -171,6 +175,7 @@ CodeBody gen_especifier( char const* path )
))); )));
CodeFn to_type = parse_function( token_fmt( "entries", (StrC)to_str_entries, stringize( CodeFn to_type = parse_function( token_fmt( "entries", (StrC)to_str_entries, stringize(
inline
Type to_type( StrC str ) Type to_type( StrC str )
{ {
local_persist local_persist
@ -282,6 +287,7 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path )
#undef do_once_start #undef do_once_start
#undef do_once_end #undef do_once_end
CodeFn to_str = parse_function(token_fmt("entries", (StrC)to_str_entries, "attribute_toks", (StrC)to_str_attributes, stringize( CodeFn to_str = parse_function(token_fmt("entries", (StrC)to_str_entries, "attribute_toks", (StrC)to_str_attributes, stringize(
inline
StrC to_str( Type type ) StrC to_str( Type type )
{ {
local_persist local_persist
@ -295,6 +301,7 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path )
))); )));
CodeFn to_type = parse_function( token_fmt( "entries", (StrC)to_str_entries, stringize( CodeFn to_type = parse_function( token_fmt( "entries", (StrC)to_str_entries, stringize(
inline
Type to_type( StrC str ) Type to_type( StrC str )
{ {
local_persist local_persist
@ -339,6 +346,7 @@ CodeBody gen_ast_inlines()
#undef log_failure #undef log_failure
char const* code_impl_tmpl = stringize( char const* code_impl_tmpl = stringize(
\n \n
inline
char const* <typename>::debug_str() char const* <typename>::debug_str()
{ {
if ( ast == nullptr ) if ( ast == nullptr )
@ -346,6 +354,7 @@ CodeBody gen_ast_inlines()
return rcast(AST*, ast)->debug_str(); return rcast(AST*, ast)->debug_str();
} }
inline
Code <typename>::duplicate() Code <typename>::duplicate()
{ {
if ( ast == nullptr ) if ( ast == nullptr )
@ -356,19 +365,23 @@ CodeBody gen_ast_inlines()
return { rcast(AST*, ast)->duplicate() }; return { rcast(AST*, ast)->duplicate() };
} }
inline
bool <typename>::is_equal( Code other ) bool <typename>::is_equal( Code other )
{ {
if ( ast == nullptr || other.ast == nullptr ) if ( ast == nullptr || other.ast == nullptr )
{ {
// Just check if they're both null. // Just check if they're both null.
return rcast(AST*, ast) == other.ast; // log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
return ast == nullptr && other.ast == nullptr;
} }
return rcast(AST*, ast)->is_equal( other.ast ); return rcast(AST*, ast)->is_equal( other.ast );
} }
inline
bool <typename>::is_valid() bool <typename>::is_valid()
{ {
return (AST*) ast != nullptr && rcast( AST*, ast)->Type != CodeT::Invalid; return (AST*) ast != nullptr && rcast( AST*, ast)->Type != CodeT::Invalid;
} }
inline
void <typename>::set_global() void <typename>::set_global()
{ {
if ( ast == nullptr ) if ( ast == nullptr )
@ -379,6 +392,7 @@ CodeBody gen_ast_inlines()
rcast(AST*, ast)->Parent = Code::Global.ast; rcast(AST*, ast)->Parent = Code::Global.ast;
} }
inline
<typename>& <typename>::operator =( Code other ) <typename>& <typename>::operator =( Code other )
{ {
if ( other.ast && other->Parent ) if ( other.ast && other->Parent )
@ -390,14 +404,17 @@ CodeBody gen_ast_inlines()
ast = rcast( decltype(ast), other.ast ); ast = rcast( decltype(ast), other.ast );
return *this; return *this;
} }
inline
bool <typename>::operator ==( Code other ) bool <typename>::operator ==( Code other )
{ {
return (AST*) ast == other.ast; return (AST*) ast == other.ast;
} }
inline
bool <typename>::operator !=( Code other ) bool <typename>::operator !=( Code other )
{ {
return (AST*) ast != other.ast; return (AST*) ast != other.ast;
} }
inline
<typename>::operator bool() <typename>::operator bool()
{ {
return ast != nullptr; return ast != nullptr;
@ -405,14 +422,17 @@ CodeBody gen_ast_inlines()
); );
char const* codetype_impl_tmpl = stringize( char const* codetype_impl_tmpl = stringize(
inline
AST* Code<typename>::raw() AST* Code<typename>::raw()
{ {
return rcast( AST*, ast ); return rcast( AST*, ast );
} }
inline
Code<typename>::operator Code() Code<typename>::operator Code()
{ {
return *rcast( Code*, this ); return *rcast( Code*, this );
} }
inline
AST_<typename>* Code<typename>::operator->() AST_<typename>* Code<typename>::operator->()
{ {
if ( ast == nullptr ) if ( ast == nullptr )
@ -480,12 +500,11 @@ CodeBody gen_ast_inlines()
impl_code_var. append( parse_global_body( token_fmt( "typename", StrC name(Var), codetype_impl_tmpl ))); impl_code_var. append( parse_global_body( token_fmt( "typename", StrC name(Var), codetype_impl_tmpl )));
char const* cast_tmpl = stringize( char const* cast_tmpl = stringize(
AST::operator Code<typename>() inline AST::operator Code<typename>()
{ {
return { rcast( AST_<typename>*, this ) }; return { rcast( AST_<typename>*, this ) };
} }
inline Code::operator Code<typename>() const
Code::operator Code<typename>() const
{ {
return { (AST_<typename>*) ast }; return { (AST_<typename>*) ast };
} }

View File

@ -1,7 +1,7 @@
#if __clang__ #ifdef __clang__
# pragma clang diagnostic pop # pragma clang diagnostic pop
#endif #endif
#if __GNUC__ #ifdef __GNUC__
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif

View File

@ -1,4 +1,4 @@
#if __clang__ #ifdef __clang__
# pragma clang diagnostic push # pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunused-const-variable" # pragma clang diagnostic ignored "-Wunused-const-variable"
# pragma clang diagnostic ignored "-Wunused-but-set-variable" # pragma clang diagnostic ignored "-Wunused-but-set-variable"
@ -9,7 +9,7 @@
# pragma clang diagnostic ignored "-Wunused-function" # pragma clang diagnostic ignored "-Wunused-function"
#endif #endif
#if __GNUC__ #ifdef __GNUC__
# pragma GCC diagnostic push # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunknown-pragmas" # pragma GCC diagnostic ignored "-Wunknown-pragmas"
# pragma GCC diagnostic ignored "-Wcomment" # pragma GCC diagnostic ignored "-Wcomment"

View File

@ -6,6 +6,7 @@ Import-Module ./helpers/target_arch.psm1
$target_arch = Join-Path $PSScriptRoot 'helpers/target_arch.psm1' $target_arch = Join-Path $PSScriptRoot 'helpers/target_arch.psm1'
$devshell = Join-Path $PSScriptRoot 'helpers/devshell.ps1' $devshell = Join-Path $PSScriptRoot 'helpers/devshell.ps1'
$format_cpp = Join-Path $PSScriptRoot 'helpers/format_cpp.psm1' $format_cpp = Join-Path $PSScriptRoot 'helpers/format_cpp.psm1'
$refactor_unreal = Join-Path $PSScriptRoot 'refactor_unreal.ps1'
$incremental_checks = Join-Path $PSScriptRoot 'helpers/incremental_checks.ps1' $incremental_checks = Join-Path $PSScriptRoot 'helpers/incremental_checks.ps1'
$vendor_toolchain = Join-Path $PSScriptRoot 'helpers/vendor_toolchain.ps1' $vendor_toolchain = Join-Path $PSScriptRoot 'helpers/vendor_toolchain.ps1'
@ -22,6 +23,7 @@ Push-Location $path_root
$verbose = $false $verbose = $false
[bool] $bootstrap = $false [bool] $bootstrap = $false
[bool] $singleheader = $false [bool] $singleheader = $false
[bool] $unreal = $false
[bool] $test = $false [bool] $test = $false
[array] $vendors = @( "clang", "msvc" ) [array] $vendors = @( "clang", "msvc" )
@ -36,6 +38,7 @@ if ( $args ) { $args | ForEach-Object {
"debug" { $release = $false } "debug" { $release = $false }
"bootstrap" { $bootstrap = $true } "bootstrap" { $bootstrap = $true }
"singleheader" { $singleheader = $true } "singleheader" { $singleheader = $true }
"unreal" { $unreal = $true }
"test" { $test = $true } "test" { $test = $true }
} }
}} }}
@ -64,7 +67,7 @@ else {
$optimize = $true $optimize = $true
} }
if ( $bootstrap -eq $false -and $singleheader -eq $false -and $test -eq $false ) { if ( $bootstrap -eq $false -and $singleheader -eq $false -and $unreal -eq $false -and $test -eq $false ) {
throw "No build target specified. One must be specified, this script will not assume one" throw "No build target specified. One must be specified, this script will not assume one"
} }
@ -80,6 +83,7 @@ $path_build = Join-Path $path_root build
$path_project = Join-Path $path_root project $path_project = Join-Path $path_root project
$path_scripts = Join-Path $path_root scripts $path_scripts = Join-Path $path_root scripts
$path_singleheader = Join-Path $path_root singleheader $path_singleheader = Join-Path $path_root singleheader
$path_unreal = Join-Path $path_root unreal_engine
$path_test = Join-Path $path_root test $path_test = Join-Path $path_root test
if ( $bootstrap ) if ( $bootstrap )
@ -162,6 +166,46 @@ if ( $singleheader )
Pop-Location Pop-Location
} }
if ( $unreal )
{
$path_build = join-path $path_unreal build
$path_gen = join-path $path_unreal gen
if ( -not(Test-Path($path_build) )) {
New-Item -ItemType Directory -Path $path_build
}
if ( -not(Test-Path($path_gen) )) {
New-Item -ItemType Directory -Path $path_gen
}
$includes = @( $path_project )
$unit = join-path $path_unreal "unreal.cpp"
$executable = join-path $path_build "unreal.exe"
$compiler_args = @()
$compiler_args += ( $flag_define + 'GEN_TIME' )
$linker_args = @(
$flag_link_win_subsystem_console
)
build-simple $path_build $includes $compiler_args $linker_args $unit $executable
Push-Location $path_unreal
if ( Test-Path( $executable ) ) {
write-host "`nRunning unreal variant generator"
$time_taken = Measure-Command { & $executable
| ForEach-Object {
write-host `t $_ -ForegroundColor Green
}
}
write-host "`n Unreal variant generator completed in $($time_taken.TotalMilliseconds) ms"
}
Pop-Location
. $refactor_unreal
}
if ( $test ) if ( $test )
{ {
$path_gen = join-path $path_test gen $path_gen = join-path $path_test gen
@ -229,7 +273,6 @@ push-location $path_scripts
if ( $bootstrap -and (Test-Path (Join-Path $path_project "gen/gen.hpp")) ) if ( $bootstrap -and (Test-Path (Join-Path $path_project "gen/gen.hpp")) )
{ {
$path_gen = join-path $path_project gen $path_gen = join-path $path_project gen
$path_comp_gen = join-path $path_project components/gen
$include = @( $include = @(
'gen.hpp', 'gen.cpp', 'gen.hpp', 'gen.cpp',
'gen.dep.hpp', 'gen.dep.cpp', 'gen.dep.hpp', 'gen.dep.cpp',
@ -252,6 +295,19 @@ if ( $singleheader -and (Test-Path (Join-Path $path_singleheader "gen/gen.hpp"))
format-cpp $path_gen $include $exclude format-cpp $path_gen $include $exclude
} }
if ( $unreal -and (Test-Path( Join-Path $path_unreal "gen/gen.hpp")) )
{
$path_gen = join-path $path_unreal gen
$include = @(
'gen.hpp', 'gen.cpp',
'gen.dep.hpp', 'gen.dep.cpp',
'gen.builder.hpp', 'gen.builder.cpp'
'gen.scanner.hpp', 'gen.scanner.cpp'
)
$exclude = $null
format-cpp $path_gen $include $exclude
}
if ( $test -and $false ) if ( $test -and $false )
{ {
$path_gen = join-path $path_test gen $path_gen = join-path $path_test gen

View File

@ -3,20 +3,22 @@ cls
$build = Join-Path $PSScriptRoot 'build.ci.ps1' $build = Join-Path $PSScriptRoot 'build.ci.ps1'
if ( $IsWindows ) { if ( $IsWindows ) {
& $build release msvc bootstrap singleheader & $build release msvc bootstrap singleheader unreal
} }
else { else {
& $build release clang bootstrap singleheader & $build release clang bootstrap singleheader unreal
} }
$path_root = git rev-parse --show-toplevel $path_root = git rev-parse --show-toplevel
$path_docs = Join-Path $path_root docs $path_docs = Join-Path $path_root docs
$path_project = Join-Path $path_root project $path_project = Join-Path $path_root project
$path_project_gen = Join-Path $path_project gen $path_project_gen = Join-Path $path_project gen
$path_singleheader = Join-Path $path_root singleheader $path_singleheader = Join-Path $path_root singleheader
$path_singleheader_gen = Join-Path $path_singleheader gen $path_singleheader_gen = Join-Path $path_singleheader gen
$path_release = Join-Path $path_root release $path_unreal = Join-Path $path_root unreal_engine
$path_release_content = Join-Path $path_release content $path_unreal_gen = Join-Path $path_unreal gen
$path_release = Join-Path $path_root release
$path_release_content = Join-Path $path_release content
if ( -not(Test-Path $path_release) ) { if ( -not(Test-Path $path_release) ) {
New-Item -ItemType Directory -Path $path_release New-Item -ItemType Directory -Path $path_release
@ -50,5 +52,17 @@ Remove-Item -Path $path_release_content\gen.hpp
# Segmented # Segmented
Copy-Item -Path $path_project_gen\* -Destination $path_release_content Copy-Item -Path $path_project_gen\* -Destination $path_release_content
Compress-Archive -Path $path_release_content\* -DestinationPath $path_release\gencpp_segmented.zip -Force Compress-Archive -Path $path_release_content\* -DestinationPath $path_release\gencpp_segmented.zip -Force
Remove-Item -Path $path_release_content\gen.dep.hpp
Remove-Item -Path $path_release_content\gen.dep.cpp
Remove-Item -Path $path_release_content\gen.hpp
Remove-Item -Path $path_release_content\gen.cpp
Remove-Item -Path $path_release_content\gen.builder.hpp
Remove-Item -Path $path_release_content\gen.builder.cpp
Remove-Item -Path $path_release_content\gen.scanner.hpp
Remove-Item -Path $path_release_content\gen.scanner.cpp
# Unreal
Copy-Item -Path $path_unreal_gen\* -Destination $path_release_content
Compress-Archive -Path $path_release_content\* -DestinationPath $path_release\gencpp_unreal.zip -Force
Remove-Item -Path $path_release_content -Recurse Remove-Item -Path $path_release_content -Recurse

View File

@ -0,0 +1,56 @@
[string] $format = $false
foreach ( $arg in $args )
{
if ( $arg -eq "format" )
{
$format = $true
}
}
[string[]] $include = 'gen.*.hpp', 'gen.*.cpp', 'gen.hpp', 'gen.cpp'
[string[]] $exclude
$path_root = git rev-parse --show-toplevel
$path_project = Join-Path $path_root project
$path_scripts = Join-Path $path_root scripts
$path_singlheader = Join-Path $path_root singleheader
$path_singleheader_comp = Join-Path $path_singlheader components
$path_unreal = Join-Path $path_root unreal_engine
$path_unreal_gen = Join-Path $path_unreal gen
$file_spec = Join-Path $path_scripts unreal.refactor
# Gather the files to be formatted.
$targetFiles = @()
$targetFiles += Get-ChildItem -Recurse -Path $path_unreal_gen -Include $include -Exclude $exclude | Select-Object -ExpandProperty FullName
# $targetFiles += Get-ChildItem -Recurse -Path $path_project -Include $include -Exclude $exclude | Select-Object -ExpandProperty FullName
# $targetFiles += Get-ChildItem -Recurse -Path $path_singleheader_comp -Include $include -Exclude $exclude | Select-Object -ExpandProperty FullName
# Format the files.
$formatParams = @(
'-i' # In-place
'-style=file:./.clang-format' # Search for a .clang-format file in the parent directory of the source file.
'-verbose'
)
write-host "Beginning refactor...`n"
$refactorParams = @(
# "-debug",
"-num=$($targetFiles.Count)"
"-src=$($targetFiles)",
"-spec=$($file_spec)"
)
& refactor $refactorParams
Write-Host "`nRefactoring complete`n`n"
if ( $format -eq $true ) {
Write-Host "Beginning format...`n"
& clang-format $formatParams $targetFiles
Write-Host "`nFormatting complete"
}

25
scripts/unreal.refactor Normal file
View File

@ -0,0 +1,25 @@
__VERSION 1
// This is a example template to be used with the refactor program
// Use it to refactor the naming convention of this library to your own.
// Can be used as an aid to help use use your project's implementation if it fullfills the dependencies of this project.
// Example: Most likely have a memory and string library already, just rename the functions and make sure the args are the same.
// Program: https://github.com/Ed94/refactor
// NOTE: Due to the current limitations of the program, not every symbol in the library can be renamed.
// This is due to the program not actually parsing C/C++.
// not : Ignore
// include : #includes
// word : Alphanumeric or underscore
// namespace : Prefix search and replace (c-namspaces).
// regex : Unavailable in __VERSION 1.
// Precedence (highest to lowest):
// word, namespace, regex
// Gen Macro namespace
// namespace GEN_, new_namespace_
word forceinline, FORCEINLINE
word spec_forceinline, spec_FORCEINLINE

3
unreal_engine/Readme.md Normal file
View File

@ -0,0 +1,3 @@
# Unreal Engine Version Generator
This generates a variant of gencpp thats compatiable with use as a thirdparty module within a plugin or module of an Unreal Project or the Engine itself.

View File

@ -0,0 +1,31 @@
/*
gencpp: An attempt at "simple" staged metaprogramming for c/c++.
See Readme.md for more information from the project repository.
Public Address:
https://github.com/Ed94/gencpp
This is a variant intended for use with Unreal Engine 5
*/
#if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME)
# error Gen.hpp : GEN_TIME not defined
#endif
//! If its desired to roll your own dependencies, define GEN_ROLL_OWN_DEPENDENCIES before including this file.
// Dependencies are derived from the c-zpl library: https://github.com/zpl-c/zpl
#ifndef GEN_ROLL_OWN_DEPENDENCIES
# include "gen.dep.hpp"
#endif
#ifndef GEN_NS_BEGIN
# ifdef GEN_DONT_USE_NAMESPACE
# define GEN_NS
# define GEN_NS_BEGIN
# define GEN_NS_END
# else
# define GEN_NS gen::
# define GEN_NS_BEGIN namespace gen {
# define GEN_NS_END }
# endif
#endif

View File

@ -0,0 +1,5 @@
#if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME)
# error Gen.hpp : GEN_TIME not defined
#endif
#include "gen.hpp"

View File

@ -0,0 +1,7 @@
API_Export, GEN_API_Export_Code
API_Import, GEN_API_Import_Code
UE_DEPRECATED, UE_DEPRECATED
UMG_API, UMG_API
COREUOBJECT_API, COREUOBJECT_API
ENGINE_API, ENGINE_API
GAMEPLAYABILITIES_API, GAMEPLAYABILITIES_API
1 API_Export GEN_API_Export_Code
2 API_Import GEN_API_Import_Code
3 UE_DEPRECATED UE_DEPRECATED
4 UMG_API UMG_API
5 COREUOBJECT_API COREUOBJECT_API
6 ENGINE_API ENGINE_API
7 GAMEPLAYABILITIES_API GAMEPLAYABILITIES_API

416
unreal_engine/unreal.cpp Normal file
View File

@ -0,0 +1,416 @@
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEDN
#include "gen.cpp"
#include "helpers/push_ignores.inline.hpp"
#include "helpers/helper.hpp"
GEN_NS_BEGIN
#include "dependencies/parsing.cpp"
GEN_NS_END
#include "auxillary/builder.hpp"
#include "auxillary/builder.cpp"
#include "auxillary/scanner.hpp"
using namespace gen;
constexpr char const* generation_notice =
"// This file was generated automatially by gencpp's unreal.cpp "
"(See: https://github.com/Ed94/gencpp)\n\n";
constexpr StrC implementation_guard_start = txt(R"(
#pragma region GENCPP IMPLEMENTATION GUARD
#if defined(GEN_IMPLEMENTATION) && ! defined(GEN_IMPLEMENTED)
# define GEN_IMPLEMENTED
)");
constexpr StrC implementation_guard_end = txt(R"(
#endif
#pragma endregion GENCPP IMPLEMENTATION GUARD
)");
constexpr StrC roll_own_dependencies_guard_start = txt(R"(
//! If its desired to roll your own dependencies, define GEN_ROLL_OWN_DEPENDENCIES before including this file.
// Dependencies are derived from the c-zpl library: https://github.com/zpl-c/zpl
#ifndef GEN_ROLL_OWN_DEPENDENCIES
)");
constexpr StrC roll_own_dependencies_guard_end = txt(R"(
// GEN_ROLL_OWN_DEPENDENCIES
#endif
)");
global bool generate_gen_dep = true;
global bool generate_builder = true;
global bool generate_editor = true;
global bool generate_scanner = true;
int gen_main()
{
#define project_dir "../project/"
gen::init();
Code push_ignores = scan_file( project_dir "helpers/push_ignores.inline.hpp" );
Code pop_ignores = scan_file( project_dir "helpers/pop_ignores.inline.hpp" );
Code ue_forceinline = code_str(FORCEINLINE);
// Code
// gen_dep.hpp
{
CodeBody header_start = def_body( CodeT::Global_Body );
{
FileContents content = file_read_contents( GlobalAllocator, true, project_dir "dependencies/header_start.hpp" );
CodeBody ori_header_start = parse_global_body( StrC { content.size, (char const*)content.data });
for (Code code = ori_header_start.begin();
code != ori_header_start.end();
++ code )
{
header_start.append(code);
if (code->Type == CodeT::Preprocess_Pragma && code->Content.starts_with(txt("once")))
{
header_start.append( fmt_newline );
header_start.append( push_ignores );
}
}
}
CodeBody macros = def_body( CodeT::Global_Body );
{
FileContents content = file_read_contents( GlobalAllocator, true, project_dir "dependencies/macros.hpp" );
CodeBody ori_macros = parse_global_body( StrC { content.size, (char const*)content.data });
for (Code code = ori_macros.begin();
code != ori_macros.end();
++ code )
{
switch (code->Type)
{
using namespace ECode;
case Preprocess_Define:
{
CodeDefine define = code.cast<CodeDefine>();
if ( define->Name.starts_with(txt("global")) )
{
macros.append(parse_global_body(txt("#define global // Global variables")));
continue;
}
macros.append(define);
}
break;
case Preprocess_Pragma:
{
macros.append(code);
continue;
local_persist bool found = false;
if (found)
{
macros.append(code);
continue;
}
if (code->Content.starts_with(txt("region ForceInline Definition")))
{
macros.append(code);
++ code;
CodeBody replacement = parse_global_body(StrC(txt(
R"(#ifdef GEN_COMPILER_MSVC
#define FORCEINLINE __forceinline
#define neverinline __declspec( noinline )
#elif defined( GEN_COMPILER_GCC )
#define FORCEINLINE inline __attribute__( ( __always_inline__ ) )
#define neverinline __attribute__( ( __noinline__ ) )
#elif defined( GEN_COMPILER_CLANG )
#if __has_attribute( __always_inline__ )
#define FORCEINLINE inline __attribute__( ( __always_inline__ ) )
#define neverinline __attribute__( ( __noinline__ ) )
#else
#define FORCEINLINE
#define neverinline
#endif
#else
#define FORCEINLINE
#define neverinline
#endif)")));
macros.append(replacement);
while (code->Type != ECode::Preprocess_Pragma
|| ! code->Content.starts_with(txt("endregion ForceInline Definition")))
++ code;
macros.append( code );
found = true;
}
}
break;
default:
macros.append(code);
break;
}
}
}
Code basic_types = scan_file( project_dir "dependencies/basic_types.hpp" );
Code debug = scan_file( project_dir "dependencies/debug.hpp" );
Code memory = scan_file( project_dir "dependencies/memory.hpp" );
Code string_ops = scan_file( project_dir "dependencies/string_ops.hpp" );
Code printing = scan_file( project_dir "dependencies/printing.hpp" );
Code containers = scan_file( project_dir "dependencies/containers.hpp" );
Code hashing = scan_file( project_dir "dependencies/hashing.hpp" );
Code strings = scan_file( project_dir "dependencies/strings.hpp" );
Code filesystem = scan_file( project_dir "dependencies/filesystem.hpp" );
Code timing = scan_file( project_dir "dependencies/timing.hpp" );
Builder
header = Builder::open("gen/gen.dep.hpp");
header.print_fmt( generation_notice );
header.print( header_start );
header.print_fmt( "\nGEN_NS_BEGIN\n" );
header.print( macros );
header.print( basic_types );
header.print( debug );
header.print( memory );
header.print( string_ops );
header.print( printing );
header.print( containers );
header.print( hashing );
header.print( strings );
header.print( filesystem );
header.print( timing );
header.print_fmt( "\nGEN_NS_END\n" );
header.print( fmt_newline );
header.print( pop_ignores );
header.write();
}
// gen_dep.cpp
{
Code src_start = scan_file( project_dir "dependencies/src_start.cpp" );
Code debug = scan_file( project_dir "dependencies/debug.cpp" );
Code string_ops = scan_file( project_dir "dependencies/string_ops.cpp" );
Code printing = scan_file( project_dir "dependencies/printing.cpp" );
Code memory = scan_file( project_dir "dependencies/memory.cpp" );
Code hashing = scan_file( project_dir "dependencies/hashing.cpp" );
Code strings = scan_file( project_dir "dependencies/strings.cpp" );
Code filesystem = scan_file( project_dir "dependencies/filesystem.cpp" );
Code timing = scan_file( project_dir "dependencies/timing.cpp" );
Builder
src = Builder::open( "gen/gen.dep.cpp" );
src.print_fmt( generation_notice );
src.print( def_include(txt("gen.dep.hpp")));
src.print( fmt_newline );
src.print( push_ignores );
src.print( src_start );
src.print_fmt( "\nGEN_NS_BEGIN\n" );
src.print( debug );
src.print( string_ops );
src.print( printing );
src.print( hashing );
src.print( memory );
src.print( strings );
src.print( filesystem );
src.print( timing );
src.print_fmt( "\nGEN_NS_END\n" );
src.print( fmt_newline );
src.print( pop_ignores );
src.write();
}
// gen.hpp
{
Code header_start = scan_file( "components/header_start.hpp" );
Code types = scan_file( project_dir "components/types.hpp" );
Code ast = scan_file( project_dir "components/ast.hpp" );
Code ast_types = scan_file( project_dir "components/ast_types.hpp" );
Code code_types = scan_file( project_dir "components/code_types.hpp" );
Code interface = scan_file( project_dir "components/interface.hpp" );
Code inlines = scan_file( project_dir "components/inlines.hpp" );
Code header_end = scan_file( project_dir "components/header_end.hpp" );
CodeBody ecode = gen_ecode ( project_dir "enums/ECode.csv" );
CodeBody eoperator = gen_eoperator ( project_dir "enums/EOperator.csv" );
CodeBody especifier = gen_especifier( project_dir "enums/ESpecifier.csv" );
CodeBody ast_inlines = gen_ast_inlines();
Builder
header = Builder::open( "gen/gen.hpp" );
header.print_fmt( generation_notice );
header.print_fmt( "#pragma once\n\n" );
header.print( push_ignores );
header.print( fmt_newline );
header.print( header_start );
header.print_fmt( "\nGEN_NS_BEGIN\n\n" );
header.print_fmt( "#pragma region Types\n" );
header.print( types );
header.print( ecode );
header.print( eoperator );
header.print( especifier );
header.print_fmt( "#pragma endregion Types\n\n" );
header.print_fmt( "#pragma region AST\n" );
header.print( ast );
header.print( code_types );
header.print( ast_types );
header.print_fmt( "\n#pragma endregion AST\n" );
header.print( interface );
header.print_fmt( "\n#pragma region Inlines\n" );
header.print( inlines );
header.print( fmt_newline );
header.print( ast_inlines );
header.print_fmt( "#pragma endregion Inlines\n" );
header.print( header_end );
header.print_fmt( "GEN_NS_END\n\n" );
header.print( pop_ignores );
header.write();
}
// gen.cpp
{
Code src_start = scan_file( "components/src_start.cpp" );
Code static_data = scan_file( project_dir "components/static_data.cpp" );
Code ast_case_macros = scan_file( project_dir "components/ast_case_macros.cpp" );
Code ast = scan_file( project_dir "components/ast.cpp" );
Code code_serialization = scan_file( project_dir "components/code_serialization.cpp" );
Code interface = scan_file( project_dir "components/interface.cpp" );
Code upfront = scan_file( project_dir "components/interface.upfront.cpp" );
Code lexer = scan_file( project_dir "components/lexer.cpp" );
Code parser = scan_file( project_dir "components/parser.cpp" );
Code parsing_interface = scan_file( project_dir "components/interface.parsing.cpp" );
Code untyped = scan_file( project_dir "components/interface.untyped.cpp" );
// Note(Ed): The Attribute tokens need to be expanded and regenerated on a per-project/installation of this library for a specific codebase of Unreal.
// We can support an arbitrary set of modules or plugin apis for parsing
// but its up to the user to define them all (This will just provide whats I've used up till now).
CodeBody etoktype = gen_etoktype( project_dir "enums/ETokType.csv", "enums/AttributeTokens.csv" );
CodeNS nspaced_etoktype = def_namespace( name(parser), def_namespace_body( args(etoktype)) );
Builder
src = Builder::open( "gen/gen.cpp" );
src.print_fmt( generation_notice );
src.print( push_ignores );
src.print( fmt_newline );
src.print( src_start );
src.print( fmt_newline );
src.print_fmt( "GEN_NS_BEGIN\n");
src.print( static_data );
src.print_fmt( "\n#pragma region AST\n\n" );
src.print( ast_case_macros );
src.print( ast );
src.print( code_serialization );
src.print_fmt( "\n#pragma endregion AST\n" );
src.print_fmt( "\n#pragma region Interface\n" );
src.print( interface );
src.print( upfront );
src.print_fmt( "\n#pragma region Parsing\n\n" );
src.print( nspaced_etoktype );
src.print( lexer );
src.print( parser );
src.print( parsing_interface );
src.print( untyped );
src.print_fmt( "\n#pragma endregion Parsing\n\n" );
src.print_fmt( "#pragma endregion Interface\n\n" );
src.print_fmt( "GEN_NS_END\n\n");
src.print( pop_ignores );
src.write();
}
// gen_builder.hpp
{
Code builder = scan_file( project_dir "auxillary/builder.hpp" );
Builder
header = Builder::open( "gen/gen.builder.hpp" );
header.print_fmt( generation_notice );
header.print( push_ignores );
header.print( fmt_newline );
header.print_fmt( "#pragma once\n\n" );
header.print( def_include( txt("gen.hpp") ));
header.print_fmt( "\nGEN_NS_BEGIN\n" );
header.print( builder );
header.print_fmt( "GEN_NS_END\n" );
header.print( fmt_newline );
header.print( pop_ignores );
header.write();
}
// gen_builder.cpp
{
Code builder = scan_file( project_dir "auxillary/builder.cpp" );
Builder
src = Builder::open( "gen/gen.builder.cpp" );
src.print_fmt( generation_notice );
src.print( push_ignores );
src.print( fmt_newline );
src.print( def_include( txt("gen.builder.hpp") ) );
src.print_fmt( "\nGEN_NS_BEGIN\n" );
src.print( builder );
src.print_fmt( "\nGEN_NS_END\n" );
src.print( fmt_newline );
src.print( pop_ignores );
src.write();
}
// gen_scanner.hpp
{
Code parsing = scan_file( project_dir "dependencies/parsing.hpp" );
Code scanner = scan_file( project_dir "auxillary/scanner.hpp" );
Builder
header = Builder::open( "gen/gen.scanner.hpp" );
header.print_fmt( generation_notice );
header.print_fmt( "#pragma once\n\n" );
header.print( push_ignores );
header.print( fmt_newline );
header.print( def_include( txt("gen.hpp") ) );
header.print_fmt( "\nGEN_NS_BEGIN\n" );
header.print( parsing );
header.print( scanner );
header.print_fmt( "GEN_NS_END\n" );
header.print( fmt_newline );
header.print( pop_ignores );
header.write();
}
// gen.scanner.cpp
{
Code parsing = scan_file( project_dir "dependencies/parsing.cpp" );
Code scanner = scan_file( project_dir "auxillary/scanner.cpp" );
Builder
src = Builder::open( "gen/gen.scanner.cpp" );
src.print_fmt( generation_notice );
src.print( push_ignores );
src.print( fmt_newline );
src.print( def_include( txt("gen.scanner.hpp") ) );
src.print_fmt( "\nGEN_NS_BEGIN\n" );
src.print( parsing );
// src.print( scanner );
src.print_fmt( "GEN_NS_END\n" );
src.print( fmt_newline );
src.print( pop_ignores );
src.write();
}
}