mirror of
https://github.com/Ed94/gencpp.git
synced 2024-12-22 07:44:45 -08:00
Unreal parsing support: Added MF_Allow_As_Attribute & MF_Allow_As_Definition
This commit is contained in:
parent
572e957c17
commit
0b03b3cd92
@ -42,6 +42,7 @@ struct AST_Body
|
|||||||
};
|
};
|
||||||
static_assert( sizeof(AST_Body) == sizeof(AST), "ERROR: AST_Body is not the same size as AST");
|
static_assert( sizeof(AST_Body) == sizeof(AST), "ERROR: AST_Body is not the same size as AST");
|
||||||
|
|
||||||
|
// TODO(Ed): Support chaining attributes (Use parameter linkage pattern)
|
||||||
struct AST_Attributes
|
struct AST_Attributes
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
|
@ -473,6 +473,7 @@ void register_macro( Macro macro ) {
|
|||||||
GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
|
GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
|
||||||
GEN_ASSERT(macro.Name.Len > 0);
|
GEN_ASSERT(macro.Name.Len > 0);
|
||||||
u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
|
u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
|
||||||
|
macro.Name = cache_str(macro.Name);
|
||||||
hashtable_set( _ctx->Macros, key, macro );
|
hashtable_set( _ctx->Macros, key, macro );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,6 +487,7 @@ void register_macros( s32 num, ... )
|
|||||||
Macro macro = va_arg(va, Macro);
|
Macro macro = va_arg(va, Macro);
|
||||||
GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
|
GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
|
||||||
GEN_ASSERT(macro.Name.Len > 0);
|
GEN_ASSERT(macro.Name.Len > 0);
|
||||||
|
macro.Name = cache_str(macro.Name);
|
||||||
|
|
||||||
u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
|
u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
|
||||||
hashtable_set( _ctx->Macros, key, macro );
|
hashtable_set( _ctx->Macros, key, macro );
|
||||||
@ -502,6 +504,7 @@ void register_macros( s32 num, Macro* macros )
|
|||||||
Macro macro = * macros;
|
Macro macro = * macros;
|
||||||
GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
|
GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
|
||||||
GEN_ASSERT(macro.Name.Len > 0);
|
GEN_ASSERT(macro.Name.Len > 0);
|
||||||
|
macro.Name = cache_str(macro.Name);
|
||||||
|
|
||||||
u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
|
u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
|
||||||
hashtable_set( _ctx->Macros, key, macro );
|
hashtable_set( _ctx->Macros, key, macro );
|
||||||
|
@ -532,45 +532,24 @@ void lex_found_token( LexContext* ctx )
|
|||||||
ctx->token.Type = macrotype_to_toktype(macro->Type);
|
ctx->token.Type = macrotype_to_toktype(macro->Type);
|
||||||
b32 is_functional = macro_is_functional(* macro);
|
b32 is_functional = macro_is_functional(* macro);
|
||||||
resolved_to_macro = has_args ? is_functional : ! is_functional;
|
resolved_to_macro = has_args ? is_functional : ! is_functional;
|
||||||
|
if ( ! resolved_to_macro ) {
|
||||||
|
log_fmt("Info(%d, %d): %S identified as a macro but usage here does not resolve to one (interpreting as identifier)\n"
|
||||||
|
, ctx->token.Line
|
||||||
|
, ctx->token.Line
|
||||||
|
, macro->Name
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ( resolved_to_macro )
|
if ( resolved_to_macro )
|
||||||
{
|
{
|
||||||
// TODO(Ed): When we introduce a macro AST (and expression support), we'll properly lex this section.
|
// TODO(Ed): When we introduce a macro AST (and expression support), we'll properly lex this section.
|
||||||
// Want to ignore any arguments the define may have as they can be execution expressions.
|
// Want to ignore any arguments the define may have as they can be execution expressions.
|
||||||
if ( has_args )
|
if ( has_args ) {
|
||||||
{
|
|
||||||
ctx->token.Flags |= TF_Macro_Functional;
|
ctx->token.Flags |= TF_Macro_Functional;
|
||||||
|
|
||||||
// move_forward();
|
|
||||||
// ctx->token.Text.Len++;
|
|
||||||
|
|
||||||
// s32 level = 0;
|
|
||||||
// while ( ctx->left && ((* ctx->scanner) != ')' || level > 0) )
|
|
||||||
// {
|
|
||||||
// if ( (* ctx->scanner) == '(' )
|
|
||||||
// level++;
|
|
||||||
|
|
||||||
// else if ( (* ctx->scanner) == ')' && level > 0 )
|
|
||||||
// level--;
|
|
||||||
|
|
||||||
// move_forward();
|
|
||||||
// ctx->token.Text.Len++;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// move_forward();
|
|
||||||
// ctx->token.Text.Len++;
|
|
||||||
}
|
}
|
||||||
|
if ( bitfield_is_set(MacroFlags, macro->Flags, MF_Allow_As_Attribute) ) {
|
||||||
//if ( (* ctx->scanner) == '\r' && ctx->scanner[1] == '\n' )
|
ctx->token.Flags |= TF_Attribute;
|
||||||
//{
|
}
|
||||||
// move_forward();
|
|
||||||
// ctx->token..Text.Length++;
|
|
||||||
//}
|
|
||||||
//else if ( (* ctx->scanner) == '\n' )
|
|
||||||
//{
|
|
||||||
// move_forward();
|
|
||||||
// ctx->token..Text.Length++;
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -204,6 +204,7 @@ internal CodeBody parse_global_nspace ( CodeType which
|
|||||||
internal Code parse_global_nspace_constructor_destructor( CodeSpecifiers specifiers );
|
internal Code parse_global_nspace_constructor_destructor( CodeSpecifiers specifiers );
|
||||||
internal Token parse_identifier ( bool* possible_member_function );
|
internal Token parse_identifier ( bool* possible_member_function );
|
||||||
internal CodeInclude parse_include ();
|
internal CodeInclude parse_include ();
|
||||||
|
internal Code parse_macro_as_definiton ( CodeAttributes attributes, CodeSpecifiers specifiers );
|
||||||
internal CodeOperator parse_operator_after_ret_type ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeTypename ret_type );
|
internal CodeOperator parse_operator_after_ret_type ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeTypename ret_type );
|
||||||
internal Code parse_operator_function_or_variable( bool expects_function, CodeAttributes attributes, CodeSpecifiers specifiers );
|
internal Code parse_operator_function_or_variable( bool expects_function, CodeAttributes attributes, CodeSpecifiers specifiers );
|
||||||
internal CodePragma parse_pragma ();
|
internal CodePragma parse_pragma ();
|
||||||
@ -578,7 +579,7 @@ CodeAttributes parse_attributes()
|
|||||||
s32 len = 0;
|
s32 len = 0;
|
||||||
|
|
||||||
// There can be more than one attribute. If there is flatten them to a single string.
|
// There can be more than one attribute. If there is flatten them to a single string.
|
||||||
// TODO(Ed): Support keeping an linked list of attributes similar to parameters
|
// TODO(Ed): Support chaining attributes (Use parameter linkage pattern)
|
||||||
while ( left && tok_is_attribute(currtok) )
|
while ( left && tok_is_attribute(currtok) )
|
||||||
{
|
{
|
||||||
if ( check( Tok_Attribute_Open ) )
|
if ( check( Tok_Attribute_Open ) )
|
||||||
@ -2434,6 +2435,12 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes
|
|||||||
|
|
||||||
Code result = InvalidCode;
|
Code result = InvalidCode;
|
||||||
|
|
||||||
|
Code macro_stmt = parse_macro_as_definiton(attributes, specifiers);
|
||||||
|
if (macro_stmt) {
|
||||||
|
parser_pop(& _ctx->parser);
|
||||||
|
return macro_stmt;
|
||||||
|
}
|
||||||
|
|
||||||
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>
|
||||||
|
|
||||||
@ -2506,6 +2513,36 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal
|
||||||
|
Code parse_macro_as_definiton( CodeAttributes attributes, CodeSpecifiers specifiers )
|
||||||
|
{
|
||||||
|
push_scope();
|
||||||
|
|
||||||
|
if (currtok.Type != Tok_Preprocess_Macro_Stmt ) {
|
||||||
|
parser_pop(& _ctx->parser);
|
||||||
|
return NullCode;
|
||||||
|
}
|
||||||
|
Macro* macro = lookup_macro(currtok.Text);
|
||||||
|
b32 can_resolve_to_definition = macro && bitfield_is_set(MacroFlags, macro->Flags, MF_Allow_As_Definition);
|
||||||
|
if ( ! can_resolve_to_definition) {
|
||||||
|
parser_pop(& _ctx->parser);
|
||||||
|
return NullCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(Ed): When AST_Macro is made, have it support attributs and specifiers for when its behaving as a declaration/definition.
|
||||||
|
Code code = parse_simple_preprocess( Tok_Preprocess_Macro_Stmt );
|
||||||
|
|
||||||
|
// Attributes and sepcifiers will be collapsed into the macro's serialization.
|
||||||
|
StrBuilder resolved_definition = strbuilder_fmt_buf(_ctx->Allocator_Temp, "%S %S %S"
|
||||||
|
, attributes ? strbuilder_to_str( attributes_to_strbuilder(attributes)) : txt("")
|
||||||
|
, specifiers ? strbuilder_to_str( specifiers_to_strbuilder(specifiers)) : txt("")
|
||||||
|
, code->Content
|
||||||
|
);
|
||||||
|
Code result = untyped_str( strbuilder_to_str(resolved_definition) );
|
||||||
|
parser_pop(& _ctx->parser);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
internal
|
internal
|
||||||
CodePragma parse_pragma()
|
CodePragma parse_pragma()
|
||||||
{
|
{
|
||||||
@ -3761,8 +3798,11 @@ CodeEnum parser_parse_enum( bool inplace_def )
|
|||||||
|
|
||||||
// Unreal UMETA macro support
|
// Unreal UMETA macro support
|
||||||
if ( currtok.Type == Tok_Preprocess_Macro_Expr ) {
|
if ( currtok.Type == Tok_Preprocess_Macro_Expr ) {
|
||||||
eat( Tok_Preprocess_Macro_Expr );
|
Code macro = parse_simple_preprocess( Tok_Preprocess_Macro_Expr );
|
||||||
// <Name> = <Expression> <Macro>
|
// <Name> = <Expression> <Macro>
|
||||||
|
|
||||||
|
// We're intentially ignoring this code as its going to be serialized as an untyped string with the rest of the enum "entry".
|
||||||
|
// TODO(Ed): We need a CodeEnumEntry, AST_EnumEntry types
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( currtok.Type == Tok_Comma )
|
if ( currtok.Type == Tok_Comma )
|
||||||
@ -4060,6 +4100,13 @@ CodeFn parser_parse_function()
|
|||||||
}
|
}
|
||||||
// <export> <Attributes> <Specifiers>
|
// <export> <Attributes> <Specifiers>
|
||||||
|
|
||||||
|
// Note(Ed): We're enforcing that using this codepath requires non-macro jank.
|
||||||
|
// Code macro_stmt = parse_macro_as_definiton(attributes, specifiers);
|
||||||
|
// if (macro_stmt) {
|
||||||
|
// parser_pop(& _ctx->parser);
|
||||||
|
// return macro_stmt;
|
||||||
|
// }
|
||||||
|
|
||||||
CodeTypename ret_type = parser_parse_type(parser_not_from_template, nullptr);
|
CodeTypename ret_type = parser_parse_type(parser_not_from_template, nullptr);
|
||||||
if ( cast(Code, ret_type) == Code_Invalid ) {
|
if ( cast(Code, ret_type) == Code_Invalid ) {
|
||||||
parser_pop(& _ctx->parser);
|
parser_pop(& _ctx->parser);
|
||||||
@ -5448,6 +5495,13 @@ CodeVar parser_parse_variable()
|
|||||||
}
|
}
|
||||||
// <ModuleFlags> <Attributes> <Specifiers>
|
// <ModuleFlags> <Attributes> <Specifiers>
|
||||||
|
|
||||||
|
// Note(Ed): We're enforcing that using this codepath requires non-macro jank.
|
||||||
|
// Code macro_stmt = parse_macro_as_definiton(attributes, specifiers);
|
||||||
|
// if (macro_stmt) {
|
||||||
|
// parser_pop(& _ctx->parser);
|
||||||
|
// return macro_stmt;
|
||||||
|
// }
|
||||||
|
|
||||||
CodeTypename type = parser_parse_type(parser_not_from_template, nullptr);
|
CodeTypename type = parser_parse_type(parser_not_from_template, nullptr);
|
||||||
// <ModuleFlags> <Attributes> <Specifiers> <ValueType>
|
// <ModuleFlags> <Attributes> <Specifiers> <ValueType>
|
||||||
|
|
||||||
|
@ -177,8 +177,22 @@ enum EMacroFlags : u16
|
|||||||
{
|
{
|
||||||
MF_Functional = bit(0), // Macro has parameters (args expected to be passed)
|
MF_Functional = bit(0), // Macro has parameters (args expected to be passed)
|
||||||
MF_Expects_Body = bit(1), // Expects to assign a braced scope to its body.
|
MF_Expects_Body = bit(1), // Expects to assign a braced scope to its body.
|
||||||
MF_Allow_As_Identifier = bit(2), // lex__eat wil treat this macro as an identifier if the parser attempts to consume it as one.
|
|
||||||
// ^^^ This is a sort of kludge because we don't support push/pop macro programs rn. ^^^
|
// lex__eat wil treat this macro as an identifier if the parser attempts to consume it as one.
|
||||||
|
// ^^^ This is a kludge because we don't support push/pop macro pragmas rn.
|
||||||
|
MF_Allow_As_Identifier = bit(2),
|
||||||
|
|
||||||
|
// lex__eat wil treat this macro as an attribute if the parser attempts to consume it as one.
|
||||||
|
// ^^^ This a kludge because unreal has a macro that behaves as both a 'statement' and an attribute (UE_DEPRECATED, PRAGMA_ENABLE_DEPRECATION_WARNINGS, etc)
|
||||||
|
// TODO(Ed): We can keep the MF_Allow_As_Attribute flag for macros, however, we need to add the ability of AST_Attributes to chain themselves.
|
||||||
|
// Its thats already a thing in the standard language anyway
|
||||||
|
// & it would allow UE_DEPRECATED, (UE_PROPERTY / UE_FUNCTION) to chain themselves as attributes of a resolved member function/varaible definition
|
||||||
|
MF_Allow_As_Attribute = bit(3),
|
||||||
|
|
||||||
|
// When a macro is encountered after attributs and specifiers while parsing a function, or variable:
|
||||||
|
// It will consume the macro and treat it as resolving the definition. (Yes this is for Unreal Engine)
|
||||||
|
// (MUST BE OF MT_Statement TYPE)
|
||||||
|
MF_Allow_As_Definition = bit(4),
|
||||||
|
|
||||||
MF_Null = 0,
|
MF_Null = 0,
|
||||||
MF_UnderlyingType = GEN_U16_MAX,
|
MF_UnderlyingType = GEN_U16_MAX,
|
||||||
|
Loading…
Reference in New Issue
Block a user