Somehow overlooked unions... More stuff on parser constructors

This commit is contained in:
Edward R. Gonzalez 2023-04-23 22:53:30 -04:00
parent d541b33b22
commit 38a60e4b91
4 changed files with 582 additions and 65 deletions

View File

@ -156,7 +156,7 @@ struct ArrayHeader
## Gen's DSL
If you don't mind a low amount of macros (61 sloc), a DSL may be optionally defined with:
If you don't mind a low amount of macros (~80 sloc), a DSL may be optionally defined with:
```cpp
GEN_DEFINE_DSL

View File

@ -2017,6 +2017,34 @@ namespace gen
return result;
}
Code def_union( s32 length, char const* name, Code body )
{
name_check( def_union, length, name );
if ( body && body->Type != ECode::Union_Body )
{
log_failure( "gen::def_union: body was not a Union_Body type" );
return Code::Invalid;
}
Code
result = make_code();
result->Name = get_cached_string( name, length );
if ( body )
{
result->Type = ECode::Union;
result->add_entry( body );
}
else
{
result->Type = ECode::Union_Fwd;
}
result.lock();
return result;
}
Code def_using( u32 length, char const* name, Code type, UsingT specifier )
{
name_check( def_using, length, name );
@ -2201,7 +2229,7 @@ namespace gen
Code
result = make_code();
result->Type = Class_Body;
result->Type = Enum_Body;
do
{
@ -2529,6 +2557,73 @@ namespace gen
result.lock();
return result;
}
Code def_union_body( s32 num, ... )
{
def_body_start( def_union_body );
Code
result = make_code();
result->Type = Union_Body;
va_list va;
va_start(va, num);
do
{
Code entry = va_arg(va, Code);
if ( ! entry )
{
log_failure("gen::def_union_body: Provided a null entry");
return Code::Invalid;
}
if ( entry->Type != Untyped )
{
log_failure("gen::def_union_body: Entry type is not allowed - %s. Must be of untyped type.", entry->debug_str() ); \
return Code::Invalid;
}
result->add_entry( entry );
}
while ( num--, num > 0 );
va_end(va);
result.lock();
return result;
}
Code def_union_body( s32 num, Code* codes )
{
def_body_code_array_start( def_union_body );
Code
result = make_code();
result->Type = Union_Body;
do
{
Code entry = *codes;
if ( ! entry )
{
log_failure("gen::def_union_body: Provided a null entry");
return Code::Invalid;
}
if ( entry->Type != Untyped )
{
log_failure("gen::def_union_body: Entry type is not allowed: %s", entry->debug_str() ); \
return Code::Invalid;
}
result->add_entry( entry );
}
while ( codes++, num--, num > 0 );
result.lock();
return result;
}
#pragma endregion Upfront Constructors
#pragma region Incremetnal Constructors
@ -3389,13 +3484,21 @@ namespace gen
}
# define currtok toks.Arr[toks.Idx]
# define eat( Type_ ) toks.__eat( Type_, txt(context) )
# define eat( Type_ ) toks.__eat( Type_, context )
# define left array_count(toks.Arr) - toks.Idx
# define check( Type_ ) left && currtok.Type == Type_
#pragma endregion Helper Macros
Code parse_type( Parser::TokArray& toks, char const* func_name );
Code parse_class ( Parser::TokArray& toks, char const* context );
Code parse_enum ( Parser::TokArray& toks, char const* context );
Code parse_friend ( Parser::TokArray& toks, char const* context );
Code parse_function( Parser::TokArray& toks, char const* context );
Code parse_struct ( Parser::TokArray& toks, char const* context );
Code parse_variable( Parser::TokArray& toks, char const* context );
Code parse_type ( Parser::TokArray& toks, char const* context );
Code parse_typedef ( Parser::TokArray& toks, char const* context );
Code parse_union ( Parser::TokArray& toks, char const* context );
Code parse_using ( Parser::TokArray& toks, char const* context );
inline
Code parse_array_decl( Parser::TokArray& toks, char const* func_name )
@ -3549,43 +3652,215 @@ namespace gen
# undef context
}
Code parse_class( s32 length, char const* def )
Code parse_class_struct_body( Parser::TokArray& toks, char const* context )
{
using namespace Parser;
using namespace ECode;
# define context parse_class
eat( TokType::BraceCurly_Open );
TokArray toks = lex( length, def );
if ( toks.Arr == nullptr )
Code
result = make_code();
result->Type = Class_Body;
while ( left && currtok.Type != TokType::BraceCurly_Close )
{
Code member = Code::Invalid;
switch ( currtok.Type )
{
case TokType::Comment:
break;
case TokType::Access_Public:
case TokType::Access_Protected:
case TokType::Access_Private:
break;
case TokType::Decl_Class:
member = parse_class( toks, context );
break;
case TokType::Decl_Enum:
member = parse_enum( toks, context );
break;
case TokType::Decl_Friend:
member = parse_friend( toks, context );
break;
case TokType::Decl_Struct:
member = parse_struct( toks, context );
break;
case TokType::Decl_Typedef:
member = parse_typedef( toks, context );
break;
case TokType::Decl_Union:
member = parse_variable( toks, context );
break;
case TokType::Decl_Using:
member = parse_using( toks, context );
break;
case TokType::Identifier:
case TokType::Spec_Const:
case TokType::Spec_Consteval:
case TokType::Spec_Constexpr:
case TokType::Spec_Constinit:
case TokType::Spec_Inline:
case TokType::Spec_Static:
case TokType::Spec_ThreadLocal:
case TokType::Spec_Volatile:
case TokType::Type_Unsigned:
case TokType::Type_Signed:
case TokType::Type_Short:
case TokType::Type_Long:
break;
}
if ( member == Code::Invalid )
return Code::Invalid;
result->add_entry( member );
eat( currtok.Type );
}
eat( TokType::BraceCurly_Close );
return result;
}
Code parse_function_body( Parser::TokArray& toks, char const* context )
{
using namespace Parser;
using namespace ECode;
eat( TokType::BraceCurly_Open );
Code
result = make_code();
result->Type = Function_Body;
while ( left && currtok.Type != TokType::BraceCurly_Close )
{
Code member = Code::Invalid;
switch ( currtok.Type )
{
case TokType::Comment:
// TODO: Add comment to function body?
break;
case TokType::Decl_Class:
member = parse_class( toks, context );
break;
case TokType::Decl_Enum:
member = parse_enum( toks, context );
break;
case TokType::Decl_Struct:
member = parse_struct( toks, context );
break;
case TokType::Decl_Typedef:
member = parse_typedef( toks, context );
break;
case TokType::Decl_Union:
member = parse_union( toks, context );
break;
case TokType::Decl_Using:
member = parse_using( toks, context );
break;
case TokType::Identifier:
break;
case TokType::Spec_Const:
case TokType::Spec_Constexpr:
case TokType::Spec_Constinit:
case TokType::Spec_Static:
case TokType::Spec_ThreadLocal:
case TokType::Spec_Volatile:
// Can be all kinds of crap
case TokType::Type_Unsigned:
case TokType::Type_Signed:
case TokType::Type_Short:
case TokType::Type_Long:
member = parse_variable( toks, context );
break;
case TokType::Spec_API:
log_failure( "gen::%s: %s not allowed in function body", context, str_tok_type( currtok.Type ) );
return Code::Invalid;
default:
Token untyped_tok = currtok;
while ( left && currtok.Type != TokType::Statement_End )
{
untyped_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)untyped_tok.Text;
eat( currtok.Type );
}
Code member = untyped_str( untyped_tok.Length, untyped_tok.Text );
break;
}
if ( member == Code::Invalid )
return Code::Invalid;
result->add_entry( member );
eat( currtok.Type );
}
eat( TokType::BraceCurly_Close );
return result;
}
Code parse_class( Parser::TokArray& toks, char const* context )
{
using namespace Parser;
Token name { nullptr, 0, TokType::Invalid };
Code parent = { nullptr };
Code speciifes = { nullptr };
Code body = { nullptr };
do
{
Code result = Code::Invalid;
}
while ( left--, left > 0 );
eat( TokType::Decl_Class );
return Code::Invalid;
# undef context
not_implemented();
}
Code parse_enum( s32 length, char const* def )
Code parse_class( s32 length, char const* def )
{
# define context txt(parse_class)
using namespace Parser;
# define context parse_enum
check_parse_args( parse_enum, length, def );
TokArray toks = lex( length, def );
if ( toks.Arr == nullptr )
return Code::Invalid;
return parse_class( toks, context );
# undef context
}
Code parse_enum( Parser::TokArray& toks, char const* context )
{
using namespace Parser;
using namespace ECode;
SpecifierT specs_found[16] { ESpecifier::Num_Specifiers };
s32 num_specifiers = 0;
@ -3671,21 +3946,28 @@ namespace gen
result.lock();
return result;
# undef context
}
Code parse_friend( s32 length, char const* def )
Code parse_enum( s32 length, char const* def )
{
using namespace Parser;
using namespace ECode;
# define context parse_friend
check_parse_args( parse_friend, length, def );
# define context parse_enum
check_parse_args( parse_enum, length, def );
TokArray toks = lex( length, def );
if ( toks.Arr == nullptr )
return Code::Invalid;
return parse_enum( toks, txt(parse_enum) );
# undef context
}
Code parse_friend( Parser::TokArray& toks, char const* context )
{
using namespace Parser;
using namespace ECode;
eat( TokType::Decl_Friend );
Code function = { nullptr };
@ -3731,9 +4013,165 @@ namespace gen
return result;
}
Code parse_friend( s32 length, char const* def )
{
using namespace Parser;
using namespace ECode;
# define context parse_friend
check_parse_args( parse_friend, length, def );
TokArray toks = lex( length, def );
if ( toks.Arr == nullptr )
return Code::Invalid;
return parse_friend( toks, txt(parse_friend) );
}
Code parse_global_body( Parser::TokArray& toks, char const* context )
{
not_implemented();
}
Code parse_global_body( s32 length, char const* def )
{
not_implemented( parse_global_body );
using namespace Parser;
using namespace ECode;
Code result = make_code();
result->Type = Global_Body;
while ( left )
{
}
result.lock();
return result;
}
Code parse_functon( Parser::TokArray& toks, char const* context )
{
using namespace Parser;
// TODO: Add attribute parsing support
SpecifierT specs_found[16] { ESpecifier::Num_Specifiers };
s32 num_specifiers = 0;
Code lang_linkage = Code::Invalid;
Code attributes = Code::Invalid;
Code array_expr = Code::Invalid;
Code specifiers = Code::Invalid;
while ( left && tok_is_specifier( currtok ) )
{
SpecifierT spec = ESpecifier::to_type( currtok.Text, currtok.Length );
switch ( spec )
{
case ESpecifier::Constexpr:
case ESpecifier::Export:
case ESpecifier::External_Linkage:
case ESpecifier::Import:
case ESpecifier::Local_Persist:
case ESpecifier::Mutable:
case ESpecifier::Static_Member:
case ESpecifier::Thread_Local:
case ESpecifier::Volatile:
break;
default:
log_failure( "gen::parse_variable: invalid specifier " txt(spec) " for variable" );
return Code::Invalid;
}
if ( spec == ESpecifier::External_Linkage )
{
specs_found[num_specifiers] = spec;
num_specifiers++;
eat( TokType::Spec_Extern );
if ( currtok.Type == TokType::String )
{
lang_linkage = untyped_str( currtok.Length, currtok.Text );
eat( TokType::String );
}
continue;
}
specs_found[num_specifiers] = spec;
num_specifiers++;
eat( currtok.Type );
}
if ( num_specifiers )
{
specifiers = def_specifiers( num_specifiers, specs_found );
}
Code ret_type = parse_type( toks, txt(parse_function) );
if ( ret_type == Code::Invalid )
return Code::Invalid;
Token name = parse_identifier( toks, txt(parse_function) );
if ( ! name )
return Code::Invalid;
Code params = parse_params( toks, txt(parse_function) );
Code body = Code::Invalid;
if ( check( TokType::BraceCurly_Open ) )
{
body = parse_function_body( toks, txt(parse_function) );
if ( body == Code::Invalid )
return Code::Invalid;
}
else
{
eat( TokType::Statement_End );
}
using namespace ECode;
Code
result = make_code();
result->Name = get_cached_string( name.Text, name.Length );
if ( body )
{
switch ( body->Type )
{
case Function_Body:
case Untyped:
break;
default:
{
log_failure("gen::def_function: body must be either of Function_Body or Untyped type. %s", body->debug_str());
return Code::Invalid;
}
}
result->Type = Function;
result->add_entry( body );
}
else
{
result->Type = Function_Fwd;
}
if ( specifiers )
result->add_entry( specifiers );
result->add_entry( ret_type );
if ( params )
result->add_entry( params );
result.lock();
return result;
}
Code parse_function( s32 length, char const* def )
@ -3747,15 +4185,16 @@ namespace gen
arena_init_from_allocator( & mem, heap(), kilobytes( 10 ) );
do_once_end
TokArray toks = lex( length, def );
if ( toks.Arr == nullptr )
return Code::Invalid;
return parse_functon( toks, txt(parse_function) );
}
Code
result = make_code();
result.lock();
return result;
Code parse_namespace( Parser::TokArray& toks, char const* context )
{
not_implemented();
}
Code parse_namespace( s32 length, char const* def )
@ -3763,11 +4202,21 @@ namespace gen
not_implemented( parse_namespace );
}
Code parse_operator( Parser::TokArray& toks, char const* context )
{
not_implemented();
}
Code parse_operator( s32 length, char const* def )
{
not_implemented( parse_operator );
}
Code parse_struct( Parser::TokArray& toks, char const* context )
{
not_implemented();
}
Code parse_struct( s32 length, char const* def )
{
Arena mem;
@ -3789,25 +4238,19 @@ namespace gen
return Code::Invalid;
}
Code parse_variable( s32 length, char const* def )
Code parse_variable( Parser::TokArray& toks, char const* context )
{
using namespace Parser;
# define context parse_variable
check_parse_args( parse_variable, length, def );
TokArray toks = lex( length, def );
if ( toks.Arr == nullptr )
return Code::Invalid;
Token name = { nullptr, 0, TokType::Invalid };
SpecifierT specs_found[16] { ESpecifier::Num_Specifiers };
s32 num_specifiers = 0;
Code lang_linkage;
Code attributes;
Code array_expr = { nullptr };
Code lang_linkage = Code::Invalid;
Code attributes = Code::Invalid;
Code array_expr = Code::Invalid;
Code specifiers = Code::Invalid;
if ( check( TokType::BraceSquare_Open ) )
{
@ -3872,6 +4315,11 @@ namespace gen
eat( currtok.Type );
}
if ( num_specifiers )
{
specifiers = def_specifiers( num_specifiers, specs_found );
}
Code type = parse_type( toks, txt(parse_variable) );
if ( type == Code::Invalid )
@ -3886,7 +4334,7 @@ namespace gen
name = currtok;
eat( TokType::Identifier );
Code expr = { nullptr };
Code expr = Code::Invalid;
if ( currtok.IsAssign )
{
@ -3927,10 +4375,28 @@ namespace gen
if ( attributes )
result->add_entry( attributes );
if (specifiers)
result->add_entry( specifiers );
if ( expr )
result->add_entry( expr );
result.lock();
return result;
}
Code parse_variable( s32 length, char const* def )
{
# define context txt(parse_variable)
using namespace Parser;
check_parse_args( parse_variable, length, def );
TokArray toks = lex( length, def );
if ( toks.Arr == nullptr )
return Code::Invalid;
return parse_variable( toks, txt(parse_variable) );
# undef context
}
@ -4040,17 +4506,10 @@ namespace gen
# undef context
}
Code parse_typedef( s32 length, char const* def )
Code parse_typedef( Parser::TokArray& toks, char const* context )
{
using namespace Parser;
# define context parse_typedef
check_parse_args( parse_typedef, length, def );
TokArray toks = lex( length, def );
if ( toks.Arr == nullptr )
return Code::Invalid;
Token name = { nullptr, 0, TokType::Invalid };
Code array_expr = { nullptr };
Code type = { nullptr };
@ -4086,20 +4545,41 @@ namespace gen
result.lock();
return result;
# undef context
}
Code parse_using( s32 length, char const* def )
Code parse_typedef( s32 length, char const* def )
{
using namespace Parser;
# define context parse_using
check_parse_args( parse_using, length, def );
# define context parse_typedef
check_parse_args( parse_typedef, length, def );
TokArray toks = lex( length, def );
if ( toks.Arr == nullptr )
return Code::Invalid;
return parse_typedef( toks, txt(parse_typedef) );
# undef context
}
Code parse_union( Parser::TokArray& toks, char const* context )
{
using namespace Parser;
return Code::Invalid;
}
Code parse_union( s32 length, char const* def )
{
using namespace Parser;
return Code::Invalid;
}
Code parse_using( Parser::TokArray& toks, char const* context )
{
using namespace Parser;
SpecifierT specs_found[16] { ESpecifier::Num_Specifiers };
s32 num_specifiers = 0;
@ -4144,6 +4624,20 @@ namespace gen
result.lock();
return result;
}
Code parse_using( s32 length, char const* def )
{
# define context parse_using
using namespace Parser;
check_parse_args( parse_using, length, def );
TokArray toks = lex( length, def );
if ( toks.Arr == nullptr )
return Code::Invalid;
return parse_using( toks, txt(parse_using) );
# undef context
}
@ -4192,6 +4686,11 @@ namespace gen
not_implemented( parse_typedefs );
}
s32 parse_unions( s32 length, char const* union_defs, Code* out_union_codes )
{
not_implemented( parse_unions );
}
s32 parse_usings( s32 length, char const* usings_def, Code* out_using_codes )
{
not_implemented( parse_usings );

View File

@ -73,6 +73,8 @@ namespace gen
Entry( Typedef ) \
Entry( Typename ) \
Entry( Union ) \
Entry( Union_Fwd ) \
Entry( Union_Body) \
Entry( Using ) \
Entry( Using_Namespace )
@ -726,6 +728,7 @@ namespace gen
Code def_struct ( s32 length, char const* name, Code parent = NoCode, Code specifiers = NoCode, Code body = NoCode );
Code def_typedef ( s32 length, char const* name, Code type );
Code def_type ( s32 length, char const* name, Code specifiers = NoCode, Code ArrayExpr = NoCode );
Code def_union ( s32 length, char const* name, Code body = NoCode );
Code def_using ( s32 length, char const* name, Code type = NoCode, UsingT specifier = UsingRegular );
Code def_variable ( Code type, s32 length, char const* name, Code value = NoCode, Code specifiers = NoCode );
@ -747,6 +750,8 @@ namespace gen
Code def_specifiers ( s32 num, SpecifierT* specs );
Code def_struct_body ( s32 num, ... );
Code def_struct_body ( s32 num, Code* codes );
Code def_union_body ( s32 num, ... );
Code def_union_body ( s32 num, Code* codes );
# pragma endregion Upfront
# pragma region Incremental
@ -761,6 +766,7 @@ namespace gen
Code make_params ();
Code make_specifiers ();
Code make_struct ( s32 length, char const* name, Code parent = NoCode, Code specifiers = NoCode );
Code make_union ( s32 length, char const* name );
# endif
# pragma endregion Incremental
@ -777,6 +783,7 @@ namespace gen
Code parse_variable ( s32 length, char const* var_def );
Code parse_type ( s32 length, char const* type_def );
Code parse_typedef ( s32 length, char const* typedef_def );
Code parse_union ( s32 length, char const* union_def );
Code parse_using ( s32 length, char const* using_def );
s32 parse_classes ( s32 length, char const* class_defs, Code* out_class_codes );
@ -788,6 +795,7 @@ namespace gen
s32 parse_structs ( s32 length, char const* struct_defs, Code* out_struct_codes );
s32 parse_variables ( s32 length, char const* var_defs, Code* out_var_codes );
s32 parse_typedefs ( s32 length, char const* typedef_defs, Code* out_typedef_codes );
s32 parse_unions ( s32 length, char const* union_defs, Code* out_union_codes );
s32 parse_usings ( s32 length, char const* using_defs, Code* out_using_codes );
#endif
#pragma endregion Parsing
@ -1024,16 +1032,19 @@ namespace gen
# define variable( Type_, Name_, ... ) gen::def_variable ( type_ns(Type_), txt_n_len(Name_), __VA_ARGS__ )
# define type( Value_, ... ) gen::def_type ( txt_n_len(Value_), __VA_ARGS__ )
# define type_fmt( Fmt_, ... ) gen::def_type ( bprintf( Fmt_, __VA_ARGS__ ) )
# define union( Name_, ... ) gen::def_union ( txt_n_len(Name_), __VA_ARGS__ )
# define using( Name_, Type_ ) gen::def_using ( txt_n_len(Name_), type_ns(Type_) )
# define using_namespace( Name_ ) gen::def_using_namespace( txt_n_len(Name_) )
# define class_body( ... ) gen::def_class_body ( macro_num_args( __VA_ARGS__ ), __VA_ARGS__ )
# define enum_body( ... ) gen::def_enum_body ( macro_num_args( __VA_ARGS__ ), __VA_ARGS__ )
# define extern_linkage_body( ... ) gen::def_extern_linkage_body( macro_num_args( __VA_ARGS__ ), __VA_ARGS__ )
# define global_body( ... ) gen::def_global_body ( macro_num_args( __VA_ARGS__ ), __VA_ARGS__ )
# define function_body( ... ) gen::def_function_body ( macro_num_args( __VA_ARGS__ ), __VA_ARGS__ )
# define namespace_body( ... ) gen::def_namespace_body( macro_num_args( __VA_ARGS__ ), __VA_ARGS__ )
# define operator_body( ... ) gen::def_operator_body ( macro_num_args( __VA_ARGS__ ), __VA_ARGS__ )
# define struct_body( ... ) gen::def_struct_body ( macro_num_args( __VA_ARGS__ ), __VA_ARGS__ )
# define union_body( ... ) gen::def_union_body ( macro_num_args( __VA_ARGS__ ), __VA_ARGS__ )
# ifdef GEN_FEATURE_INCREMENTAL
// Incremental
@ -1054,6 +1065,7 @@ namespace gen
# define variable_code( ... ) gen::parse_variable ( txt_n_len( __VA_ARGS__ ))
# define type_code( ... ) gen::parse_type ( txt_n_len( __VA_ARGS__ ))
# define typedef_code( ... ) gen::parse_typedef ( txt_n_len( __VA_ARGS__ ))
# define union_code( ... ) gen::parse_union ( txt_n_len( __VA_ARGS__ ))
# define using_code( ... ) gen::parse_code ( txt_n_len( __VA_ARGS__ ))
# endif

View File

@ -4,6 +4,12 @@
#ifdef gen_time
#include "gen.cpp"
using namespace gen;
int gen_main()
{
Memory::setup();