mirror of
https://github.com/Ed94/gencpp.git
synced 2025-06-14 18:51:47 -07:00
Updated readme, added def_body and AST::validate_body
Fixed meson first setup error with missing thirdparty dir (removed it since its no longer used) Improved SOA test to use newly added funtions.
This commit is contained in:
@ -8,24 +8,6 @@ All dependencies are currently held within `Bloat.hpp` and `Bloat.cpp`
|
||||
|
||||
All the library code is contained in two files: `gen.hpp` and `gen.cpp`
|
||||
|
||||
|
||||
## Bloat.hpp/cpp
|
||||
|
||||
Currently acts as the isolation header for thridparty dependencies along with code not directly related to the library.
|
||||
|
||||
Organization:
|
||||
|
||||
* ZPL inclusion and selective symbol exposure to global scope.
|
||||
* Utility macro definitions used throughout the library.
|
||||
* Global memory arena definition
|
||||
* StrC and String definitions
|
||||
* Token string formatter
|
||||
* Formatted and Fatal Logs
|
||||
|
||||
The cpp contains the implementation of the global memory arena and the token formmatter.
|
||||
|
||||
Any global symbol pollution will be removed when dependencies are intergrated properly into the library.
|
||||
|
||||
## gen.hpp
|
||||
|
||||
While getting fleshed out, all feature macros are defined on the top of the header.
|
||||
|
122
project/gen.cpp
122
project/gen.cpp
@ -2795,6 +2795,114 @@ namespace gen
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AST::validate_body()
|
||||
{
|
||||
using namespace ECode;
|
||||
#define CheckBodyType( BodyType ) \
|
||||
if ( Type != BodyType ) \
|
||||
{ \
|
||||
log_failure( "AST::validate_body: Invalid body type %s", debug_str() ); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define CheckEntries( Unallowed_Types ) \
|
||||
do \
|
||||
{ \
|
||||
for ( s32 idx = 0; idx < num_entries(); idx++ ) \
|
||||
{ \
|
||||
AST* elem = entry( idx ); \
|
||||
\
|
||||
switch ( elem->Type ) \
|
||||
{ \
|
||||
Unallowed_Types \
|
||||
log_failure( "AST::validate_body: Invalid entry in body %s", elem->debug_str() ); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
while (0);
|
||||
|
||||
switch ( Type )
|
||||
{
|
||||
case Class_Body:
|
||||
CheckBodyType( Class_Body );
|
||||
CheckEntries( AST_BODY_CLASS_UNALLOWED_TYPES );
|
||||
break;
|
||||
case Enum_Body:
|
||||
CheckBodyType( Enum_Body );
|
||||
for ( s32 idx = 0; idx < body()->num_entries(); idx++ )
|
||||
{
|
||||
AST* elem = entry( idx );
|
||||
|
||||
if ( elem->Type != Untyped )
|
||||
{
|
||||
log_failure( "AST::validate_body: Invalid entry in enum body (needs to be untyped or comment) %s", elem->debug_str() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Export_Body:
|
||||
for ( s32 idx = 0; idx < num_entries(); idx++ )
|
||||
{
|
||||
AST* elem = entry( idx );
|
||||
|
||||
if ( elem->Type != Untyped )
|
||||
{
|
||||
log_failure( "AST::validate_body: Invalid entry in export body %s", elem->debug_str() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Extern_Linkage:
|
||||
CheckBodyType( Extern_Linkage );
|
||||
CheckEntries( AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES );
|
||||
break;
|
||||
case Function_Body:
|
||||
CheckBodyType( Function_Body );
|
||||
CheckEntries( AST_BODY_FUNCTION_UNALLOWED_TYPES );
|
||||
break;
|
||||
case Global_Body:
|
||||
for ( s32 idx = 0; idx < num_entries(); idx++ )
|
||||
{
|
||||
AST* elem = entry( idx );
|
||||
|
||||
if ( elem->Type != Untyped )
|
||||
{
|
||||
log_failure( "AST::validate_body: Invalid entry in global body %s", elem->debug_str() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Namespace_Body:
|
||||
CheckBodyType( Namespace_Body );
|
||||
CheckEntries( AST_BODY_NAMESPACE_UNALLOWED_TYPES );
|
||||
break;
|
||||
case Struct_Body:
|
||||
CheckBodyType( Struct_Body );
|
||||
CheckEntries( AST_BODY_STRUCT_UNALLOWED_TYPES );
|
||||
break;
|
||||
case Union_Body:
|
||||
CheckBodyType( Union_Body );
|
||||
for ( s32 idx = 0; idx < body()->num_entries(); idx++ )
|
||||
{
|
||||
AST* elem = entry( idx );
|
||||
|
||||
if ( elem->Type != Untyped )
|
||||
{
|
||||
log_failure( "AST::validate_body: Invalid entry in union body (needs to be untyped or comment) %s", elem->debug_str() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log_failure( "AST::validate_body: Invalid this AST does not have a body %s", debug_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#pragma endregion AST
|
||||
|
||||
#pragma region Gen Interface
|
||||
@ -4404,7 +4512,7 @@ namespace gen
|
||||
\
|
||||
if ( codes == nullptr ) \
|
||||
{ \
|
||||
log_failure("gen::def_class_body: Provided a null array of codes"); \
|
||||
log_failure("gen::" stringize(Name_)" : Provided a null array of codes"); \
|
||||
return Code::Invalid; \
|
||||
}
|
||||
|
||||
@ -4504,9 +4612,9 @@ namespace gen
|
||||
return Code::Invalid;
|
||||
}
|
||||
|
||||
if ( entry->Type != Untyped )
|
||||
if ( entry->Type != Untyped && entry->Type != Comment )
|
||||
{
|
||||
log_failure("gen::def_enum_body: Entry type is not allowed - %s. Must be of untyped type.", entry->debug_str() ); \
|
||||
log_failure("gen::def_enum_body: Entry type is not allowed - %s. Must be of untyped or comment type.", entry->debug_str() ); \
|
||||
return Code::Invalid;
|
||||
}
|
||||
|
||||
@ -4536,7 +4644,7 @@ namespace gen
|
||||
return Code::Invalid;
|
||||
}
|
||||
|
||||
if ( entry->Type != Untyped )
|
||||
if ( entry->Type != Untyped && entry->Type != Comment )
|
||||
{
|
||||
log_failure("gen::def_enum_body: Entry type is not allowed: %s", entry->debug_str() ); \
|
||||
return Code::Invalid;
|
||||
@ -4906,7 +5014,7 @@ namespace gen
|
||||
|
||||
if ( entry->Type != Untyped && entry->Type != Comment )
|
||||
{
|
||||
log_failure("gen::def_union_body: Entry type is not allowed - %s. Must be of untyped type.", entry->debug_str() ); \
|
||||
log_failure("gen::def_union_body: Entry type is not allowed - %s. Must be of untyped or comment type.", entry->debug_str() ); \
|
||||
return Code::Invalid;
|
||||
}
|
||||
|
||||
@ -4936,7 +5044,7 @@ namespace gen
|
||||
return Code::Invalid;
|
||||
}
|
||||
|
||||
if ( entry->Type != Untyped )
|
||||
if ( entry->Type != Untyped && entry->Type != Comment )
|
||||
{
|
||||
log_failure("gen::def_union_body: Entry type is not allowed: %s", entry->debug_str() ); \
|
||||
return Code::Invalid;
|
||||
@ -8099,7 +8207,7 @@ namespace gen
|
||||
#pragma region Builder
|
||||
void Builder::print( Code code )
|
||||
{
|
||||
Buffer.append_fmt( "%s\n", code.to_string() );
|
||||
Buffer.append_fmt( "%s\n", code->to_string() );
|
||||
}
|
||||
|
||||
void Builder::print_fmt( char const* fmt, ... )
|
||||
|
266
project/gen.hpp
266
project/gen.hpp
@ -2666,6 +2666,61 @@ namespace gen
|
||||
// Desired width of the AST data structure.
|
||||
constexpr u32 AST_POD_Size = 256;
|
||||
|
||||
struct AST;
|
||||
|
||||
/*
|
||||
AST* typedef as to not constantly have to add the '*' as this is written often..
|
||||
*/
|
||||
struct Code
|
||||
{
|
||||
# pragma region Statics
|
||||
// Used to identify ASTs that should always be duplicated. (Global constant ASTs)
|
||||
static Code Global;
|
||||
|
||||
// Used to identify invalid generated code.
|
||||
static Code Invalid;
|
||||
# pragma endregion Statics
|
||||
|
||||
# pragma region Member Functions
|
||||
void set_global();
|
||||
|
||||
bool is_valid();
|
||||
|
||||
bool operator ==( Code other )
|
||||
{
|
||||
return ast == other.ast;
|
||||
}
|
||||
|
||||
bool operator !=( Code other )
|
||||
{
|
||||
return ast != other.ast;
|
||||
}
|
||||
|
||||
operator AST*()
|
||||
{
|
||||
return ast;
|
||||
}
|
||||
|
||||
AST* operator->()
|
||||
{
|
||||
if ( ast == nullptr )
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ast;
|
||||
}
|
||||
# pragma endregion Member Functions
|
||||
|
||||
AST* ast;
|
||||
};
|
||||
|
||||
struct Code_POD
|
||||
{
|
||||
AST* ast;
|
||||
};
|
||||
|
||||
// TODO: If perf needs it, convert layout an SOA format.
|
||||
/*
|
||||
Simple AST POD with functionality to seralize into C++ syntax.
|
||||
@ -2679,6 +2734,9 @@ namespace gen
|
||||
struct AST
|
||||
{
|
||||
# pragma region Member Functions
|
||||
// add_entry with validation
|
||||
void add( AST* other );
|
||||
|
||||
void add_entry( AST* other );
|
||||
|
||||
AST* body()
|
||||
@ -2688,7 +2746,7 @@ namespace gen
|
||||
|
||||
AST* duplicate();
|
||||
|
||||
AST*& entry( u32 idx )
|
||||
AST* entry( u32 idx )
|
||||
{
|
||||
return DynamicEntries ? ArrDyn[ idx ] : ArrStatic[ idx ];
|
||||
}
|
||||
@ -2698,11 +2756,6 @@ namespace gen
|
||||
return num_entries();
|
||||
}
|
||||
|
||||
bool is_invalid()
|
||||
{
|
||||
return Type != ECode::Invalid;
|
||||
}
|
||||
|
||||
bool is_equal( AST* other );
|
||||
|
||||
s32 num_entries()
|
||||
@ -2799,12 +2852,16 @@ namespace gen
|
||||
);
|
||||
}
|
||||
|
||||
String to_string();
|
||||
|
||||
char const* type_str()
|
||||
{
|
||||
return ECode::to_str( Type );
|
||||
}
|
||||
|
||||
String to_string();
|
||||
bool validate_body();
|
||||
|
||||
operator Code();
|
||||
# pragma endregion Member Functions
|
||||
|
||||
constexpr static
|
||||
@ -2852,106 +2909,10 @@ namespace gen
|
||||
|
||||
// Its intended for the AST to have equivalent size to its POD.
|
||||
// All extra functionality within the AST namespace should just be syntatic sugar.
|
||||
static_assert( sizeof(Code) == sizeof(Code_POD), "ERROR: Code is not POD" );
|
||||
static_assert( sizeof(AST) == sizeof(AST_POD), "ERROR: AST IS NOT POD" );
|
||||
static_assert( sizeof(AST_POD) == AST_POD_Size, "ERROR: AST POD is not size of AST_POD_Size" );
|
||||
|
||||
/*
|
||||
AST* typedef as to not constantly have to add the '*' as this is written often..
|
||||
*/
|
||||
struct Code
|
||||
{
|
||||
# pragma region Statics
|
||||
// Used to identify ASTs that should always be duplicated. (Global constant ASTs)
|
||||
static Code Global;
|
||||
|
||||
// Used to identify invalid generated code.
|
||||
static Code Invalid;
|
||||
# pragma endregion Statics
|
||||
|
||||
# pragma region Member Functions
|
||||
Code body()
|
||||
{
|
||||
if ( ast == nullptr )
|
||||
{
|
||||
log_failure("Code::body: AST is null!");
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
if ( ast->Type == ECode::Invalid )
|
||||
{
|
||||
log_failure("Code::body: Type is invalid, cannot get");
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
return { ast->body() };
|
||||
}
|
||||
|
||||
String to_string() const
|
||||
{
|
||||
return ast->to_string();
|
||||
}
|
||||
|
||||
void set_global()
|
||||
{
|
||||
if ( ast == nullptr )
|
||||
{
|
||||
log_failure("Code::set_global: Cannot set code as global, AST is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
ast->Parent = Global.ast;
|
||||
}
|
||||
|
||||
bool is_valid()
|
||||
{
|
||||
// Originally intended to use operator bool(), however for some reason
|
||||
// The C++ standard has operator Type*() with higher precedence than operator bool().
|
||||
// Even when directly casting to bool. Amazing.
|
||||
return ast != nullptr && ast->Type != ECode::Invalid;
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return ast != nullptr && ast->Type != ECode::Invalid;
|
||||
}
|
||||
|
||||
bool operator ==( Code other )
|
||||
{
|
||||
return ast == other.ast;
|
||||
}
|
||||
|
||||
bool operator !=( Code other )
|
||||
{
|
||||
return ast != other.ast;
|
||||
}
|
||||
|
||||
operator AST*()
|
||||
{
|
||||
return ast;
|
||||
}
|
||||
|
||||
AST* operator->()
|
||||
{
|
||||
if ( ast == nullptr )
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ast;
|
||||
}
|
||||
# pragma endregion Member Functions
|
||||
|
||||
AST* ast;
|
||||
};
|
||||
|
||||
struct Code_POD
|
||||
{
|
||||
AST_POD* ast;
|
||||
};
|
||||
|
||||
static_assert( sizeof(Code) == sizeof(Code_POD), "ERROR: Code is not POD" );
|
||||
|
||||
// Used when the its desired when omission is allowed in a definition.
|
||||
constexpr Code NoCode = { nullptr };
|
||||
#pragma endregion Data Structures
|
||||
@ -3051,8 +3012,11 @@ namespace gen
|
||||
, Code specifiers = NoCode, Code attributes = NoCode
|
||||
, ModuleFlag mflags = ModuleFlag::None );
|
||||
|
||||
Code def_class_body ( s32 num, ... );
|
||||
Code def_class_body ( s32 num, Code* codes );
|
||||
// There are two options for defining a struct body, either varadically provided with the args macro to auto-deduce the arg num,
|
||||
/// or provide as an array of Code objects.
|
||||
|
||||
Code def_class_body ( s32 num, ... );
|
||||
Code def_class_body ( s32 num, Code* codes );
|
||||
Code def_enum_body ( s32 num, ... );
|
||||
Code def_enum_body ( s32 num, Code* codes );
|
||||
Code def_export_body ( s32 num, ... );
|
||||
@ -3073,6 +3037,9 @@ namespace gen
|
||||
Code def_struct_body ( s32 num, Code* codes );
|
||||
Code def_union_body ( s32 num, ... );
|
||||
Code def_union_body ( s32 num, Code* codes );
|
||||
|
||||
// Constructs an empty body. Use AST::validate_body() to check if the body is was has valid entries.
|
||||
Code def_body( CodeT type );
|
||||
# pragma endregion Upfront
|
||||
|
||||
# pragma region Parsing
|
||||
@ -3098,24 +3065,8 @@ namespace gen
|
||||
# pragma endregion Parsing
|
||||
|
||||
# pragma region Untyped text
|
||||
sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va );
|
||||
|
||||
//! Do not use directly. Use the token_fmt macro instead.
|
||||
// Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string.
|
||||
inline
|
||||
StrC token_fmt_impl( sw num, ... )
|
||||
{
|
||||
local_persist thread_local
|
||||
char buf[GEN_PRINTF_MAXLEN] = { 0 };
|
||||
mem_set( buf, 0, GEN_PRINTF_MAXLEN );
|
||||
|
||||
va_list va;
|
||||
va_start(va, num );
|
||||
sw result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va);
|
||||
va_end(va);
|
||||
|
||||
return { result, buf };
|
||||
}
|
||||
sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va );
|
||||
StrC token_fmt_impl( sw, ... );
|
||||
|
||||
Code untyped_str ( StrC content);
|
||||
Code untyped_fmt ( char const* fmt, ... );
|
||||
@ -3383,6 +3334,73 @@ namespace gen
|
||||
|
||||
to_add->Parent = this;
|
||||
}
|
||||
|
||||
inline
|
||||
void Code::set_global()
|
||||
{
|
||||
if ( ast == nullptr )
|
||||
{
|
||||
log_failure("Code::set_global: Cannot set code as global, AST is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
ast->Parent = Global.ast;
|
||||
}
|
||||
|
||||
inline
|
||||
bool Code::is_valid()
|
||||
{
|
||||
return ast != nullptr && ast->Type != CodeT::Invalid;
|
||||
}
|
||||
|
||||
AST::operator gen::Code()
|
||||
{
|
||||
return { this };
|
||||
}
|
||||
|
||||
Code def_body( CodeT type )
|
||||
{
|
||||
switch ( type )
|
||||
{
|
||||
using namespace ECode;
|
||||
case Class_Body:
|
||||
case Enum_Body:
|
||||
case Export_Body:
|
||||
case Extern_Linkage:
|
||||
case Function_Body:
|
||||
case Global_Body:
|
||||
case Namespace_Body:
|
||||
case Struct_Body:
|
||||
case Union_Body:
|
||||
break;
|
||||
|
||||
default:
|
||||
log_failure( "def_body: Invalid type %s", (char const*)ECode::to_str(type) );
|
||||
return Code::Invalid;
|
||||
}
|
||||
|
||||
Code
|
||||
result = make_code();
|
||||
result->Type = type;
|
||||
return result;
|
||||
}
|
||||
|
||||
//! Do not use directly. Use the token_fmt macro instead.
|
||||
// Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string.
|
||||
inline
|
||||
StrC token_fmt_impl( sw num, ... )
|
||||
{
|
||||
local_persist thread_local
|
||||
char buf[GEN_PRINTF_MAXLEN] = { 0 };
|
||||
mem_set( buf, 0, GEN_PRINTF_MAXLEN );
|
||||
|
||||
va_list va;
|
||||
va_start(va, num );
|
||||
sw result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va);
|
||||
va_end(va);
|
||||
|
||||
return { result, buf };
|
||||
}
|
||||
}
|
||||
#pragma endregion Inlines
|
||||
|
||||
|
Reference in New Issue
Block a user