11 Commits

Author SHA1 Message Date
Ed_
00df336610 fix type on parser namespace in singleheader.cpp 2024-10-26 18:42:23 -04:00
Ed_
d89c9a6072 de-hardcode target_arch.psm1 import 2024-10-25 13:11:21 -04:00
Ed_
6aa99ac1d5 change how path_root is resolved so it works when cloned into another repository 2024-10-25 13:07:39 -04:00
Ed_
3989f5fa83 formatting and removing unused code 2024-10-25 12:54:55 -04:00
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
Ed_
e1592ba410 Bug fixes and updates to package_release.ps1
- Incrased size of the defines_map_arena to 256KB
- Various fixes for the parser
- Various fixes for code serialization
- Fix for is_equal member func in Code types
- Fixes for hasthable container
- Added are_equal static func to String type for use against StrC
- Added starts_with functions to String type
- package_release.ps1 now packages all docs (forgot to update it with last release)
2024-05-05 21:53:22 -04:00
41 changed files with 1432 additions and 631 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

@ -10,7 +10,9 @@ Its not meant to be a black box metaprogramming utility, it should be easy to in
## Notes ## Notes
**On Partial Hiatus: Working on handmade hero for now. Only fixes will be pushed as I come across them until I get what I want done from the series** **On Partial Hiatus: Life has got me tackling other issues..**
I will be passively updating the library with bug fixes and minor improvements as I use it for my personal projects.
There won't be any major reworks or features to this thing for a while.
This project is still in development (very much an alpha state), so expect bugs and missing features. This project is still in development (very much an alpha state), so expect bugs and missing features.
See [issues](https://github.com/Ed94/gencpp/issues) for a list of known bugs or todos. See [issues](https://github.com/Ed94/gencpp/issues) for a list of known bugs or todos.

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 +1,5 @@
#include "scanner.hpp" #ifdef GEN_INTELLISENSE_DIRECTIVES
# include "scanner.hpp"
#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

@ -139,7 +139,7 @@ void CodeConstructor::to_string_fwd( String& result )
if ( ast->InlineCmt ) if ( ast->InlineCmt )
result.append_fmt( "; // %S\n", ast->InlineCmt->Content ); result.append_fmt( "; // %S\n", ast->InlineCmt->Content );
else else
result.append( ";" ); result.append( ";\n" );
} }
String CodeClass::to_string() String CodeClass::to_string()
@ -183,7 +183,7 @@ void CodeClass::to_string_def( String& result )
while ( interface ) while ( interface )
{ {
result.append_fmt( ", %S", interface.to_string() ); result.append_fmt( ", %S", interface.to_string() );
interface = interface->Next ? interface->Next->cast< CodeType >() : Code { nullptr }; interface = interface->Next ? interface->Next->cast< CodeType >() : CodeType { nullptr };
} }
} }
else if ( ast->Name ) else if ( ast->Name )
@ -480,6 +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() );
bool prefix_specs = false;
if ( ast->Specs ) if ( ast->Specs )
{ {
for ( SpecifierT spec : ast->Specs ) for ( SpecifierT spec : ast->Specs )
@ -488,11 +489,13 @@ void CodeFn::to_string_def( String& result )
{ {
StrC spec_str = ESpecifier::to_str( spec ); StrC spec_str = ESpecifier::to_str( spec );
result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr ); result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr );
prefix_specs = true;
} }
} }
} }
if ( ast->Attributes || ast->Specs ) if ( ast->Attributes || prefix_specs )
result.append( "\n" ); result.append( "\n" );
if ( ast->ReturnType ) if ( ast->ReturnType )
@ -530,19 +533,22 @@ void CodeFn::to_string_fwd( 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;
if ( ast->Specs ) if ( ast->Specs )
{ {
for ( SpecifierT spec : ast->Specs ) for ( SpecifierT spec : ast->Specs )
{ {
if ( ESpecifier::is_trailing( spec ) && ! (spec != ESpecifier::Pure) ) if ( ! ESpecifier::is_trailing( spec ) || ! (spec != ESpecifier::Pure) )
{ {
StrC spec_str = ESpecifier::to_str( spec ); StrC spec_str = ESpecifier::to_str( spec );
result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr ); result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr );
prefix_specs = true;
} }
} }
} }
if ( ast->Attributes || ast->Specs ) if ( ast->Attributes || prefix_specs )
{ {
result.append("\n" ); result.append("\n" );
} }
@ -571,7 +577,7 @@ void CodeFn::to_string_fwd( String& result )
} }
} }
if ( ast->Specs.has( ESpecifier::Pure ) >= 0 ) if ( ast->Specs && ast->Specs.has( ESpecifier::Pure ) >= 0 )
result.append( " = 0;" ); result.append( " = 0;" );
else if (ast->Body) else if (ast->Body)
result.append_fmt( " = %S;", ast->Body.to_string() ); result.append_fmt( " = %S;", ast->Body.to_string() );
@ -758,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() );
@ -788,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() );
@ -841,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() );
@ -983,7 +1008,7 @@ void CodeStruct::to_string_def( String& result )
while ( interface ) while ( interface )
{ {
result.append_fmt( ", %S", interface.to_string() ); result.append_fmt( ", %S", interface.to_string() );
interface = interface->Next ? interface->Next->cast< CodeType >() : Code { nullptr }; interface = interface->Next ? interface->Next->cast< CodeType >() : CodeType { nullptr };
} }
} }
else if ( ast->Name ) else if ( ast->Name )
@ -1090,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 )
@ -1260,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;
} }
@ -1298,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
@ -1330,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

@ -88,17 +88,17 @@ void define_constants()
access_private = make_code(); access_private = make_code();
access_private->Type = ECode::Access_Private; access_private->Type = ECode::Access_Private;
access_private->Name = get_cached_string( txt("private:") ); access_private->Name = get_cached_string( txt("private:\n") );
access_private.set_global(); access_private.set_global();
access_protected = make_code(); access_protected = make_code();
access_protected->Type = ECode::Access_Protected; access_protected->Type = ECode::Access_Protected;
access_protected->Name = get_cached_string( txt("protected:") ); access_protected->Name = get_cached_string( txt("protected:\n") );
access_protected.set_global(); access_protected.set_global();
access_public = make_code(); access_public = make_code();
access_public->Type = ECode::Access_Public; access_public->Type = ECode::Access_Public;
access_public->Name = get_cached_string( txt("public:") ); access_public->Name = get_cached_string( txt("public:\n") );
access_public.set_global(); access_public.set_global();
attrib_api_export = def_attributes( code(GEN_API_Export_Code)); attrib_api_export = def_attributes( code(GEN_API_Export_Code));
@ -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

@ -159,7 +159,7 @@ struct TokArray
} }
}; };
global Arena_128KB defines_map_arena; global Arena_256KB defines_map_arena;
global HashTable<StrC> defines; global HashTable<StrC> defines;
global Array<Token> Tokens; global Array<Token> Tokens;
@ -374,6 +374,16 @@ s32 lex_preprocessor_directive(
move_forward(); move_forward();
preprocess_content.Length++; preprocess_content.Length++;
if ( current == '\r' && scanner[1] == '\n' )
{
move_forward();
move_forward();
}
else if ( current == '\n' )
{
move_forward();
}
Tokens.append( preprocess_content ); Tokens.append( preprocess_content );
return Lex_Continue; // Skip found token, its all handled here. return Lex_Continue; // Skip found token, its all handled here.
} }
@ -576,7 +586,7 @@ TokArray lex( StrC content )
{ {
s32 length = 0; s32 length = 0;
char const* scanner = entry.Data; char const* scanner = entry.Data;
while ( entry.length() > length && char_is_alphanumeric( *scanner ) || *scanner == '_' ) while ( entry.length() > length && (char_is_alphanumeric( *scanner ) || *scanner == '_') )
{ {
scanner++; scanner++;
length ++; length ++;
@ -1192,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

@ -136,8 +136,8 @@ void init()
, ( LexAllocator_Size - sizeof( Array<Token>::Header ) ) / sizeof(Token) , ( LexAllocator_Size - sizeof( Array<Token>::Header ) ) / sizeof(Token)
); );
defines_map_arena = Arena_128KB::init(); defines_map_arena = Arena_256KB::init();
defines = HashTable<StrC>::init( defines_map_arena ); defines = HashTable<StrC>::init_reserve( defines_map_arena, 256 );
} }
internal internal
@ -554,40 +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::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()
{ {
@ -1345,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 );
@ -1373,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 )
{ {
@ -1403,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
@ -1539,18 +1538,18 @@ Code parse_function_body()
result->Type = Function_Body; result->Type = Function_Body;
// TODO : Support actual parsing of function body // TODO : Support actual parsing of function body
Token start = currtok; Token start = currtok_noskip;
s32 level = 0; s32 level = 0;
while ( left && ( currtok.Type != TokType::BraceCurly_Close || level > 0 ) ) while ( left && ( currtok_noskip.Type != TokType::BraceCurly_Close || level > 0 ) )
{ {
if ( currtok.Type == TokType::BraceCurly_Open ) if ( currtok_noskip.Type == TokType::BraceCurly_Open )
level++; level++;
else if ( currtok.Type == TokType::BraceCurly_Close && level > 0 ) else if ( currtok_noskip.Type == TokType::BraceCurly_Close && level > 0 )
level--; level--;
eat( currtok.Type ); eat( currtok_noskip.Type );
} }
Token previous = prevtok; Token previous = prevtok;
@ -1851,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;
} }
@ -2534,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 );
@ -2619,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 ) )
{ {
@ -2664,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)
@ -2683,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;
@ -2767,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)
@ -2786,11 +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() && CheckEndParams()) || (capture_level > 0 || template_level > 0) )
|| capture_level > 0 || template_level > 0 )
{ {
if (currtok.Text[ 0 ] == '<') if (currtok.Text[ 0 ] == '<')
++ template_level; ++ template_level;
@ -2824,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;
@ -2867,7 +2892,7 @@ CodePreprocessCond parse_preprocess_cond()
CodePreprocessCond CodePreprocessCond
cond = (CodePreprocessCond) make_code(); cond = (CodePreprocessCond) make_code();
cond->Type = scast(CodeT, currtok.Type - (ETokType::Preprocess_If - ECode::Preprocess_If) ); cond->Type = scast(CodeT, currtok.Type - ( TokType::Preprocess_If - ECode::Preprocess_If ) );
eat( currtok.Type ); eat( currtok.Type );
// #<Conditional> // #<Conditional>
@ -3062,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>
@ -3093,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 );
@ -3187,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;
} }
@ -3241,6 +3297,8 @@ CodeVar parse_variable_declaration_list()
break; break;
} }
// eat(currtok.Type);
if ( specifiers ) if ( specifiers )
specifiers.append( spec ); specifiers.append( spec );
else else
@ -3642,6 +3700,13 @@ CodeEnum parse_enum( bool inplace_def )
// <Name> = <Expression> <Macro>, // <Name> = <Expression> <Macro>,
} }
// Consume inline comments
// if ( currtok.Type == TokType::Comment && prevtok.Line == currtok.Line )
// {
// eat( TokType::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;
member = untyped_str( entry ); member = untyped_str( entry );
@ -4015,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 ) )
@ -4445,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();
@ -155,10 +160,10 @@ struct Array
{ {
Header& header = * get_header(); Header& header = * get_header();
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;
} }
@ -312,14 +317,12 @@ struct HashTable
Type Value; Type Value;
}; };
static constexpr f32 CriticalLoadScale = 0.7f;
static static
HashTable init( AllocatorInfo allocator ) HashTable init( AllocatorInfo allocator )
{ {
HashTable<Type> result = { { nullptr }, { nullptr } }; HashTable<Type> result = init_reserve(allocator, 8);
result.Hashes = Array<sw>::init( allocator );
result.Entries = Array<Entry>::init( allocator );
return result; return result;
} }
@ -330,19 +333,17 @@ struct HashTable
result.Hashes = Array<sw>::init_reserve( allocator, num ); result.Hashes = Array<sw>::init_reserve( allocator, num );
result.Hashes.get_header()->Num = num; result.Hashes.get_header()->Num = num;
result.Hashes.resize( num );
result.Hashes.fill( 0, num, -1);
result.Entries = Array<Entry>::init_reserve( allocator, num ); result.Entries = Array<Entry>::init_reserve( allocator, num );
return result; return result;
} }
void clear( void ) void clear( void )
{ {
for ( sw idx = 0; idx < Hashes.num(); idx++ )
Hashes[ idx ] = -1;
Hashes.clear();
Entries.clear(); Entries.clear();
Hashes.fill( 0, Hashes.num(), -1);
} }
void destroy( void ) void destroy( void )
@ -369,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 );
} }
@ -381,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 );
} }
@ -395,32 +396,19 @@ struct HashTable
void rehash( sw new_num ) void rehash( sw new_num )
{ {
sw idx;
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 < sw(Entries.num()); ++idx )
Array<sw>::Header* hash_header = new_ht.Hashes.get_header();
for ( idx = 0; idx < new_ht.Hashes.num(); ++idx )
new_ht.Hashes[ idx ] = -1;
for ( idx = 0; idx < Entries.num(); ++idx )
{ {
Entry& entry = Entries[ idx ];
FindResult find_result; FindResult find_result;
if ( new_ht.Hashes.num() == 0 ) Entry& entry = Entries[ idx ];
new_ht.grow();
entry = Entries[ idx ];
find_result = new_ht.find( entry.Key ); find_result = new_ht.find( entry.Key );
last_added_index = new_ht.add_entry( entry.Key ); last_added_index = new_ht.add_entry( entry.Key );
if ( find_result.PrevIndex < 0 ) if ( find_result.PrevIndex < 0 )
new_ht.Hashes[ find_result.HashIndex ] = last_added_index; new_ht.Hashes[ find_result.HashIndex ] = last_added_index;
else else
new_ht.Entries[ find_result.PrevIndex ].Next = last_added_index; new_ht.Entries[ find_result.PrevIndex ].Next = last_added_index;
@ -436,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;
@ -478,11 +466,10 @@ struct HashTable
sw idx; sw idx;
FindResult find_result; FindResult find_result;
if ( Hashes.num() == 0 ) if ( full() )
grow(); grow();
find_result = find( key ); find_result = find( key );
if ( find_result.EntryIndex >= 0 ) if ( find_result.EntryIndex >= 0 )
{ {
idx = find_result.EntryIndex; idx = find_result.EntryIndex;
@ -509,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;
@ -555,7 +542,9 @@ protected:
b32 full() b32 full()
{ {
return 0.75f * Hashes.num() < Entries.num(); uw critical_load = uw( CriticalLoadScale * f32(Hashes.num()) );
b32 result = Entries.num() > critical_load;
return result;
} }
}; };

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

@ -11,15 +11,14 @@ struct StrC
sw Len; sw Len;
char const* Ptr; char const* Ptr;
operator char const* () const operator char const* () const { return Ptr; }
{ char const& operator[]( sw index ) const { return Ptr[index]; }
return Ptr;
}
}; };
#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 };
@ -99,6 +98,19 @@ struct String
return true; return true;
} }
static
bool are_equal( String lhs, StrC rhs )
{
if ( lhs.length() != (rhs.Len) )
return false;
for ( sw idx = 0; idx < lhs.length(); ++idx )
if ( lhs[idx] != rhs[idx] )
return false;
return true;
}
bool make_space_for( char const* str, sw add_len ); bool make_space_for( char const* str, sw add_len );
bool append( char c ) bool append( char c )
@ -128,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)
@ -197,6 +209,24 @@ struct String
return header.Length; return header.Length;
} }
b32 starts_with( StrC substring ) const
{
if (substring.Len > length())
return false;
b32 result = str_compare(Data, substring.Ptr, substring.Len ) == 0;
return result;
}
b32 starts_with( String substring ) const
{
if (substring.length() > length())
return false;
b32 result = str_compare(Data, substring, substring.length() - 1 ) == 0;
return result;
}
void skip_line() void skip_line()
{ {
#define current (*scanner) #define current (*scanner)
@ -324,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,20 +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 )
{ {
log_failure("Code::is_equal: Cannot compare code, AST is null!"); // Just check if they're both null.
return false; // 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 )
@ -380,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 )
@ -391,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;
@ -406,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 )
@ -481,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,6 +1,7 @@
#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 "-Wswitch" # pragma clang diagnostic ignored "-Wswitch"
# pragma clang diagnostic ignored "-Wunused-variable" # pragma clang diagnostic ignored "-Wunused-variable"
# pragma clang diagnostic ignored "-Wunknown-pragmas" # pragma clang diagnostic ignored "-Wunknown-pragmas"
@ -8,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

@ -2,14 +2,36 @@
# It will most likely need a partial rewrite to segment the build process into separate script invocations based on the OS. # It will most likely need a partial rewrite to segment the build process into separate script invocations based on the OS.
# That or just rewrite it in an sh script and call it a day. # That or just rewrite it in an sh script and call it a day.
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'
$path_root = git rev-parse --show-toplevel Import-Module $target_arch
function Get-ScriptRepoRoot {
$currentPath = $PSScriptRoot
while ($currentPath -ne $null -and $currentPath -ne "")
{
if (Test-Path (Join-Path $currentPath ".git")) {
return $currentPath
}
# Also check for .git file which indicates a submodule
$gitFile = Join-Path $currentPath ".git"
if (Test-Path $gitFile -PathType Leaf)
{
$gitContent = Get-Content $gitFile
if ($gitContent -match "gitdir: (.+)") {
return $currentPath
}
}
$currentPath = Split-Path $currentPath -Parent
}
throw "Unable to find repository root"
}
$path_root = Get-ScriptRepoRoot
Import-Module $target_arch Import-Module $target_arch
Import-Module $format_cpp Import-Module $format_cpp
@ -22,6 +44,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 +59,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 +88,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 +104,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 +187,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 +294,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 +316,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
@ -26,15 +28,21 @@ if ( -not(Test-Path $path_release_content) ) {
New-Item -ItemType Directory -Path $path_release_content New-Item -ItemType Directory -Path $path_release_content
} }
$license = Join-Path $path_root LICENSE $license = Join-Path $path_root LICENSE
$readme_root = Join-Path $path_root Readme.md $readme_root = Join-Path $path_root Readme.md
$readme_docs = Join-Path $path_docs Readme.md $readme_docs = Join-Path $path_docs Readme.md
$readme_parsing = Join-Path $path_docs Parsing.md $readme_ast_design = Join-Path $path_docs AST_Design.md
$readme_ast_types = Join-Path $path_docs AST_Types.md
$readme_parsing = Join-Path $path_docs Parsing.md
$readme_parser_algo = Join-Path $path_docs Parser_Algo.md
Copy-Item $license -Destination (Join-Path $path_release_content "LICENSE") Copy-Item $license -Destination (Join-Path $path_release_content "LICENSE")
Copy-Item $readme_root -Destination (Join-Path $path_release_content "Readme.md") Copy-Item $readme_root -Destination (Join-Path $path_release_content "Readme.md")
Copy-Item $readme_docs -Destination (Join-Path $path_release_content "Readme_Docs.md") Copy-Item $readme_docs -Destination (Join-Path $path_release_content "Readme_Docs.md")
Copy-Item $readme_parsing -Destination (Join-Path $path_release_content "Parsing.md") Copy-Item $readme_ast_design -Destination (Join-Path $path_release_content "AST_Design.md")
Copy-Item $readme_ast_types -Destination (Join-Path $path_release_content "AST_Types.md")
Copy-Item $readme_parsing -Destination (Join-Path $path_release_content "Parsing.md")
Copy-Item $readme_parser_algo -Destination (Join-Path $path_release_content "Parser_Algo.md")
# Singleheader # Singleheader
Copy-Item -Path $path_singleheader_gen\gen.hpp -Destination $path_release_content\gen.hpp Copy-Item -Path $path_singleheader_gen\gen.hpp -Destination $path_release_content\gen.hpp
@ -44,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

View File

@ -209,7 +209,7 @@ int gen_main()
Code untyped = scan_file( project_dir "components/interface.untyped.cpp" ); Code untyped = scan_file( project_dir "components/interface.untyped.cpp" );
CodeBody etoktype = gen_etoktype( project_dir "enums/ETokType.csv", project_dir "enums/AttributeTokens.csv" ); CodeBody etoktype = gen_etoktype( project_dir "enums/ETokType.csv", project_dir "enums/AttributeTokens.csv" );
CodeNS parser_nspace = def_namespace( name(Parser), def_namespace_body( args(etoktype)) ); CodeNS parser_nspace = def_namespace( name(parser), def_namespace_body( args(etoktype)) );
header.print_fmt( "\nGEN_NS_BEGIN\n"); header.print_fmt( "\nGEN_NS_BEGIN\n");
header.print( static_data ); header.print( static_data );

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
COREUOBJECT_API, COREUOBJECT_API
ENGINE_API, ENGINE_API
GAMEPLAYABILITIES_API, GAMEPLAYABILITIES_API
UMG_API, UMG_API
UE_DEPRECATED, UE_DEPRECATED
1 API_Export GEN_API_Export_Code
2 API_Import GEN_API_Import_Code
3 COREUOBJECT_API COREUOBJECT_API
4 ENGINE_API ENGINE_API
5 GAMEPLAYABILITIES_API GAMEPLAYABILITIES_API
6 UMG_API UMG_API
7 UE_DEPRECATED UE_DEPRECATED

368
unreal_engine/unreal.cpp Normal file
View File

@ -0,0 +1,368 @@
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#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;
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();
}
}