Removed incremental API, fixes for operator__validation, added formatting pass on generated files

Decided not to support the incremental API, its not necessary as the ergonomics are not that big a deal.

Got operators to pass the sanity base cases, which means now all upfront constructors pass the base cases!

Next up is getting it to pass the array container generation.
This commit is contained in:
Edward R. Gonzalez 2023-06-29 22:48:47 -04:00
parent 19e58fea30
commit 257e9ebf11
14 changed files with 329 additions and 846 deletions

View File

@ -93,24 +93,6 @@ Code header;
} }
``` ```
### Incremental
```cpp
// Types are done the same with upfront. Incremental does not have a full interface replacment.
// Get a Code AST from the CodePool.
Code header = make_struct( name(ArrayHeader) );
{
// Make a struct body.
Code body = header.body();
// Members
body->add( def_variable( t_uw, name(Num)) );
body->add( def_variable( t_uw, name(Capacity)) );
body->add( def_variable( t_allocator, name(Allocator)) );
}
```
### Parse ### Parse
```cpp ```cpp
@ -272,10 +254,9 @@ Data Notes:
* This library treats memory failures as fatal. * This library treats memory failures as fatal.
* Strings are stored in their own set of arenas. AST constructors use cached strings for names, and content. * Strings are stored in their own set of arenas. AST constructors use cached strings for names, and content.
## There are four sets of interfaces for Code AST generation the library provides ## There are three sets of interfaces for Code AST generation the library provides
* Upfront * Upfront
* Incremental
* Parsing * Parsing
* Untyped * Untyped
@ -335,40 +316,6 @@ Code <name>
``` ```
### Incremental construction
A Code AST is provided but the body is not complete.
* code.add( AST* ) // Adds AST with validation.
* code.add_entry( AST* ) // Adds AST entry without validation.
Code ASTs may be explictly validated at anytime using Code's check() member function.
Interface :
* make_class
* make_enum
* make_export_body
* make_extern_linkage
* make_function
* make_global_body
* make_namespace
* make_operator
* make_params
* make_specifiers
* make_struct
* make_union
Usage:
```cpp
Code <name> = make_<function name>( ... )
{
<name>->add( ... );
...
}
```
### Parse construction ### Parse construction
A string provided to the API is parsed for the intended language construct. A string provided to the API is parsed for the intended language construct.
@ -616,8 +563,3 @@ Names or Content fields are interned strings and thus showed be cached using `ge
* Generate a single-header library. * Generate a single-header library.
* Generate a C-supported single-header library. * Generate a C-supported single-header library.
* Actually get to version 1. * Actually get to version 1.
* Review if the upfront or incremental constructors are actually a net benefit vs just using the parse constructors.
* They exist as a artifact of learning what was possible or not possible with staged metaprogramming in C++ (the parse interface was the last to get fleshed out)
* Most likely at least Incremental could possibly be removed in favor of just using the parse constructors.
* Possible merits are ergonomics for very dynamic generation or performance reasons.
* They'll most likely stay until its evident that they are not necessary.

View File

@ -32,7 +32,6 @@ While getting fleshed out, all feature macros are defined on the top of the head
These macros are: These macros are:
* `GEN_DEFINE_DSL` : Define the preprocessor DSL for using the library interface
* `GEN_DEFINE_LIBRARY_CORE_CONSTANTS` : Optional typename codes as they are non-standard to C/C++ and not necessary to library usage * `GEN_DEFINE_LIBRARY_CORE_CONSTANTS` : Optional typename codes as they are non-standard to C/C++ and not necessary to library usage
* `GEN_ENCORCE_READONLY_AST` : Defines checks in Code when accessing the AST to make sure readonly marked ASTs are not mutated * `GEN_ENCORCE_READONLY_AST` : Defines checks in Code when accessing the AST to make sure readonly marked ASTs are not mutated
* `GEN_FEATURE_INCREMENTAL` : Defines the incremental constructors * `GEN_FEATURE_INCREMENTAL` : Defines the incremental constructors
@ -71,7 +70,7 @@ AST with.
First set of fowards are either backend functions used for various aspects of AST generation or configurating allocators used for different containers. First set of fowards are either backend functions used for various aspects of AST generation or configurating allocators used for different containers.
Interface fowards defined in order of: Upfront, Incremental, Parsing, Untyped. Interface fowards defined in order of: Upfront, Parsing, Untyped.
From there forwards for the File handlers are defined: Builder, Editor, Scanner. From there forwards for the File handlers are defined: Builder, Editor, Scanner.

View File

@ -5,8 +5,7 @@
#ifdef gen_time #ifdef gen_time
namespace gen namespace gen
{ {
ZPL_TABLE_DEFINE( StringTable, str_tbl_, String ); ZPL_TABLE_DEFINE( StringTable, str_tbl_, String );
// ZPL_TABLE_DEFINE( TypeTable, type_tbl_ , Code );
namespace StaticData namespace StaticData
{ {
@ -151,278 +150,6 @@ namespace gen
#pragma region AST #pragma region AST
Code Code::Invalid; Code Code::Invalid;
bool AST::add( AST* other )
{
#ifdef GEN_FEATURE_INCREMENTAL
if ( other == nullptr )
{
log_failure( "AST::add: Provided a null AST" );
return false;
}
if ( other->Type == ECode::Invalid )
{
log_failure( "AST::add: Provided an invalid AST" );
return false;
}
switch ( Type )
{
using namespace ECode;
case Invalid:
log_failure( "AST::add: Cannot add an AST to an invalid AST." );
return false;
case Untyped:
log_failure( "AST::add: Cannot add an AST to an untyped AST." );
return false;
case Comment:
log_failure( "AST::add: Cannot add an AST to a comment." );
return false;
case Access_Private:
log_failure( "AST::add: Cannot add an AST to a private access specifier." );
return false;
case Access_Protected:
log_failure( "AST::add: Cannot add an AST to a protected access specifier." );
return false;
case Access_Public:
log_failure( "AST::add: Cannot add an AST to a public access specifier." );
return false;
case Attributes:
log_failure( "AST::add: Cannot add an AST to an attribute." );
return false;
case Class:
log_failure( "AST::add: Cannot add an AST to a class, only to its body" );
return false;
case Class_Fwd:
log_failure( "AST::add: Cannot add an AST to a class forward declaration." );
return false;
case Class_Body:
switch ( other->Type )
{
AST_BODY_CLASS_UNALLOWED_TYPES
{
log_failure( "AST::add: Cannot add %s to a class body.", other->type_str() );
return false;
}
default:
break;
}
break;
case Enum:
log_failure( "AST::add: Cannot add an AST to an enum, only to its body" );
return false;
case Enum_Fwd:
log_failure( "AST::add: Cannot add an AST to an enum forward declaration." );
return false;
case Enum_Body:
if ( other->Type != Untyped )
{
log_failure( "AST::add: Cannot add an AST which is not untyped to an enum body." );
return false;
}
break;
case Execution:
log_failure( "AST::add: Cannot add an AST to an execution block." );
return false;
break;
case Export_Body:
switch ( other->Type )
{
AST_BODY_EXPORT_UNALLOWED_TYPES
{
log_failure( "AST::add: Cannot add %s to an export body.", other->type_str() );
return false;
}
default:
break;
}
break;
case Extern_Linkage:
log_failure( "AST::add: Cannot add an AST to an extern linkage, only to its body." );
return false;
case Extern_Linkage_Body:
switch ( other->Type )
{
AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES
{
log_failure( "AST::add: Cannot add %s to an extern linkage body.", other->type_str() );
return false;
}
default:
break;
}
case Enum_Class:
log_failure( "AST::add: Cannot add an AST to an enum class, only to its body" );
return false;
case Enum_Class_Fwd:
log_failure( "AST::add: Cannot add an AST to an enum class forward declaration." );
return false;
case Friend:
log_failure( "AST::add: Cannot add an AST to a friend declaration." );
return false;
case Function:
log_failure( "AST::add: Cannot add an AST to a function, only to its body" );
return false;
case Function_Body:
switch ( other->Type )
{
AST_BODY_FUNCTION_UNALLOWED_TYPES
{
log_failure( "AST::add: Cannot add %s to a function body.", other->type_str() );
return false;
}
default:
break;
}
break;
case Function_Fwd:
log_failure( "AST::add: Cannot add an AST to a function forward declaration." );
return false;
case Global_Body:
switch ( other->Type )
{
AST_BODY_GLOBAL_UNALLOWED_TYPES
{
log_failure( "AST::add: Cannot add %s to a global body.", other->type_str() );
return false;
}
default:
break;
}
break;
case Module:
log_failure( "AST::add: Cannot add an AST to a module, only to its body" );
return false;
case Namespace:
if ( Type != Global_Body )
{
log_failure( "AST::add: Cannot add a namespace to a non-global body." );
return false;
}
case Namespace_Body:
switch ( other-> Type )
{
AST_BODY_NAMESPACE_UNALLOWED_TYPES
{
log_failure( "AST::add: Cannot add %s to a namespace body.", other->type_str() );
return false;
}
default:
break;
}
break;
case Operator:
log_failure( "AST::add: Cannot add an operator, only to its body" );
return false;
case Operator_Fwd:
log_failure( "AST::add: Cannot add an operator forward declaration." );
return false;
case Parameters:
log_failure( "AST::add: Cannot add to a parameter list, use AST::add_param instead" );
return false;
case Preprocessor_Include:
log_failure( "AST::add: Cannot add an AST to a preprocessor include." );
return false;
case Specifiers:
log_failure( "AST::add: Cannot add to a specifier, use AST::add_specifier instead." );
return false;
case Struct:
log_failure( "AST::add: Cannot add to a struct, only to its body." );
return false;
case Struct_Body:
switch ( other->Type )
{
AST_BODY_STRUCT_UNALLOWED_TYPES
{
log_failure( "AST::add: Cannot add %s to a struct body.", other->type_str() );
return false;
}
default:
break;
}
break;
case Typedef:
log_failure( "AST::add: Cannot add to a typedef." );
return false;
case Typename:
log_failure( "AST::add: Cannot add to a typename." );
return false;
case Union:
log_failure( "AST::add: Cannot add to a union, only to its body." );
return false;
case Union_Body:
if ( other->Type != Untyped )
{
log_failure( "AST::add: Cannot add an AST which is not untyped to a union body." );
return false;
}
case Using:
log_failure( "AST::add: Cannot add to a using statement." );
return false;
case Using_Namespace:
log_failure( "AST::add: Cannot add to a using namespace statement." );
return false;
case Variable:
log_failure( "AST::add: Cannot add to a variable." );
return false;
}
add_entry( other );
return true;
#else
log_failure( "AST::add: Incremental AST building is not enabled." );
return false;
#endif
}
AST* AST::duplicate() AST* AST::duplicate()
{ {
using namespace ECode; using namespace ECode;
@ -563,7 +290,6 @@ namespace gen
break; break;
case Untyped: case Untyped:
// result = string_append_length( result, Content, string_length( ccast(String, Content)) );
result.append( Content ); result.append( Content );
break; break;
@ -623,7 +349,7 @@ namespace gen
result.append( Name ); result.append( Name );
AST* parent = entry( idx ); AST const* parent = entry( idx );
if ( parent ) if ( parent )
{ {
@ -671,7 +397,7 @@ namespace gen
{ {
s32 idx = 1; s32 idx = 1;
AST* Entry = entry( idx); AST const* Entry = entry( idx);
if ( Entry->Type == Attributes ) if ( Entry->Type == Attributes )
{ {
@ -724,33 +450,34 @@ namespace gen
result.append( "enum class " ); result.append( "enum class " );
s32 idx = 0; if ( num_entries() > 1 )
if ( entry( idx )->Type == Attributes )
{ {
result.append_fmt( "%s ", entry( idx )->to_string() ); s32 idx = 1;
idx++;
if ( entry( idx )->Type == Attributes )
{
result.append_fmt( "%s ", entry( idx )->to_string() );
idx++;
}
if ( entry( idx )->Type == Typename )
{
result.append_fmt( "%s : %s\n%s{\n"
, Name
, entry( idx )->to_string()
, indent_str
);
}
else
{
result.append_fmt( "%s\n{\n"
, Name
);
}
} }
if ( entry( idx )->Type == Typename ) result.append_fmt( "%s};"
{
result.append_fmt( "%s : %s\n%s{\n"
, Name
, entry( idx )->to_string()
, indent_str
);
}
else
{
result.append_fmt( "%s\n%s{\n"
, Name
, indent_str
);
}
result.append_fmt( "%s\n%s};"
, body()->to_string() , body()->to_string()
, indent_str
); );
} }
break; break;
@ -968,7 +695,7 @@ namespace gen
idx++; idx++;
} }
result.append_fmt( "%s operator %s (", entry( idx )->to_string(), Name ); result.append_fmt( "%s %s (", entry( idx )->to_string(), Name );
idx++; idx++;
if ( entry( idx )->Type == Parameters ) if ( entry( idx )->Type == Parameters )
@ -981,10 +708,9 @@ namespace gen
result.append_fmt( "void" ); result.append_fmt( "void" );
} }
result.append_fmt( ")\n%s{\n%s\n%s}" result.append_fmt( ")\n%s{\n%s\n}"
, indent_str , indent_str
, body()->to_string() , body()->to_string()
, indent_str
); );
} }
break; break;
@ -1004,7 +730,7 @@ namespace gen
idx++; idx++;
} }
result.append_fmt( "%s operator%s(", entry( idx )->to_string(), Name ); result.append_fmt( "%s %s (", entry( idx )->to_string(), Name );
idx++; idx++;
if ( entry( idx )->Type == Parameters ) if ( entry( idx )->Type == Parameters )
@ -1241,6 +967,38 @@ namespace gen
#undef ProcessModuleFlags #undef ProcessModuleFlags
} }
bool AST::is_equal( AST* other )
{
if ( Type != other->Type )
return false;
switch ( Type )
{
case ECode::Typedef:
case ECode::Typename:
{
if ( Name != other->Name )
return false;
if ( num_entries() != other->num_entries() )
return false;
for ( s32 i = 0; i < num_entries(); ++i )
{
if ( entry( i ) != other->entry( i ) )
return false;
}
return true;
}
}
if ( Name != other->Name )
return false;
return true;
}
#pragma endregion AST #pragma endregion AST
#pragma region Gen Interface #pragma region Gen Interface
@ -1728,7 +1486,7 @@ namespace gen
switch ( params_code->param_count() ) switch ( params_code->param_count() )
{ {
case 1: case 1:
if ( params_code->param_type() == type_ns(int) ) if ( params_code->param_type()->is_equal( type_ns(int) ) )
is_member_symbol = true; is_member_symbol = true;
else else
@ -1738,7 +1496,7 @@ namespace gen
case 2: case 2:
check_param_eq_ret(); check_param_eq_ret();
if ( params_code->get_param(1) != type_ns(int) ) if ( ! params_code->get_param(1)->is_equal( type_ns(int) ) )
{ {
log_failure("gen::def_operator: " log_failure("gen::def_operator: "
"operator%s requires second parameter of non-member definition to be int for post-decrement", "operator%s requires second parameter of non-member definition to be int for post-decrement",
@ -1772,7 +1530,7 @@ namespace gen
return OpValidateResult::Fail; return OpValidateResult::Fail;
} }
if ( params_code->param_type() == ret_type ) if ( params_code->param_type()->is_equal( ret_type ) )
{ {
log_failure("gen::def_operator: " log_failure("gen::def_operator: "
"operator%s is non-member symbol yet first paramter does not equal return type\n" "operator%s is non-member symbol yet first paramter does not equal return type\n"
@ -1814,7 +1572,7 @@ namespace gen
break; break;
case 2: case 2:
if ( params_code->param_type() != ret_type ) if ( ! params_code->param_type()->is_equal( ret_type ) )
{ {
log_failure("gen::def_operator: " log_failure("gen::def_operator: "
"operator%s is non-member symbol yet first paramter does not equal return type\n" "operator%s is non-member symbol yet first paramter does not equal return type\n"
@ -1858,7 +1616,7 @@ namespace gen
} }
} }
if ( ret_type != type_ns(bool) ) if ( ! ret_type->is_equal( type_ns(bool) ))
{ {
log_failure("gen::def_operator: operator%s return type must be of type bool - %s" log_failure("gen::def_operator: operator%s return type must be of type bool - %s"
, to_str(op) , to_str(op)
@ -2402,7 +2160,7 @@ namespace gen
{ {
using namespace ECode; using namespace ECode;
if ( body && body->Type != Function_Body ) if ( body && body->Type != Function_Body && body->Type != Untyped )
{ {
log_failure( "gen::def_operator: Body was provided but its not of function body type: %s", body->debug_str() ); log_failure( "gen::def_operator: Body was provided but its not of function body type: %s", body->debug_str() );
return Code::Invalid; return Code::Invalid;
@ -2427,7 +2185,7 @@ namespace gen
return Code::Invalid; return Code::Invalid;
} }
char const* name = str_fmt_buf( "operator%s", to_str(op) ); char const* name = str_fmt_buf( "operator %s", to_str(op) );
Code Code
result = make_code(); result = make_code();
@ -2561,10 +2319,6 @@ namespace gen
return Code::Invalid; return Code::Invalid;
} }
// Code cached = get_cached_type( name );
// if ( cached )
// return cached;
Code Code
result = make_code(); result = make_code();
result->Name = get_cached_string( name ); result->Name = get_cached_string( name );
@ -2578,11 +2332,6 @@ namespace gen
result.lock(); result.lock();
// s32 hash_length = name.Len > kilobytes(1) ? kilobytes(1) : name.Len;
// s32 key = crc32( name.Ptr, hash_length );
// type_tbl_set( & StaticData::TypeMap, key, result );
return result; return result;
} }
@ -3196,7 +2945,7 @@ namespace gen
result->Name = current->Name; result->Name = current->Name;
result->Type = current->Type; result->Type = current->Type;
result->add_entry( current->entry( 0) ); result->add_entry( current->entry( 0 ) );
while( codes++, current = * codes, num--, num > 0 ) while( codes++, current = * codes, num--, num > 0 )
{ {
@ -3344,329 +3093,11 @@ namespace gen
result.lock(); result.lock();
return result; return result;
} }
#pragma endregion Upfront Constructors
#pragma region Incremetnal Constructors
#ifdef GEN_FEATURE_INCREMENTAL
Code make_class( StrC name
, Code parent, AccessSpec parent_access
, Code specifiers, Code attributes
, ModuleFlag mflags )
{
using namespace ECode;
name_check( make_struct, name );
if ( attributes && attributes->Type != Attributes )
{
log_failure( "gen::make_class: attributes was not a `Attributes` type: %s", attributes->debug_str() );
return Code::Invalid;
}
if ( specifiers && specifiers->Type != Specifiers )
{
log_failure( "gen::make_class: specifiers was not a `Specifiers` type: %s", specifiers->debug_str() );
return Code::Invalid;
}
if ( parent && parent->Type != Struct )
{
log_failure( "gen::make_class: parent was not a `Struct` type: %s", parent->debug_str() );
return Code::Invalid;
}
Code
result = make_code();
result->Type = Struct;
result->Name = get_cached_string( name );
result->ModuleFlags = mflags;
Code
body = make_code();
body->Type = Struct_Body;
result->add_entry( body );
if ( attributes )
result->add_entry( attributes );
if ( specifiers )
result->add_entry( specifiers );
if ( parent )
result->add_entry( parent );
return result;
}
Code make_enum( StrC name, Code type, EnumT specifier, Code attributes, ModuleFlag mflags )
{
using namespace ECode;
name_check( make_enum, name );
if ( attributes && attributes->Type != Attributes )
{
log_failure( "gen::make_enum: attributes was not a `Attributes` type: %s", attributes->debug_str() );
return Code::Invalid;
}
if ( type && type->Type != Typename )
{
log_failure("gen::make_enum: type provided is not of code type typename - %s", type->debug_str() );
return Code::Invalid;
}
Code
result = make_code();
result->Type = specifier == EnumClass ? Enum_Class : Enum;
result->Name = get_cached_string( name );
result->ModuleFlags = mflags;
Code
body = make_code();
body->Type = Enum_Body;
result->add_entry( body );
if ( type )
result->add_entry( type );
return result;
}
Code make_export_body( StrC name )
{
using namespace ECode;
Code
result = make_code();
result->Type = Export_Body;
if ( name && name.Len > 0 )
result->Name = get_cached_string( name );
return result;
}
Code make_extern_link( StrC name, ModuleFlag mflags )
{
using namespace ECode;
name_check( make_extern_linkage, name);
Code
result = make_code();
result->Type = Extern_Linkage;
result->Name = get_cached_string( name );
result->ModuleFlags = mflags;
return result;
}
Code make_function( StrC name
, Code params, Code ret_type
, Code specifiers, Code attributes
, ModuleFlag mflags
)
{
using namespace ECode;
name_check( make_function, name );
if ( attributes && attributes->Type != Attributes )
{
log_failure( "gen::make_function: attributes was not a `Attributes` type: %s", attributes->debug_str() );
return Code::Invalid;
}
if ( specifiers && specifiers->Type != Specifiers )
{
log_failure( "gen::def_function: specifiers was not a `Specifiers` type" );
return Code::Invalid;
}
if ( params && params->Type != Parameters )
{
log_failure( "gen::def_function: params was not a `Parameters` type" );
return Code::Invalid;
}
if ( ret_type == nullptr || ret_type->Type != Typename )
{
log_failure( "gen::def_function: ret_type was not a Typename" );
return Code::Invalid;
}
Code
result = make_code();
result->Name = get_cached_string( name );
result->Type = Function;
result->ModuleFlags = mflags;
Code
body = make_code();
body->Type = Function_Body;
result->add_entry( body );
if ( attributes )
result->add_entry( attributes );
if ( specifiers )
result->add_entry( specifiers );
if ( ret_type )
result->add_entry( ret_type );
if ( params )
result->add_entry( params );
return result;
}
Code make_global_body( StrC name )
{
name_check( make_global_body, name );
Code
result = make_code();
result->Type = ECode::Global_Body;
if ( name.Len > 0 )
result->Name = get_cached_string( name );
return result;
}
Code make_namespace( StrC name, Code parent, ModuleFlag mflags )
{
name_check( make_namespace, name );
Code
result = make_code();
result->Type = ECode::Namespace;
result->Name = get_cached_string( name );
result->ModuleFlags = mflags;
Code
body = make_code();
body->Type = ECode::Namespace_Body;
result->add_entry( body );
return result;
}
Code make_operator( OperatorT op, Code params_code, Code ret_type, Code specifiers, Code attributes, ModuleFlag mflags )
{
using namespace ECode;
if ( attributes && attributes->Type != Attributes )
{
log_failure( "gen::make_operator: attributes was not a `Attributes` type: %s", attributes->debug_str() );
return Code::Invalid;
}
OpValidateResult check_result = operator__validate( op, params_code, ret_type, specifiers );
if ( check_result == OpValidateResult::Fail )
{
return Code::Invalid;
}
char const* name = str_fmt_buf( "operator%s", to_str(op) );
Code
result = make_code();
result->Name = get_cached_string( { str_len(name, MaxNameLength), name } );
result->ModuleFlags = mflags;
if ( attributes )
result->add_entry( attributes );
if ( specifiers )
result->add_entry( specifiers );
if (params_code)
result->add_entry( params_code );
result->add_entry( ret_type );
return result;
}
Code make_params()
{
Code
result = make_code();
result->Type = ECode::Parameters;
return result;
}
Code make_specifiers()
{
Code
result = make_code();
result->Type = ECode::Specifiers;
return result;
}
Code make_struct( StrC name, Code parent, Code specifiers, Code attributes, ModuleFlag mflags )
{
using namespace ECode;
name_check( make_struct, name );
if ( attributes && attributes->Type != Attributes )
{
log_failure( "gen::make_struct: attributes was not a `Attributes` type: %s", attributes->debug_str() );
return Code::Invalid;
}
if ( specifiers && specifiers->Type != Specifiers )
{
log_failure( "gen::make_struct: specifiers was not a `Specifiers` type" );
return Code::Invalid;
}
if ( parent && parent->Type != Struct )
{
log_failure( "gen::make_struct: parent was not a `Struct` type" );
return Code::Invalid;
}
Code
result = make_code();
result->Type = Struct;
result->Name = get_cached_string( name );
result->ModuleFlags = mflags;
Code
body = make_code();
body->Type = Function_Body;
result->add_entry( make_code() );
if ( attributes )
result->add_entry( attributes );
if ( specifiers )
result->add_entry( specifiers );
if ( parent )
result->add_entry( parent );
return result;
}
# undef name_check # undef name_check
# undef null_check # undef null_check
# undef null_or_invalid_check # undef null_or_invalid_check
#endif // GEN_FEATURE_INCREMENTAL #pragma endregion Upfront Constructors
#pragma endregion Incremetnal Constructions
#pragma region Parsing Constructors #pragma region Parsing Constructors
#ifdef GEN_FEATURE_PARSING #ifdef GEN_FEATURE_PARSING

View File

@ -11,7 +11,6 @@
#include "Bloat.hpp" #include "Bloat.hpp"
// Temporarily here for debugging purposes. // Temporarily here for debugging purposes.
// #define GEN_DEFINE_DSL
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
// #define GEN_DONT_USE_FATAL // #define GEN_DONT_USE_FATAL
// #define GEN_ENFORCE_READONLY_AST // #define GEN_ENFORCE_READONLY_AST
@ -390,11 +389,6 @@ namespace gen
struct AST struct AST
{ {
#pragma region Member Functions #pragma region Member Functions
// Used with incremental constructors
// Adds and checks entries to see if they are valid additions the type of ast.
bool add( AST* other );
void add_entry( AST* other ); void add_entry( AST* other );
inline inline
@ -413,7 +407,7 @@ namespace gen
inline inline
bool has_entries() bool has_entries()
{ {
return entry( 0 ); return num_entries();
} }
inline inline
@ -422,6 +416,9 @@ namespace gen
return Type != ECode::Invalid; return Type != ECode::Invalid;
} }
inline
bool is_equal( AST* other );
inline inline
s32 num_entries() s32 num_entries()
{ {
@ -640,13 +637,13 @@ namespace gen
} }
inline inline
String to_string() String to_string() const
{ {
return ast->to_string(); return ast->to_string();
} }
inline inline
operator bool() operator bool() const
{ {
return ast; return ast;
} }
@ -718,21 +715,6 @@ namespace gen
// Used when the its desired when omission is allowed in a definition. // Used when the its desired when omission is allowed in a definition.
constexpr Code NoCode = { nullptr }; constexpr Code NoCode = { nullptr };
// extern const Code InvalidCode;
/*
Type Table: Used to store Typename ASTs. Types are registered by their string literal value.
Provides interning specific to Typename ASTs.
Interning for other types should be possible (specifiers) with this, so long as they
don't have an set of child AST entries (Use the content field).
TODO: I'm not sure if this is viable.
ASTs are duplicated when added (parent is unique),
Parent is currently used for debug and serialization.
If these features are considered unnecessary, then caching would be fine.
*/
// ZPL_TABLE_DECLARE( ZPL_EXTERN, TypeTable, type_tbl_, Code );
#pragma endregion Data Structures #pragma endregion Data Structures
#pragma region Gen Interface #pragma region Gen Interface
@ -856,45 +838,6 @@ namespace gen
Code def_union_body ( s32 num, Code* codes ); Code def_union_body ( s32 num, Code* codes );
# pragma endregion Upfront # pragma endregion Upfront
# pragma region Incremental
# ifdef GEN_FEATURE_INCREMENTAL
Code make_class( StrC name
, Code parent = NoCode, AccessSpec access = AccessSpec::Default
, Code specifiers = NoCode, Code attributes = NoCode
, ModuleFlag mflags = ModuleFlag::None );
Code make_enum( StrC name
, Code type = NoCode, EnumT specifier = EnumRegular
, Code attributes = NoCode, ModuleFlag mflags = ModuleFlag::None );
Code make_export_body( StrC name = { 1, "" } );
Code make_extern_link( s32 length, char const* name, ModuleFlag mflags = ModuleFlag::None );
Code make_function( StrC name
, Code params = NoCode, Code ret_type = NoCode
, Code specifiers = NoCode, Code attributes = NoCode
, ModuleFlag mflags = ModuleFlag::None );
Code make_global_body( StrC name = { 1, "" } );
Code make_namespace ( s32 length, char const* name, ModuleFlag mflags = ModuleFlag::None );
Code make_operator( OperatorT op
, Code params = NoCode, Code ret_type = NoCode
, Code specifiers = NoCode, Code attributes = NoCode
, ModuleFlag mflags = ModuleFlag::None );
Code make_params ();
Code make_specifiers();
Code make_struct( StrC name
, Code parent = NoCode, AccessSpec access = AccessSpec::Default
, Code specifiers = NoCode, Code attributes = NoCode
, ModuleFlag mflags = ModuleFlag::None );
Code make_union( StrC name, Code attributes = NoCode, ModuleFlag mflags = ModuleFlag::None );
# endif
# pragma endregion Incremental
#pragma region Parsing #pragma region Parsing
#ifdef GEN_FEATURE_PARSING #ifdef GEN_FEATURE_PARSING
Code parse_class ( StrC class_def ); Code parse_class ( StrC class_def );
@ -1061,11 +1004,9 @@ namespace gen
#pragma region Macros #pragma region Macros
# define gen_main main # define gen_main main
# define __ NoCode # define __ NoCode
# define spec_alignas( Value_ ) ESpecifier::Alignas, Value
// This represents the naming convention for all typename Codes generated. // This represents the naming convention for all typename Codes generated.
// Used by the DSL but can also be used without it.
# define type_ns( Name_ ) t_##Name_ # define type_ns( Name_ ) t_##Name_
// Convienence for defining any name used with the gen api. // Convienence for defining any name used with the gen api.
@ -1075,6 +1016,9 @@ namespace gen
// Same as name just used to indicate intention of literal for code instead of names. // Same as name just used to indicate intention of literal for code instead of names.
# define code( Code_ ) { txt_n_len( Code_ ) } # define code( Code_ ) { txt_n_len( Code_ ) }
# define code_args( num, ... ) num, (Code[num]){ __VA_ARGS__ }
# define enum_entry( id ) "\t" #id ",\n"
#pragma endregion Macros #pragma endregion Macros
#pragma region Constants #pragma region Constants

View File

@ -52,12 +52,29 @@ $path_scripts = Join-Path $path_root scripts
$gencpp = Join-Path $path_gen_build gencpp.exe $gencpp = Join-Path $path_gen_build gencpp.exe
Push-location $path_gen Push-location $path_gen
# & $gencpp
Write-Host `nGenerating files...
& $gencpp
Write-Host `nBeginning format...
$formatParams = @(
'-i' # In-place
'-style=file' # Search for a .clang-format file in the parent directory of the source file.
'-verbose'
)
$include = @('*.gen.hpp', '*.gen.cpp')
$exclude = $null
$targetFiles = @(Get-ChildItem -Recurse -Path $path_gen -Include $include -Exclude $exclude | Select-Object -ExpandProperty FullName)
clang-format $formatParams $targetFiles
Write-Host "`nFormatting complete"
Pop-Location Pop-Location
# Build the program depending on generated files. # Build the program depending on generated files.
# if ( -not( Test-Path $path_test_build ) ) # if ( -not( Test-Path $path_test_build ) )k
# { # {
# $args_meson = @() # $args_meson = @()
# $args_meson += "setup" # $args_meson += "setup"

View File

@ -0,0 +1,5 @@
# Singleheader generator
This will require the scanner to be implemented before it can be done properly.

View File

View File

@ -1,4 +0,0 @@
// Removes the genc_ namespace if desired
namespace genc_

0
singleheader/meson.build Normal file
View File

View File

@ -56,11 +56,9 @@ u32 gen_sanity()
Code def; Code def;
{ {
Code body = untyped_str( StrC::from( Code body = untyped_str( StrC::from(
#define enum_entry( id ) "\t" #id ",\n"
enum_entry( A ) enum_entry( A )
enum_entry( B ) enum_entry( B )
enum_entry( C ) enum_entry( C )
#undef enum_entry
)); ));
def = def_enum( name(ETestEnum), body, t_u8 ); def = def_enum( name(ETestEnum), body, t_u8 );
@ -120,7 +118,7 @@ u32 gen_sanity()
// Include // Include
{ {
Code include = def_include( StrC::from("DummyInclude.hpp") ); Code include = def_include( StrC::from("../DummyInclude.hpp") );
gen_sanity_file.print(include); gen_sanity_file.print(include);
} }
@ -161,7 +159,37 @@ u32 gen_sanity()
// Operator // Operator
{ {
// This is nasty... // Going to make a bit flag set of overloads for this.
Code bitflagtest;
{
Code body = def_enum_body( 1, untyped_str( StrC::from(
enum_entry( A = 1 << 0 )
enum_entry( B = 1 << 1 )
enum_entry( C = 1 << 2 )
)));
bitflagtest = def_enum( name(EBitFlagtest), body, t_u8, EnumClass );
}
Code t_bitflag = def_type( name(EBitFlagtest) );
Code op_fwd, op_or;
{
Code params = def_params( code_args( 2,
def_param( t_bitflag, name(a) ),
def_param( t_bitflag, name(b) )
));
op_fwd = def_operator( EOperator::BOr, params, t_bitflag );
op_or = def_operator( EOperator::BOr, params, t_bitflag, untyped_str( code(
return EBitFlagtest( (u8)a | (u8)b );
)));
}
gen_sanity_file.print(bitflagtest);
gen_sanity_file.print_fmt("\n");
gen_sanity_file.print(op_fwd);
gen_sanity_file.print(op_or);
} }
gen_sanity_file.print_fmt("\n"); gen_sanity_file.print_fmt("\n");

163
test/gen/.clang-format Normal file
View File

@ -0,0 +1,163 @@
# Format Style Options - Created with Clang Power Tools
---
AccessModifierOffset: -4
AlignAfterOpenBracket: BlockIndent
AlignArrayOfStructures: Right
AlignConsecutiveAssignments:
Enabled: true
AcrossEmptyLines: false
AcrossComments: true
AlignCompound: true
PadOperators: true
AlignConsecutiveBitFields: AcrossComments
AlignConsecutiveDeclarations: AcrossComments
AlignConsecutiveMacros: AcrossComments
AlignEscapedNewlines: Right
AlignOperands: DontAlign
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortLambdasOnASingleLine: None
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BeforeLambdaBody: false
BeforeWhile: false
# BreakAfterAttributes: Always
# BreakArrays: false
# BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Allman
BreakBeforeInheritanceComma: true
BreakInheritanceList: BeforeComma
BreakBeforeConceptDeclarations: true
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakStringLiterals: true
ColumnLimit: 180
CompactNamespaces: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth : 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: false
DeriveLineEnding: true
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
IncludeBlocks: Preserve
IndentCaseBlocks: true
IndentCaseLabels: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: AfterHash
IndentRequires: true
IndentWidth: 4
IndentWrappedFunctionNames: false
# InsertNewlineAtEOF: true
InsertTrailingCommas: Wrapped
LambdaBodyIndentation: OuterScope
Language: Cpp
MaxEmptyLinesToKeep: 4
NamespaceIndentation: All
PointerAlignment: Left
QualifierAlignment: Leave
ReferenceAlignment: Left
ReflowComments: true
# RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Always
ShortNamespaceLines: 40
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: true
SpaceAfterTemplateKeyword: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatementsExceptControlMacros
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpacesBeforeTrailingComments: 4
SpaceInEmptyBlock: true
SpaceInEmptyParentheses: false
SpacesInAngles: true
SpacesInCStyleCastParentheses: true
SpacesInConditionalStatement: true
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: 20
SpacesInParentheses: true
SpacesInSquareBrackets: true
Standard: c++17
TabWidth: 4
UseTab: ForIndentation
...

View File

@ -3,15 +3,16 @@
// The following will show a series of base cases for the gen api. // The following will show a series of base cases for the gen api.
class TestEmptyClass; class TestEmptyClass;
class TestEmptyClass class TestEmptyClass
{ {
// Empty class body // Empty class body
}; };
typedef unsigned char u8; typedef unsigned char u8;
enum ETestEnum : u8; enum ETestEnum : u8;
enum ETestEnum : u8 enum ETestEnum : u8
{ {
A, A,
@ -23,24 +24,21 @@ enum class ETestEnumClass : u8;
extern "C" extern "C"
{ {
// Empty extern body // Empty extern body
} }
class TestFriend class TestFriend
{ {
friend class TestFriendFwd; friend class TestFriendFwd;
}; };
void test_function(void); void test_function( void );
void test_function(void)
void test_function( void )
{ {
// Empty function body // Empty function body
} }
#include "DummyInclude.hpp" #include "../DummyInclude.hpp"
namespace TestNamespace namespace TestNamespace
{ {
@ -48,31 +46,43 @@ namespace TestNamespace
}; };
enum class EBitFlagtest : u8
void test_function_wparam(u8 a);
void test_function_wparams(u8 a, u8 b)
{ {
// Empty function body A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
};
EBitFlagtest operator|( EBitFlagtest a, EBitFlagtest b );
EBitFlagtest operator|( EBitFlagtest a, EBitFlagtest b )
{
return EBitFlagtest( ( u8 )a | ( u8 )b );
} }
void test_function_wparams2(u8 a, u8 b)
void test_function_wparam( u8 a );
void test_function_wparams( u8 a, u8 b )
{ {
// Empty function body // Empty function body
}
void test_function_wparams2( u8 a, u8 b )
{
// Empty function body
} }
class TestEmptyStruct; class TestEmptyStruct;
class TestEmptyStruct class TestEmptyStruct
{ {
// Empty class body // Empty class body
}; };
union TestEmptyUnion union TestEmptyUnion
{ {
// Empty union body // Empty union body
}; };
using TestUsing = u8; using TestUsing = u8;
@ -82,4 +92,3 @@ u8 test_variable;
u8 test_variable2 = 0x12; u8 test_variable2 = 0x12;
// End of base case tests. // End of base case tests.

View File

@ -1,51 +0,0 @@
#include "Bloat.cpp"
#ifdef gen_time
#include "gen.cpp"
void case_untyped()
{
}
int gen_main()
{
Memory::setup();
log_fmt("\nPress any key after attaching to process\n");
getchar();
gen::init();
case_untyped();
Memory::cleanup();
return 0;
}
#endif
#ifdef runtime
int main()
{
return 0;
}
#endif