Backporting changes done on UnrealGencpp repo

Commits:
ec77e8b - Fixes while parsing EditorEngine.h
5017429 - parse_complicated_definition fix when parsing Controller.h
aac0dd5 - Add  IRISCORE_API
049b59c - Support for attributes retated to an operator or function between the return type and the identifier/op (Thanks World.h...)
97d7e6d - Fix for attributes after name in using statements
9f204e7 - Support for final specifier on class & struct definitions
f0698cc - Added support for Spec_Delete (= delete on functions and operators) [Part 3]
1f6650a - Added support for Spec_Delete (= delete on functions and operators) [Part 2]
06ac8da - Added support for Spec_Delete (= delete on functions and operators)
This commit is contained in:
Edward R. Gonzalez 2025-01-30 13:25:56 -05:00
parent f8c42a53c6
commit 16bc66c80e
10 changed files with 156 additions and 54 deletions

View File

@ -378,7 +378,7 @@ struct AST
{ {
Code InlineCmt; // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable Code InlineCmt; // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable
Code Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable // TODO(Ed): Parameters can have attributes Code Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable // TODO(Ed): Parameters can have attributes
Code Specs; // Destructor, Function, Operator, Typename, Variable Code Specs; // Class, Destructor, Function, Operator, Struct, Typename, Variable
union { union {
Code InitializerList; // Constructor Code InitializerList; // Constructor
Code ParentType; // Class, Struct, ParentType->Next has a possible list of interfaces. Code ParentType; // Class, Struct, ParentType->Next has a possible list of interfaces.

View File

@ -100,7 +100,7 @@ struct AST_Class
{ {
CodeComment InlineCmt; // Only supported by forward declarations CodeComment InlineCmt; // Only supported by forward declarations
CodeAttributes Attributes; CodeAttributes Attributes;
char _PAD_SPECS_ [ sizeof(AST*) ]; CodeSpecifiers Specs; // Support for final
CodeTypename ParentType; CodeTypename ParentType;
char _PAD_PARAMS_[ sizeof(AST*) ]; char _PAD_PARAMS_[ sizeof(AST*) ];
CodeBody Body; CodeBody Body;
@ -970,7 +970,7 @@ struct AST_Struct
{ {
CodeComment InlineCmt; CodeComment InlineCmt;
CodeAttributes Attributes; CodeAttributes Attributes;
char _PAD_SPECS_ [ sizeof(AST*) ]; CodeSpecifiers Specs; // Support for final
CodeTypename ParentType; CodeTypename ParentType;
char _PAD_PARAMS_[ sizeof(AST*) ]; char _PAD_PARAMS_[ sizeof(AST*) ];
CodeBody Body; CodeBody Body;

View File

@ -186,10 +186,16 @@ void class_to_strbuilder_def( CodeClass self, StrBuilder* result )
strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) );
} }
if ( self->Name.Len )
strbuilder_append_str( result, self->Name );
if (self->Specs && specifiers_has(self->Specs, Spec_Final) > -1)
strbuilder_append_str(result, txt(" final"));
if ( self->ParentType ) if ( self->ParentType )
{ {
Str access_level = access_spec_to_str( self->ParentAccess ); Str access_level = access_spec_to_str( self->ParentAccess );
strbuilder_append_fmt( result, "%S : %S %SB", self->Name, access_level, typename_to_strbuilder(self->ParentType) ); strbuilder_append_fmt( result, " : %S %SB", self->Name, access_level, typename_to_strbuilder(self->ParentType) );
CodeTypename interface = cast(CodeTypename, self->ParentType->Next); CodeTypename interface = cast(CodeTypename, self->ParentType->Next);
if ( interface ) if ( interface )
@ -201,10 +207,6 @@ void class_to_strbuilder_def( CodeClass self, StrBuilder* result )
interface = interface->Next ? cast(CodeTypename, interface->Next) : NullCode; interface = interface->Next ? cast(CodeTypename, interface->Next) : NullCode;
} }
} }
else if ( self->Name.Len )
{
strbuilder_append_str( result, self->Name );
}
if ( self->InlineCmt ) if ( self->InlineCmt )
{ {
@ -646,10 +648,12 @@ void fn_to_strbuilder_fwd(CodeFn self, StrBuilder* result )
strbuilder_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); strbuilder_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr );
} }
} }
}
if ( self->Specs && specifiers_has(self->Specs, Spec_Pure ) >= 0 ) if ( specifiers_has(self->Specs, Spec_Pure ) >= 0 )
strbuilder_append_str( result, txt(" = 0;") ); strbuilder_append_str( result, txt(" = 0") );
else if ( specifiers_has(self->Specs, Spec_Delete ) >= 0 )
strbuilder_append_str( result, txt(" = delete") );
}
// This is bodged in for now SOLEY for Unreal's PURE_VIRTUAL functional macro (I kept it open ended for other jank) // This is bodged in for now SOLEY for Unreal's PURE_VIRTUAL functional macro (I kept it open ended for other jank)
if ( self->SuffixSpecs ) if ( self->SuffixSpecs )
@ -1096,11 +1100,17 @@ void struct_to_strbuilder_def( CodeStruct self, StrBuilder* result )
strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) );
} }
if ( self->Name.Len )
strbuilder_append_str( result, self->Name );
if (self->Specs && specifiers_has(self->Specs, Spec_Final))
strbuilder_append_str( result, txt(" final"));
if ( self->ParentType ) if ( self->ParentType )
{ {
Str access_level = access_spec_to_str( self->ParentAccess ); Str access_level = access_spec_to_str( self->ParentAccess );
strbuilder_append_fmt( result, "%S : %S %SB", self->Name, access_level, typename_to_strbuilder(self->ParentType) ); strbuilder_append_fmt( result, " : %S %SB", access_level, typename_to_strbuilder(self->ParentType) );
CodeTypename interface = cast(CodeTypename, self->ParentType->Next); CodeTypename interface = cast(CodeTypename, self->ParentType->Next);
if ( interface ) if ( interface )
@ -1112,10 +1122,6 @@ void struct_to_strbuilder_def( CodeStruct self, StrBuilder* result )
interface = interface->Next ? cast( CodeTypename, interface->Next) : NullCode; interface = interface->Next ? cast( CodeTypename, interface->Next) : NullCode;
} }
} }
else if ( self->Name.Len )
{
strbuilder_append_str( result, self->Name );
}
if ( self->InlineCmt ) if ( self->InlineCmt )
{ {

View File

@ -33,6 +33,7 @@ enum Specifier : u32
Spec_NoExceptions, Spec_NoExceptions,
Spec_Override, Spec_Override,
Spec_Pure, Spec_Pure,
Spec_Delete,
Spec_Volatile, Spec_Volatile,
Spec_NumSpecifiers, Spec_NumSpecifiers,
Spec_UnderlyingType = 0xffffffffu Spec_UnderlyingType = 0xffffffffu
@ -67,6 +68,7 @@ inline Str spec_to_str(Specifier type)
{ "noexcept", sizeof("noexcept") - 1 }, { "noexcept", sizeof("noexcept") - 1 },
{ "override", sizeof("override") - 1 }, { "override", sizeof("override") - 1 },
{ "= 0", sizeof("= 0") - 1 }, { "= 0", sizeof("= 0") - 1 },
{ "= delete", sizeof("= delete") - 1 },
{ "volatile", sizeof("volatile") - 1 }, { "volatile", sizeof("volatile") - 1 },
}; };
return lookup[type]; return lookup[type];
@ -81,6 +83,7 @@ inline bool spec_is_trailing(Specifier specifier)
case Spec_NoExceptions: case Spec_NoExceptions:
case Spec_Override: case Spec_Override:
case Spec_Pure: case Spec_Pure:
case Spec_Delete:
case Spec_Volatile: case Spec_Volatile:
return true; return true;
default: default:

View File

@ -156,6 +156,7 @@ struct Opts_def_struct {
CodeAttributes attributes; CodeAttributes attributes;
CodeTypename* interfaces; CodeTypename* interfaces;
s32 num_interfaces; s32 num_interfaces;
CodeSpecifiers specifiers; // Only used for final specifier for now.
ModuleFlag mflags; ModuleFlag mflags;
}; };
GEN_API CodeClass def_class( Str name, Opts_def_struct opts GEN_PARAM_DEFAULT ); GEN_API CodeClass def_class( Str name, Opts_def_struct opts GEN_PARAM_DEFAULT );

View File

@ -532,6 +532,7 @@ CodeClass def_class( Str name, Opts_def_struct p )
result->Name = cache_str( name ); result->Name = cache_str( name );
result->ModuleFlags = p.mflags; result->ModuleFlags = p.mflags;
result->Attributes = p.attributes; result->Attributes = p.attributes;
result->Specs = p.specifiers;
result->ParentAccess = p.parent_access; result->ParentAccess = p.parent_access;
result->ParentType = p.parent; result->ParentType = p.parent;
if ( p.body ) if ( p.body )
@ -1065,6 +1066,7 @@ CodeStruct def_struct( Str name, Opts_def_struct p )
result->Type = CT_Struct_Fwd; result->Type = CT_Struct_Fwd;
} }
result->Attributes = p.attributes; result->Attributes = p.attributes;
result->Specs = p.specifiers;
result->ParentAccess = p.parent_access; result->ParentAccess = p.parent_access;
result->ParentType = p.parent; result->ParentType = p.parent;

View File

@ -264,7 +264,6 @@ s32 lex_preprocessor_define( LexContext* ctx )
} }
// TODO(Ed): We need to to attempt to recover from a lex failure? // TODO(Ed): We need to to attempt to recover from a lex failure?
forceinline
s32 lex_preprocessor_directive( LexContext* ctx ) s32 lex_preprocessor_directive( LexContext* ctx )
{ {
char const* hash = ctx->scanner; char const* hash = ctx->scanner;
@ -480,7 +479,6 @@ s32 lex_preprocessor_directive( LexContext* ctx )
return Lex_Continue; // Skip found token, its all handled here. return Lex_Continue; // Skip found token, its all handled here.
} }
forceinline
void lex_found_token( LexContext* ctx ) void lex_found_token( LexContext* ctx )
{ {
if ( ctx->token.Type != Tok_Invalid ) { if ( ctx->token.Type != Tok_Invalid ) {

View File

@ -717,6 +717,13 @@ Code parse_class_struct( TokType which, bool inplace_def )
} }
// <ModuleFlags> <class/struct> <Attributes> <Name> // <ModuleFlags> <class/struct> <Attributes> <Name>
CodeSpecifiers specifiers = NullCode;
if ( check(Tok_Spec_Final)) {
specifiers = def_specifier(Spec_Final);
eat(Tok_Spec_Final);
}
// <ModuleFlags> <class/struct> <Attributes> <Name> <final>
local_persist local_persist
char interface_arr_mem[ kilobytes(4) ] = {0}; char interface_arr_mem[ kilobytes(4) ] = {0};
Array(CodeTypename) interfaces; { Array(CodeTypename) interfaces; {
@ -728,22 +735,22 @@ Code parse_class_struct( TokType which, bool inplace_def )
if ( check( Tok_Assign_Classifer ) ) if ( check( Tok_Assign_Classifer ) )
{ {
eat( Tok_Assign_Classifer ); eat( Tok_Assign_Classifer );
// <ModuleFlags> <class/struct> <Attributes> <Name> : // <ModuleFlags> <class/struct> <Attributes> <Name> <final> :
if ( tok_is_access_specifier(currtok) ) { if ( tok_is_access_specifier(currtok) ) {
access = tok_to_access_specifier(currtok); access = tok_to_access_specifier(currtok);
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> // <ModuleFlags> <class/struct> <Attributes> <Name> <final> : <Access Specifier>
eat( currtok.Type ); eat( currtok.Type );
} }
Token parent_tok = parse_identifier(nullptr); Token parent_tok = parse_identifier(nullptr);
parent = def_type( parent_tok.Text ); parent = def_type( parent_tok.Text );
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Parent/Interface Name> // <ModuleFlags> <class/struct> <Attributes> <Name> <final> : <Access Specifier> <Parent/Interface Name>
while ( check(Tok_Comma) ) while ( check(Tok_Comma) )
{ {
eat( Tok_Comma ); eat( Tok_Comma );
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Name>, // <ModuleFlags> <class/struct> <Attributes> <Name> <final> : <Access Specifier> <Name>,
if ( tok_is_access_specifier(currtok) ) { if ( tok_is_access_specifier(currtok) ) {
eat(currtok.Type); eat(currtok.Type);
@ -751,32 +758,32 @@ Code parse_class_struct( TokType which, bool inplace_def )
Token interface_tok = parse_identifier(nullptr); Token interface_tok = parse_identifier(nullptr);
array_append( interfaces, def_type( interface_tok.Text ) ); array_append( interfaces, def_type( interface_tok.Text ) );
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Name>, ... // <ModuleFlags> <class/struct> <Attributes> <Name> <final> : <Access Specifier> <Name>, ...
} }
} }
if ( check( Tok_BraceCurly_Open ) ) { if ( check( Tok_BraceCurly_Open ) ) {
body = parse_class_struct_body( which, name ); body = parse_class_struct_body( which, name );
} }
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Name>, ... { <Body> } // <ModuleFlags> <class/struct> <Attributes> <Name> <final> : <Access Specifier> <Name>, ... { <Body> }
CodeComment inline_cmt = NullCode; CodeComment inline_cmt = NullCode;
if ( ! inplace_def ) if ( ! inplace_def )
{ {
Token stmt_end = currtok; Token stmt_end = currtok;
eat( Tok_Statement_End ); eat( Tok_Statement_End );
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Name>, ... { <Body> }; // <ModuleFlags> <class/struct> <Attributes> <Name> <final> : <Access Specifier> <Name>, ... { <Body> };
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line ) if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
inline_cmt = parse_comment(); inline_cmt = parse_comment();
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Name>, ... { <Body> }; <InlineCmt> // <ModuleFlags> <class/struct> <Attributes> <Name> <final> : <Access Specifier> <Name>, ... { <Body> }; <InlineCmt>
} }
if ( which == Tok_Decl_Class ) if ( which == Tok_Decl_Class )
result = cast(Code, def_class( name.Text, def_assign( body, parent, access, attributes, interfaces, scast(s32, array_num(interfaces)), mflags ) )); result = cast(Code, def_class( name.Text, def_assign( body, parent, access, attributes, interfaces, scast(s32, array_num(interfaces)), specifiers, mflags ) ));
else else
result = cast(Code, def_struct( name.Text, def_assign( body, (CodeTypename)parent, access, attributes, interfaces, scast(s32, array_num(interfaces)), mflags ) )); result = cast(Code, def_struct( name.Text, def_assign( body, (CodeTypename)parent, access, attributes, interfaces, scast(s32, array_num(interfaces)), specifiers, mflags ) ));
if ( inline_cmt ) if ( inline_cmt )
result->InlineCmt = cast(Code, inline_cmt); result->InlineCmt = cast(Code, inline_cmt);
@ -947,10 +954,6 @@ CodeBody parse_class_struct_body( TokType which, Token name )
member = cast(Code, parse_simple_preprocess( Tok_Preprocess_Macro_Stmt )); member = cast(Code, parse_simple_preprocess( Tok_Preprocess_Macro_Stmt ));
break; break;
} }
case Tok_Preprocess_Macro_Expr: {
log_failure("Unbounded macro expression residing in class/struct body\n%S", parser_to_strbuilder(_ctx->parser));
return InvalidCode;
}
// case Tok_Preprocess_Macro: // case Tok_Preprocess_Macro:
// // <Macro> // // <Macro>
@ -976,6 +979,15 @@ CodeBody parse_class_struct_body( TokType which, Token name )
break; break;
} }
case Tok_Preprocess_Macro_Expr:
{
if ( ! tok_is_attribute(currtok))
{
log_failure("Unbounded macro expression residing in class/struct body\n%S", parser_to_strbuilder(_ctx->parser));
return InvalidCode;
}
}
//! Fallthrough intended
case Tok_Attribute_Open: case Tok_Attribute_Open:
case Tok_Decl_GNU_Attribute: case Tok_Decl_GNU_Attribute:
case Tok_Decl_MSVC_Attribute: case Tok_Decl_MSVC_Attribute:
@ -1143,27 +1155,44 @@ Code parse_complicated_definition( TokType which )
{ {
push_scope(); push_scope();
bool is_inplace = false; b32 is_inplace = false;
b32 is_fn_def = false;
TokArray tokens = _ctx->parser.Tokens; TokArray tokens = _ctx->parser.Tokens;
s32 idx = tokens.Idx; s32 idx = tokens.Idx;
s32 level = 0; s32 level = 0;
b32 had_def = false;
b32 had_paren = false;
for ( ; idx < array_num(tokens.Arr); idx++ ) for ( ; idx < array_num(tokens.Arr); idx++ )
{ {
if ( tokens.Arr[ idx ].Type == Tok_BraceCurly_Open ) if ( tokens.Arr[ idx ].Type == Tok_BraceCurly_Open )
level++; level++;
if ( tokens.Arr[ idx ].Type == Tok_BraceCurly_Close ) if ( tokens.Arr[ idx ].Type == Tok_BraceCurly_Close ) {
level--; level--;
had_def = level == 0;
}
if ( level == 0 && tokens.Arr[ idx ].Type == Tok_Statement_End ) b32 found_fn_def = had_def && had_paren;
if ( level == 0 && (tokens.Arr[ idx ].Type == Tok_Statement_End || found_fn_def) )
break; break;
} }
is_fn_def = had_def && had_paren;
if (is_fn_def)
{
// Function definition with <which> on return type
Code result = parse_operator_function_or_variable(false, NullCode, NullCode);
// <which> <typename>(...) ... { ... }
parser_pop(& _ctx->parser);
return result;
}
if ( ( idx - 2 ) == tokens.Idx ) if ( ( idx - 2 ) == tokens.Idx )
{ {
// Its a forward declaration only // It's a forward declaration only
Code result = parse_forward_or_definition( which, is_inplace ); Code result = parse_forward_or_definition( which, is_inplace );
// <class, enum, struct, or union> <Name>; // <class, enum, struct, or union> <Name>;
parser_pop(& _ctx->parser); parser_pop(& _ctx->parser);
@ -1427,12 +1456,26 @@ CodeFn parse_function_after_name(
else if ( check(Tok_Operator) && currtok.Text.Ptr[0] == '=' ) else if ( check(Tok_Operator) && currtok.Text.Ptr[0] == '=' )
{ {
eat(Tok_Operator); eat(Tok_Operator);
if ( specifiers == nullptr )
{
specifiers = (CodeSpecifiers) make_code();
specifiers->Type = CT_Specifiers;
}
if ( str_are_equal(nexttok.Text, txt("delete")))
{
specifiers_append(specifiers, Spec_Delete);
eat(currtok.Type);
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers> = delete
}
else
{
specifiers_append(specifiers, Spec_Pure ); specifiers_append(specifiers, Spec_Pure );
eat( Tok_Number); eat( Tok_Number);
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers> = 0
}
Token stmt_end = currtok; Token stmt_end = currtok;
eat( Tok_Statement_End ); eat( Tok_Statement_End );
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers> = 0;
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line ) if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
inline_cmt = parse_comment(); inline_cmt = parse_comment();
@ -1684,10 +1727,6 @@ CodeBody parse_global_nspace( CodeType which )
member = cast(Code, parse_simple_preprocess( Tok_Preprocess_Macro_Stmt )); member = cast(Code, parse_simple_preprocess( Tok_Preprocess_Macro_Stmt ));
break; break;
} }
case Tok_Preprocess_Macro_Expr: {
log_failure("Unbounded macro expression residing in class/struct body\n%S", parser_to_strbuilder(_ctx->parser));
return InvalidCode;
}
case Tok_Preprocess_Pragma: { case Tok_Preprocess_Pragma: {
member = cast(Code, parse_pragma()); member = cast(Code, parse_pragma());
@ -1721,6 +1760,16 @@ CodeBody parse_global_nspace( CodeType which )
log_failure( "gen::%s: This function is not implemented" ); log_failure( "gen::%s: This function is not implemented" );
return InvalidCode; return InvalidCode;
} }
break;
case Tok_Preprocess_Macro_Expr:
{
if (tok_is_attribute(currtok))
{
log_failure("Unbounded macro expression residing in class/struct body\n%S", parser_to_strbuilder(_ctx->parser));
return InvalidCode;
}
}
//! Fallthrough intentional //! Fallthrough intentional
case Tok_Attribute_Open: case Tok_Attribute_Open:
case Tok_Decl_GNU_Attribute: case Tok_Decl_GNU_Attribute:
@ -1995,6 +2044,10 @@ Token parse_identifier( bool* possible_member_function )
Token name = currtok; Token name = currtok;
_ctx->parser.Scope->Name = name.Text; _ctx->parser.Scope->Name = name.Text;
// Typename can be: '::' <name>
// If that is the case first option will be Tok_Access_StaticSymbol below
if (check(Tok_Identifier))
eat( Tok_Identifier ); eat( Tok_Identifier );
// <Name> // <Name>
@ -2416,6 +2469,25 @@ CodeOperator parse_operator_after_ret_type(
} }
// <ExportFlag> <Attributes> <Specifiers> <ReturnType> <Qualifier::...> operator <Op> ( <Parameters> ) <Specifiers> // <ExportFlag> <Attributes> <Specifiers> <ReturnType> <Qualifier::...> operator <Op> ( <Parameters> ) <Specifiers>
// TODO(Ed): Add proper "delete" and "new" awareness
// We're dealing with either a "= delete" or operator deletion
if (check(Tok_Operator) && currtok.Text.Ptr[0] == '=')
{
eat(currtok.Type);
if ( ! str_are_equal(currtok.Text, txt("delete")))
{
log_failure("Expected delete after = in operator forward instead found \"%S\"\n%SB", currtok.Text, parser_to_strbuilder(_ctx->parser));
parser_pop(& _ctx->parser);
return InvalidCode;
}
if (specifiers == nullptr)
specifiers = def_specifier( Spec_Delete );
else
specifiers_append(specifiers, Spec_Delete);
eat(currtok.Type);
// <ExportFlag> <Attributes> <Specifiers> <ReturnType> <Qualifier::...> operator <Op> ( <Parameters> ) <Specifiers> = delete
}
// Parse Body // Parse Body
CodeBody body = { nullptr }; CodeBody body = { nullptr };
CodeComment inline_cmt = NullCode; CodeComment inline_cmt = NullCode;
@ -2466,6 +2538,24 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes
CodeTypename type = parser_parse_type( parser_not_from_template, nullptr ); CodeTypename type = parser_parse_type( parser_not_from_template, nullptr );
// <Attributes> <Specifiers> <ReturnType/ValueType> // <Attributes> <Specifiers> <ReturnType/ValueType>
// Thanks Unreal
CodeAttributes post_rt_attributes = parse_attributes();
if (post_rt_attributes)
{
if (attributes)
{
StrBuilder merged = strbuilder_fmt_buf(_ctx->Allocator_Temp, "%S %S", attributes->Content, post_rt_attributes->Content);
attributes->Content = cache_str(strbuilder_to_str(merged));
}
else
{
attributes = post_rt_attributes;
}
// <Attributes> <Specifiers> <ReturnType/ValueType> <Attributes>
// CONVERTED TO:
// <Attributes> <Specifiers> <ReturnType/ValueType>
}
if ( type == InvalidCode ) { if ( type == InvalidCode ) {
parser_pop(& _ctx->parser); parser_pop(& _ctx->parser);
return InvalidCode; return InvalidCode;
@ -2713,10 +2803,8 @@ CodeParams parse_params( bool use_template_capture )
// ( <Macro> <ValueType> <Name> <PostNameMacro> // ( <Macro> <ValueType> <Name> <PostNameMacro>
} }
// In template captures you can have a typename have direct assignment without a name // C++ allows typename = expression... so anything goes....
// typename = typename ... if ( bitfield_is_set( u32, currtok.Flags, TF_Assign ) )
// Which would result in a static value type from a struct expansion (traditionally)
if ( ( name.Text.Ptr || use_template_capture ) && bitfield_is_set( u32, currtok.Flags, TF_Assign ) )
{ {
eat( Tok_Operator ); eat( Tok_Operator );
// ( <Macro> <ValueType> <Name> = // ( <Macro> <ValueType> <Name> =
@ -2824,10 +2912,8 @@ CodeParams parse_params( bool use_template_capture )
// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <PostNameMacro> // ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <PostNameMacro>
} }
// In template captures you can have a typename have direct assignment without a name /// C++ allows typename = expression... so anything goes....
// typename = typename ... if ( bitfield_is_set( u32, currtok.Flags, TF_Assign ) )
// Which would result in a static value type from a struct expansion (traditionally)
if ( ( name.Text.Ptr || use_template_capture ) && bitfield_is_set( u32, currtok.Flags, TF_Assign ) )
{ {
eat( Tok_Operator ); eat( Tok_Operator );
// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name> <PostNameMacro> = // ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name> <PostNameMacro> =
@ -3451,6 +3537,7 @@ CodeConstructor parser_parse_constructor( CodeSpecifiers specifiers )
body = cast(CodeBody, parse_function_body()); body = cast(CodeBody, parse_function_body());
// <Name> ( <Parameters> ) { <Body> } // <Name> ( <Parameters> ) { <Body> }
} }
// TODO(Ed): Add support for detecting constructor deletion
else if ( check( Tok_Operator) && currtok.Text.Ptr[ 0 ] == '=' ) else if ( check( Tok_Operator) && currtok.Text.Ptr[ 0 ] == '=' )
{ {
body = cast(CodeBody, parse_assignment_expression()); body = cast(CodeBody, parse_assignment_expression());
@ -5438,6 +5525,9 @@ CodeUsing parser_parse_using()
if ( ! is_namespace ) if ( ! is_namespace )
{ {
attributes = parse_attributes();
// <ModuleFlags> using <Name> <Attributes>
if ( bitfield_is_set( u32, currtok.Flags, TF_Assign )) if ( bitfield_is_set( u32, currtok.Flags, TF_Assign ))
{ {
attributes = parse_attributes(); attributes = parse_attributes();

View File

@ -24,4 +24,5 @@ Final, final
NoExceptions, noexcept NoExceptions, noexcept
Override, override Override, override
Pure, = 0 Pure, = 0
Delete, = delete
Volatile, volatile Volatile, volatile

1 Invalid INVALID
24 NoExceptions noexcept
25 Override override
26 Pure = 0
27 Delete = delete
28 Volatile volatile

View File

@ -220,6 +220,7 @@ CodeBody gen_especifier( char const* path, bool use_c_definition = false )
case Spec_NoExceptions: case Spec_NoExceptions:
case Spec_Override: case Spec_Override:
case Spec_Pure: case Spec_Pure:
case Spec_Delete:
case Spec_Volatile: case Spec_Volatile:
return true; return true;