2023-11-20 12:09:01 -08:00
|
|
|
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
|
|
|
#pragma once
|
|
|
|
#include "gen/etoktype.cpp"
|
|
|
|
#include "interface.upfront.cpp"
|
2023-11-22 11:23:21 -08:00
|
|
|
#include "lexer.cpp"
|
2023-11-20 12:09:01 -08:00
|
|
|
#endif
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
GEN_NS_PARSER_BEGIN
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
// TODO(Ed) : Rename ETok_Capture_Start, ETok_Capture_End to Open_Parenthesis adn Close_Parenthesis
|
2023-11-22 11:23:21 -08:00
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
constexpr bool dont_skip_formatting = false;
|
2024-12-02 19:25:39 -08:00
|
|
|
constexpr bool skip_formatting = true;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
struct StackNode
|
|
|
|
{
|
|
|
|
StackNode* Prev;
|
|
|
|
|
|
|
|
Token Start;
|
|
|
|
Token Name; // The name of the AST node (if parsed)
|
|
|
|
StrC ProcName; // The name of the procedure
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ParseContext
|
|
|
|
{
|
|
|
|
TokArray Tokens;
|
|
|
|
StackNode* Scope;
|
2024-12-03 06:31:27 -08:00
|
|
|
};
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
void push( ParseContext* ctx, StackNode* node )
|
|
|
|
{
|
|
|
|
node->Prev = ctx->Scope;
|
|
|
|
ctx->Scope = node;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
#if 0 && Build_Debug
|
|
|
|
log_fmt("\tEntering Context: %.*s\n", Scope->ProcName.Len, Scope->ProcName.Ptr );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void pop(ParseContext* ctx)
|
|
|
|
{
|
|
|
|
#if 0 && Build_Debug
|
|
|
|
log_fmt("\tPopping Context: %.*s\n", Scope->ProcName.Len, Scope->ProcName.Ptr );
|
|
|
|
#endif
|
|
|
|
ctx->Scope = ctx->Scope->Prev;
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
String to_string(ParseContext ctx)
|
|
|
|
{
|
|
|
|
String result = string_make_reserve( GlobalAllocator, kilobytes(4) );
|
|
|
|
|
|
|
|
Token scope_start = ctx.Scope->Start;
|
2024-12-04 08:01:53 -08:00
|
|
|
Token last_valid = ctx.Tokens.Idx >= array_num(ctx.Tokens.Arr) ? ctx.Tokens.Arr[array_num(ctx.Tokens.Arr) -1] : (* current(& ctx.Tokens, true));
|
2024-12-03 06:31:27 -08:00
|
|
|
|
|
|
|
sptr length = scope_start.Length;
|
|
|
|
char const* current = scope_start.Text + length;
|
2024-12-04 21:40:51 -08:00
|
|
|
while ( current <= array_back( ctx.Tokens.Arr)->Text && *current != '\n' && length < 74 )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
current++;
|
|
|
|
length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
String line = string_make_strc( GlobalAllocator, { length, scope_start.Text } );
|
|
|
|
string_append_fmt( & result, "\tScope : %s\n", line );
|
|
|
|
string_free(& line);
|
2024-12-03 06:31:27 -08:00
|
|
|
|
|
|
|
sptr dist = (sptr)last_valid.Text - (sptr)scope_start.Text + 2;
|
|
|
|
sptr length_from_err = dist;
|
2024-12-04 08:01:53 -08:00
|
|
|
String line_from_err = string_make_strc( GlobalAllocator, { length_from_err, last_valid.Text } );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
if ( length_from_err < 100 )
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_fmt(& result, "\t(%d, %d):%*c\n", last_valid.Line, last_valid.Column, length_from_err, '^' );
|
2024-12-03 06:31:27 -08:00
|
|
|
else
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_fmt(& result, "\t(%d, %d)\n", last_valid.Line, last_valid.Column );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
StackNode* curr_scope = ctx.Scope;
|
|
|
|
s32 level = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if ( is_valid(curr_scope->Name) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_fmt(& result, "\t%d: %s, AST Name: %.*s\n", level, curr_scope->ProcName.Ptr, curr_scope->Name.Length, curr_scope->Name.Text );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_fmt(& result, "\t%d: %s\n", level, curr_scope->ProcName.Ptr );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:31:27 -08:00
|
|
|
|
|
|
|
curr_scope = curr_scope->Prev;
|
|
|
|
level++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:31:27 -08:00
|
|
|
while ( curr_scope );
|
|
|
|
return result;
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
global ParseContext Context;
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
bool __eat(TokArray* self, TokType type )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-04 08:01:53 -08:00
|
|
|
if ( array_num(self->Arr) - self->Idx <= 0 )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "No tokens left.\n%s", to_string(Context) );
|
2023-11-20 12:09:01 -08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
Token at_idx = self->Arr[ self->Idx ];
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ( at_idx.Type == Tok_NewLine && type != Tok_NewLine )
|
|
|
|
|| ( at_idx.Type == Tok_Comment && type != Tok_Comment ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 19:25:39 -08:00
|
|
|
self->Idx ++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
if ( at_idx.Type != type )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 19:25:39 -08:00
|
|
|
Token tok = * current( self, skip_formatting );
|
2023-11-20 12:09:01 -08:00
|
|
|
log_failure( "Parse Error, TokArray::eat, Expected: ' %s ' not ' %.*s ' (%d, %d)`\n%s"
|
2024-12-03 06:50:30 -08:00
|
|
|
, to_str(type).Ptr
|
2024-12-02 19:25:39 -08:00
|
|
|
, at_idx.Length, at_idx.Text
|
|
|
|
, tok.Line
|
|
|
|
, tok.Column
|
2024-12-03 06:31:27 -08:00
|
|
|
, to_string(Context)
|
2023-11-20 12:09:01 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0 && Build_Debug
|
2024-12-02 19:25:39 -08:00
|
|
|
log_fmt("Ate: %S\n", self->Arr[Idx].to_string() );
|
2023-11-20 12:09:01 -08:00
|
|
|
#endif
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
self->Idx ++;
|
2023-11-20 12:09:01 -08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
void init()
|
|
|
|
{
|
2024-12-04 08:01:53 -08:00
|
|
|
Tokens = array_init_reserve(Token, arena_allocator_info( & LexArena)
|
2024-11-30 10:14:47 -08:00
|
|
|
, ( LexAllocator_Size - sizeof( ArrayHeader ) ) / sizeof(Token)
|
2023-11-20 12:09:01 -08:00
|
|
|
);
|
2023-11-21 18:27:33 -08:00
|
|
|
|
2024-12-01 15:50:37 -08:00
|
|
|
fixed_arena_init(& defines_map_arena);
|
2024-12-04 21:40:51 -08:00
|
|
|
defines = hashtable_init_reserve(StrC, fixed_arena_allocator_info( & defines_map_arena), 256 );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
void deinit()
|
|
|
|
{
|
|
|
|
parser::Tokens = { nullptr };
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma region Helper Macros
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
#define check_parse_args( def ) _check_parse_args(def, stringize(_func_) )
|
|
|
|
bool _check_parse_args( StrC def, char const* func_name )
|
|
|
|
{
|
|
|
|
if ( def.Len <= 0 )
|
|
|
|
{
|
|
|
|
log_failure( str_fmt_buf("gen::%s: length must greater than 0", func_name) );
|
|
|
|
pop(& Context);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ( def.Ptr == nullptr )
|
|
|
|
{
|
|
|
|
log_failure( str_fmt_buf("gen::%s: def was null", func_name) );
|
|
|
|
pop(& Context);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-04 21:40:51 -08:00
|
|
|
# define currtok_noskip (* current( & Context.Tokens, dont_skip_formatting ))
|
|
|
|
# define currtok (* current( & Context.Tokens, skip_formatting ))
|
|
|
|
# define peektok (* peek(Context.Tokens, skip_formatting))
|
2024-12-02 19:25:39 -08:00
|
|
|
# define prevtok (* previous( Context.Tokens, dont_skip_formatting))
|
|
|
|
# define nexttok (* next( Context.Tokens, skip_formatting ))
|
|
|
|
# define eat( Type_ ) __eat( & Context.Tokens, Type_ )
|
2024-12-04 08:01:53 -08:00
|
|
|
# define left ( array_num(Context.Tokens.Arr) - Context.Tokens.Idx )
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-10-27 18:18:41 -07:00
|
|
|
#ifdef check
|
|
|
|
#define CHECK_WAS_DEFINED
|
|
|
|
#pragma push_macro("check")
|
|
|
|
#undef check
|
|
|
|
#endif
|
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
# define check_noskip( Type_ ) ( left && currtok_noskip.Type == Type_ )
|
2024-12-02 19:25:39 -08:00
|
|
|
# define check( Type_ ) ( left && currtok.Type == Type_ )
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
# define push_scope() \
|
2024-12-02 22:44:01 -08:00
|
|
|
parser::StackNode scope { nullptr, currtok_noskip, parser::NullToken, txt( __func__ ) }; \
|
2024-12-03 06:31:27 -08:00
|
|
|
push( & parser::Context, & scope )
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
#pragma endregion Helper Macros
|
|
|
|
|
|
|
|
// Procedure Forwards ( Entire parser internal parser interface )
|
|
|
|
|
|
|
|
internal Code parse_array_decl ();
|
|
|
|
internal CodeAttributes parse_attributes ();
|
|
|
|
internal CodeComment parse_comment ();
|
2023-11-21 18:27:33 -08:00
|
|
|
internal Code parse_complicated_definition ( TokType which );
|
2023-11-20 12:09:01 -08:00
|
|
|
internal CodeBody parse_class_struct_body ( TokType which, Token name = NullToken );
|
|
|
|
internal Code parse_class_struct ( TokType which, bool inplace_def );
|
|
|
|
internal CodeDefine parse_define ();
|
2024-04-17 14:40:32 -07:00
|
|
|
internal Code parse_expression ();
|
|
|
|
internal Code parse_forward_or_definition ( TokType which, bool is_inplace );
|
2024-12-03 12:19:39 -08:00
|
|
|
internal CodeFn parse_function_after_name ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeTypename ret_type, Token name );
|
2023-11-20 12:09:01 -08:00
|
|
|
internal Code parse_function_body ();
|
|
|
|
internal Code parse_global_nspace ();
|
2024-04-17 14:40:32 -07:00
|
|
|
internal Code parse_global_nspace_constructor_destructor( CodeSpecifiers specifiers );
|
2023-11-20 12:09:01 -08:00
|
|
|
internal Token parse_identifier ( bool* possible_member_function = nullptr );
|
|
|
|
internal CodeInclude parse_include ();
|
2024-12-03 12:19:39 -08:00
|
|
|
internal CodeOperator parse_operator_after_ret_type ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeTypename ret_type );
|
2023-11-20 12:09:01 -08:00
|
|
|
internal Code parse_operator_function_or_variable( bool expects_function, CodeAttributes attributes, CodeSpecifiers specifiers );
|
|
|
|
internal CodePragma parse_pragma ();
|
|
|
|
internal CodeParam parse_params ( bool use_template_capture = false );
|
|
|
|
internal CodePreprocessCond parse_preprocess_cond ();
|
2024-12-05 21:33:53 -08:00
|
|
|
internal Code parse_simple_preprocess ( TokType which, bool dont_consume_braces = false );
|
2023-11-20 12:09:01 -08:00
|
|
|
internal Code parse_static_assert ();
|
|
|
|
internal void parse_template_args ( Token& token );
|
2024-12-03 12:19:39 -08:00
|
|
|
internal CodeVar parse_variable_after_name ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeTypename type, StrC name );
|
2023-11-20 12:09:01 -08:00
|
|
|
internal CodeVar parse_variable_declaration_list ();
|
|
|
|
|
|
|
|
internal CodeClass parse_class ( bool inplace_def = false );
|
2024-04-17 14:40:32 -07:00
|
|
|
internal CodeConstructor parse_constructor ( CodeSpecifiers specifiers );
|
2024-12-02 17:20:30 -08:00
|
|
|
internal CodeDestructor parse_destructor ( CodeSpecifiers specifiers = NullCode );
|
2023-11-20 12:09:01 -08:00
|
|
|
internal CodeEnum parse_enum ( bool inplace_def = false );
|
|
|
|
internal CodeBody parse_export_body ();
|
|
|
|
internal CodeBody parse_extern_link_body();
|
|
|
|
internal CodeExtern parse_extern_link ();
|
|
|
|
internal CodeFriend parse_friend ();
|
|
|
|
internal CodeFn parse_function ();
|
|
|
|
internal CodeNS parse_namespace ();
|
2024-12-02 17:20:30 -08:00
|
|
|
internal CodeOpCast parse_operator_cast ( CodeSpecifiers specifiers = NullCode );
|
2023-11-20 12:09:01 -08:00
|
|
|
internal CodeStruct parse_struct ( bool inplace_def = false );
|
|
|
|
internal CodeVar parse_variable ();
|
|
|
|
internal CodeTemplate parse_template ();
|
2024-12-03 12:19:39 -08:00
|
|
|
internal CodeTypename parse_type ( bool from_template = false, bool* is_function = nullptr );
|
2023-11-20 12:09:01 -08:00
|
|
|
internal CodeTypedef parse_typedef ();
|
|
|
|
internal CodeUnion parse_union ( bool inplace_def = false );
|
|
|
|
internal CodeUsing parse_using ();
|
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
constexpr bool inplace_def = true;
|
|
|
|
constexpr bool dont_consume_braces = true;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Internal parsing functions
|
|
|
|
|
|
|
|
constexpr bool strip_formatting_dont_preserve_newlines = false;
|
|
|
|
/*
|
|
|
|
This function was an attempt at stripping formatting from any c++ code.
|
|
|
|
It has edge case failures that prevent it from being used in function bodies.
|
|
|
|
*/
|
|
|
|
internal
|
|
|
|
String strip_formatting( StrC raw_text, bool preserve_newlines = true )
|
|
|
|
{
|
2024-12-01 00:06:30 -08:00
|
|
|
String content = string_make_reserve( GlobalAllocator, raw_text.Len );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( raw_text.Len == 0 )
|
|
|
|
return content;
|
|
|
|
|
|
|
|
#define cut_length ( scanner - raw_text.Ptr - last_cut )
|
|
|
|
#define cut_ptr ( raw_text.Ptr + last_cut )
|
|
|
|
#define pos ( sptr( scanner ) - sptr( raw_text.Ptr ) )
|
|
|
|
#define move_fwd() do { scanner++; tokleft--; } while(0)
|
|
|
|
|
|
|
|
s32 tokleft = raw_text.Len;
|
|
|
|
sptr last_cut = 0;
|
|
|
|
char const* scanner = raw_text.Ptr;
|
|
|
|
|
|
|
|
if ( scanner[0] == ' ' )
|
|
|
|
{
|
|
|
|
move_fwd();
|
|
|
|
last_cut = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool within_string = false;
|
|
|
|
bool within_char = false;
|
|
|
|
bool must_keep_newline = false;
|
|
|
|
while ( tokleft )
|
|
|
|
{
|
|
|
|
// Skip over the content of string literals
|
|
|
|
if ( scanner[0] == '"' )
|
|
|
|
{
|
|
|
|
move_fwd();
|
|
|
|
|
|
|
|
while ( tokleft && ( scanner[0] != '"' || *( scanner - 1 ) == '\\' ) )
|
|
|
|
{
|
|
|
|
if ( scanner[0] == '\\' && tokleft > 1 )
|
|
|
|
{
|
|
|
|
scanner += 2;
|
|
|
|
tokleft -= 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
move_fwd();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip the closing "
|
|
|
|
if ( tokleft )
|
|
|
|
move_fwd();
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_c_str_len( & content, cut_ptr, cut_length );
|
2023-11-20 12:09:01 -08:00
|
|
|
last_cut = sptr( scanner ) - sptr( raw_text.Ptr );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip over the content of character literals
|
|
|
|
if ( scanner[0] == '\'' )
|
|
|
|
{
|
|
|
|
move_fwd();
|
|
|
|
|
|
|
|
while ( tokleft
|
|
|
|
&& ( scanner[0] != '\''
|
|
|
|
|| ( *(scanner -1 ) == '\\' )
|
|
|
|
) )
|
|
|
|
{
|
|
|
|
move_fwd();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip the closing '
|
|
|
|
if ( tokleft )
|
|
|
|
move_fwd();
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_c_str_len( & content, cut_ptr, cut_length );
|
2023-11-20 12:09:01 -08:00
|
|
|
last_cut = sptr( scanner ) - sptr( raw_text.Ptr );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Block comments
|
|
|
|
if ( tokleft > 1 && scanner[0] == '/' && scanner[1] == '*' )
|
|
|
|
{
|
|
|
|
while ( tokleft > 1 && !(scanner[0] == '*' && scanner[1] == '/') )
|
|
|
|
move_fwd();
|
|
|
|
|
|
|
|
scanner += 2;
|
|
|
|
tokleft -= 2;
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_c_str_len( & content, cut_ptr, cut_length );
|
2023-11-20 12:09:01 -08:00
|
|
|
last_cut = sptr( scanner ) - sptr( raw_text.Ptr );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Line comments
|
|
|
|
if ( tokleft > 1 && scanner[0] == '/' && scanner[1] == '/' )
|
|
|
|
{
|
|
|
|
must_keep_newline = true;
|
|
|
|
|
|
|
|
scanner += 2;
|
|
|
|
tokleft -= 2;
|
|
|
|
|
|
|
|
while ( tokleft && scanner[ 0 ] != '\n' )
|
|
|
|
move_fwd();
|
|
|
|
|
|
|
|
if (tokleft)
|
|
|
|
move_fwd();
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_c_str_len( & content, cut_ptr, cut_length );
|
2023-11-20 12:09:01 -08:00
|
|
|
last_cut = sptr( scanner ) - sptr( raw_text.Ptr );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tabs
|
|
|
|
if (scanner[0] == '\t')
|
|
|
|
{
|
|
|
|
if (pos > last_cut)
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_c_str_len( & content, cut_ptr, cut_length);
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
if ( * string_back( content ) != ' ' )
|
2024-12-04 08:30:54 -08:00
|
|
|
string_append_char( & content, ' ' );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
move_fwd();
|
|
|
|
last_cut = sptr(scanner) - sptr(raw_text.Ptr);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( tokleft > 1 && scanner[0] == '\r' && scanner[1] == '\n' )
|
|
|
|
{
|
|
|
|
if ( must_keep_newline || preserve_newlines )
|
|
|
|
{
|
|
|
|
must_keep_newline = false;
|
|
|
|
|
|
|
|
scanner += 2;
|
|
|
|
tokleft -= 2;
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_c_str_len( & content, cut_ptr, cut_length );
|
2023-11-20 12:09:01 -08:00
|
|
|
last_cut = sptr( scanner ) - sptr( raw_text.Ptr );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pos > last_cut )
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_c_str_len( & content, cut_ptr, cut_length );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Replace with a space
|
2024-12-04 08:01:53 -08:00
|
|
|
if ( * string_back( content ) != ' ' )
|
2024-12-04 08:30:54 -08:00
|
|
|
string_append_char( & content, ' ' );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
scanner += 2;
|
|
|
|
tokleft -= 2;
|
|
|
|
|
|
|
|
last_cut = sptr( scanner ) - sptr( raw_text.Ptr );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( scanner[0] == '\n' )
|
|
|
|
{
|
|
|
|
if ( must_keep_newline || preserve_newlines )
|
|
|
|
{
|
|
|
|
must_keep_newline = false;
|
|
|
|
|
|
|
|
move_fwd();
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_c_str_len( & content, cut_ptr, cut_length );
|
2023-11-20 12:09:01 -08:00
|
|
|
last_cut = sptr( scanner ) - sptr( raw_text.Ptr );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pos > last_cut )
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_c_str_len( & content, cut_ptr, cut_length );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Replace with a space
|
2024-12-04 08:30:54 -08:00
|
|
|
if ( * string_back( content ) != ' ' )
|
|
|
|
string_append_char( & content, ' ' );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
move_fwd();
|
|
|
|
|
|
|
|
last_cut = sptr( scanner ) - sptr( raw_text.Ptr );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Escaped newlines
|
|
|
|
if ( scanner[0] == '\\' )
|
|
|
|
{
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_c_str_len( & content, cut_ptr, cut_length );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
s32 amount_to_skip = 1;
|
|
|
|
if ( tokleft > 1 && scanner[1] == '\n' )
|
|
|
|
{
|
|
|
|
amount_to_skip = 2;
|
|
|
|
}
|
|
|
|
else if ( tokleft > 2 && scanner[1] == '\r' && scanner[2] == '\n' )
|
|
|
|
{
|
|
|
|
amount_to_skip = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( amount_to_skip > 1 && pos == last_cut )
|
|
|
|
{
|
|
|
|
scanner += amount_to_skip;
|
|
|
|
tokleft -= amount_to_skip;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
move_fwd();
|
|
|
|
|
|
|
|
last_cut = sptr( scanner ) - sptr( raw_text.Ptr );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Consectuive spaces
|
|
|
|
if ( tokleft > 1 && char_is_space( scanner[0] ) && char_is_space( scanner[ 1 ] ) )
|
|
|
|
{
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_c_str_len( & content, cut_ptr, cut_length );
|
2023-11-20 12:09:01 -08:00
|
|
|
do
|
|
|
|
{
|
|
|
|
move_fwd();
|
|
|
|
}
|
|
|
|
while ( tokleft && char_is_space( scanner[0] ) );
|
|
|
|
|
|
|
|
last_cut = sptr( scanner ) - sptr( raw_text.Ptr );
|
|
|
|
|
|
|
|
// Preserve only 1 space of formattting
|
2024-12-04 08:30:54 -08:00
|
|
|
char* last = string_back(content);
|
2024-12-01 20:35:58 -08:00
|
|
|
if ( last == nullptr || * last != ' ' )
|
2024-12-04 08:30:54 -08:00
|
|
|
string_append_char( & content, ' ' );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
move_fwd();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( last_cut < raw_text.Len )
|
|
|
|
{
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_c_str_len( & content, cut_ptr, raw_text.Len - last_cut );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#undef cut_ptr
|
|
|
|
#undef cut_length
|
|
|
|
#undef pos
|
|
|
|
#undef move_fwd
|
|
|
|
|
|
|
|
return content;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
Code parse_array_decl()
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Operator ) && currtok.Text[0] == '[' && currtok.Text[1] == ']' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 19:25:39 -08:00
|
|
|
Code array_expr = untyped_str( to_str(currtok) );
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Operator );
|
2023-11-21 18:27:33 -08:00
|
|
|
// []
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return array_expr;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_BraceSquare_Open ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceSquare_Open );
|
2023-11-21 18:27:33 -08:00
|
|
|
// [
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( left == 0 )
|
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, unexpected end of array declaration ( '[]' scope started )\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_BraceSquare_Close )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, empty array expression in definition\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
Token untyped_tok = currtok;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && currtok.Type != Tok_BraceSquare_Close )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
|
|
|
untyped_tok.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)untyped_tok.Text;
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
Code array_expr = untyped_str( to_str(untyped_tok) );
|
2023-11-21 18:27:33 -08:00
|
|
|
// [ <Content>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( left == 0 )
|
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, unexpected end of array declaration, expected ]\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type != Tok_BraceSquare_Close )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
log_failure( "%s: Error, expected ] in array declaration, not %s\n%s", to_str( currtok.Type ), to_string(Context) );
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceSquare_Close );
|
2023-11-21 18:27:33 -08:00
|
|
|
// [ <Content> ]
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Its a multi-dimensional array
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_BraceSquare_Open ))
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
Code adjacent_arr_expr = parse_array_decl();
|
2023-11-21 18:27:33 -08:00
|
|
|
// [ <Content> ][ <Content> ]...
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 17:20:30 -08:00
|
|
|
array_expr->Next.ast = adjacent_arr_expr.ast;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return array_expr;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return { nullptr };
|
|
|
|
}
|
|
|
|
|
|
|
|
internal inline
|
|
|
|
CodeAttributes parse_attributes()
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
Token start = currtok;
|
|
|
|
s32 len = 0;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// 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
|
2024-12-02 19:25:39 -08:00
|
|
|
while ( left && is_attribute(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Attribute_Open ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Attribute_Open );
|
2024-04-17 14:40:32 -07:00
|
|
|
// [[
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && currtok.Type != Tok_Attribute_Close )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
// [[ <Content>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Attribute_Close );
|
2024-04-17 14:40:32 -07:00
|
|
|
// [[ <Content> ]]
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( check( Tok_Decl_GNU_Attribute ) )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Decl_GNU_Attribute );
|
|
|
|
eat( Tok_Capture_Start );
|
|
|
|
eat( Tok_Capture_Start );
|
2024-04-17 14:40:32 -07:00
|
|
|
// __attribute__((
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && currtok.Type != Tok_Capture_End )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
// __attribute__(( <Content>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_End );
|
|
|
|
eat( Tok_Capture_End );
|
2024-04-17 14:40:32 -07:00
|
|
|
// __attribute__(( <Content> ))
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text;
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( check( Tok_Decl_MSVC_Attribute ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Decl_MSVC_Attribute );
|
|
|
|
eat( Tok_Capture_Start );
|
2024-04-17 14:40:32 -07:00
|
|
|
// __declspec(
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && currtok.Type != Tok_Capture_End )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
// __declspec( <Content>
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_End );
|
2024-04-17 14:40:32 -07:00
|
|
|
// __declspec( <Content> )
|
|
|
|
|
|
|
|
len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-02 19:25:39 -08:00
|
|
|
else if ( is_attribute(currtok) )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
eat( currtok.Type );
|
|
|
|
// <Attribute>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// If its a macro based attribute, this could be a functional macro such as Unreal's UE_DEPRECATED(...)
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Capture_Start))
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_Start );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
s32 level = 0;
|
2024-12-03 06:50:30 -08:00
|
|
|
while (left && currtok.Type != Tok_Capture_End && level == 0)
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if (currtok.Type == Tok_Capture_Start)
|
2024-04-17 14:40:32 -07:00
|
|
|
++ level;
|
2024-12-03 06:50:30 -08:00
|
|
|
if (currtok.Type == Tok_Capture_End)
|
2024-04-17 14:40:32 -07:00
|
|
|
--level;
|
|
|
|
eat(currtok.Type);
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
eat(Tok_Capture_End);
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text;
|
|
|
|
// <Attribute> ( ... )
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( len > 0 )
|
|
|
|
{
|
|
|
|
StrC attribute_txt = { len, start.Text };
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
String name_stripped = strip_formatting( attribute_txt, strip_formatting_dont_preserve_newlines );
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
Code result = make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_PlatformAttributes;
|
2024-12-04 08:01:53 -08:00
|
|
|
result->Name = get_cached_string( { string_length(name_stripped), name_stripped } );
|
2023-11-20 12:09:01 -08:00
|
|
|
result->Content = result->Name;
|
2024-04-17 14:40:32 -07:00
|
|
|
// result->Token =
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
return ( CodeAttributes )result;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return { nullptr };
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
2023-11-21 18:27:33 -08:00
|
|
|
Code parse_class_struct( TokType which, bool inplace_def = false )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( which != Tok_Decl_Class && which != Tok_Decl_Struct )
|
2023-11-21 18:27:33 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
log_failure( "Error, expected class or struct, not %s\n%s", to_str( which ), to_string(Context) );
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-21 18:27:33 -08:00
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
Token name { nullptr, 0, Tok_Invalid };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-01 02:30:37 -08:00
|
|
|
AccessSpec access = AccessSpec_Default;
|
2024-12-03 12:19:39 -08:00
|
|
|
CodeTypename parent = { nullptr };
|
2023-11-21 18:27:33 -08:00
|
|
|
CodeBody body = { nullptr };
|
|
|
|
CodeAttributes attributes = { nullptr };
|
2024-12-01 02:30:37 -08:00
|
|
|
ModuleFlag mflags = ModuleFlag_None;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-01 21:03:38 -08:00
|
|
|
CodeClass result = InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check(Tok_Module_Export) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-01 02:30:37 -08:00
|
|
|
mflags = ModuleFlag_Export;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Module_Export );
|
2023-11-21 18:27:33 -08:00
|
|
|
}
|
2023-11-21 20:36:56 -08:00
|
|
|
// <ModuleFlags>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
eat( which );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <ModuleFlags> <class/struct>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
attributes = parse_attributes();
|
2023-11-21 20:36:56 -08:00
|
|
|
// <ModuleFlags> <class/struct> <Attributes>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Identifier ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2023-11-21 18:27:33 -08:00
|
|
|
name = parse_identifier();
|
|
|
|
Context.Scope->Name = name;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-21 20:36:56 -08:00
|
|
|
// <ModuleFlags> <class/struct> <Attributes> <Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
local_persist
|
2024-12-04 21:40:51 -08:00
|
|
|
char interface_arr_mem[ kilobytes(4) ] {0};
|
2024-12-03 12:19:39 -08:00
|
|
|
Array<CodeTypename> interfaces; {
|
2024-11-30 14:18:49 -08:00
|
|
|
Arena arena = arena_init_from_memory( interface_arr_mem, kilobytes(4) );
|
2024-12-04 08:01:53 -08:00
|
|
|
interfaces = array_init_reserve(CodeTypename, arena_allocator_info(& arena), 4 );
|
2024-11-30 20:38:27 -08:00
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-21 20:36:56 -08:00
|
|
|
// TODO(Ed) : Make an AST_DerivedType, we'll store any arbitary derived type into there as a linear linked list of them.
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Assign_Classifer ) )
|
2023-11-21 18:27:33 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Assign_Classifer );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <ModuleFlags> <class/struct> <Attributes> <Name> :
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
if ( is_access_specifier(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 19:25:39 -08:00
|
|
|
access = to_access_specifier(currtok);
|
2023-11-21 20:36:56 -08:00
|
|
|
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier>
|
2024-04-17 14:40:32 -07:00
|
|
|
eat( currtok.Type );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
Token parent_tok = parse_identifier();
|
2024-12-02 19:25:39 -08:00
|
|
|
parent = def_type( to_str(parent_tok) );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Parent/Interface Name>
|
2023-11-21 18:27:33 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( check(Tok_Comma) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Comma );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Name>,
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
if ( is_access_specifier(currtok) )
|
2023-11-21 18:27:33 -08:00
|
|
|
{
|
|
|
|
eat(currtok.Type);
|
|
|
|
}
|
|
|
|
Token interface_tok = parse_identifier();
|
|
|
|
|
2024-12-05 14:04:17 -08:00
|
|
|
array_append( interfaces, def_type( to_str(interface_tok) ) );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Name>, ...
|
2023-11-21 18:27:33 -08:00
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-21 18:27:33 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_BraceCurly_Open ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2023-11-21 18:27:33 -08:00
|
|
|
body = parse_class_struct_body( which, name );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-21 20:36:56 -08:00
|
|
|
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Name>, ... { <Body> }
|
2023-11-21 18:27:33 -08:00
|
|
|
|
2024-12-02 17:20:30 -08:00
|
|
|
CodeComment inline_cmt = NullCode;
|
2023-11-21 18:27:33 -08:00
|
|
|
if ( ! inplace_def )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2023-11-21 18:27:33 -08:00
|
|
|
Token stmt_end = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Name>, ... { <Body> };
|
2023-11-21 18:27:33 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
|
2023-11-21 18:27:33 -08:00
|
|
|
inline_cmt = parse_comment();
|
2024-12-02 21:45:30 -08:00
|
|
|
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Name>, ... { <Body> }; <InlineCmt>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-21 18:27:33 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( which == Tok_Decl_Class )
|
2024-12-02 21:45:30 -08:00
|
|
|
result = def_class( to_str(name), { body, parent, access, attributes, mflags } );
|
2023-11-21 18:27:33 -08:00
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
else
|
2024-12-03 12:19:39 -08:00
|
|
|
result = def_struct( to_str(name), { body, (CodeTypename)parent, access, attributes, mflags } );
|
2023-11-21 18:27:33 -08:00
|
|
|
|
|
|
|
if ( inline_cmt )
|
|
|
|
result->InlineCmt = inline_cmt;
|
|
|
|
|
2024-12-04 21:40:51 -08:00
|
|
|
array_free(interfaces);
|
2023-11-21 18:27:33 -08:00
|
|
|
return result;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
internal neverinline
|
|
|
|
CodeBody parse_class_struct_body( TokType which, Token name )
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceCurly_Open );
|
2023-11-21 20:36:56 -08:00
|
|
|
// {
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeBody
|
|
|
|
result = (CodeBody) make_code();
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( which == Tok_Decl_Class )
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Class_Body;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Struct_Body;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && currtok_noskip.Type != Tok_BraceCurly_Close )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-01 21:03:38 -08:00
|
|
|
Code member = Code_Invalid;
|
2023-11-20 12:09:01 -08:00
|
|
|
CodeAttributes attributes = { nullptr };
|
|
|
|
CodeSpecifiers specifiers = { nullptr };
|
|
|
|
|
|
|
|
bool expects_function = false;
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// Context.Scope->Start = currtok_noskip;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Preprocess_Hash )
|
|
|
|
eat( Tok_Preprocess_Hash );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
switch ( currtok_noskip.Type )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Statement_End:
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
// TODO(Ed): Convert this to a general warning procedure
|
2024-12-02 19:25:39 -08:00
|
|
|
log_fmt("Dangling end statement found %S\n", to_string(currtok_noskip));
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2024-04-17 14:40:32 -07:00
|
|
|
continue;
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_NewLine:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = fmt_newline;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_NewLine );
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Comment:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_comment();
|
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Access_Public:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = access_public;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Access_Public );
|
|
|
|
eat( Tok_Assign_Classifer );
|
2023-11-21 20:36:56 -08:00
|
|
|
// public:
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Access_Protected:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = access_protected;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Access_Protected );
|
|
|
|
eat( Tok_Assign_Classifer );
|
2023-11-21 20:36:56 -08:00
|
|
|
// protected:
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Access_Private:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = access_private;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Access_Private );
|
|
|
|
eat( Tok_Assign_Classifer );
|
2023-11-21 20:36:56 -08:00
|
|
|
// private:
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Class:
|
|
|
|
member = parse_complicated_definition( Tok_Decl_Class );
|
2023-11-21 20:36:56 -08:00
|
|
|
// class
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Enum:
|
|
|
|
member = parse_complicated_definition( Tok_Decl_Enum );
|
2023-11-21 20:36:56 -08:00
|
|
|
// enum
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Friend:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_friend();
|
2023-11-21 20:36:56 -08:00
|
|
|
// friend
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Operator:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_operator_cast();
|
2023-11-21 20:36:56 -08:00
|
|
|
// operator <Type>()
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Struct:
|
|
|
|
member = parse_complicated_definition( Tok_Decl_Struct );
|
2023-11-21 20:36:56 -08:00
|
|
|
// struct
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Template:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_template();
|
2023-11-21 20:36:56 -08:00
|
|
|
// template< ... >
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Typedef:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_typedef();
|
2023-11-21 20:36:56 -08:00
|
|
|
// typedef
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Union:
|
|
|
|
member = parse_complicated_definition( Tok_Decl_Union );
|
2023-11-21 20:36:56 -08:00
|
|
|
// union
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Using:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_using();
|
2023-11-21 20:36:56 -08:00
|
|
|
// using
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Operator:
|
2024-12-03 17:21:08 -08:00
|
|
|
//if ( currtok.Text[0] != '~' )
|
|
|
|
//{
|
|
|
|
// log_failure( "Operator token found in global body but not destructor unary negation\n%s", to_string(Context) );
|
|
|
|
// return InvalidCode;
|
|
|
|
//}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
member = parse_destructor();
|
2023-11-21 20:36:56 -08:00
|
|
|
// ~<Name>()
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Define:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_define();
|
2023-11-21 20:36:56 -08:00
|
|
|
// #define
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Include:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_include();
|
2023-11-21 20:36:56 -08:00
|
|
|
// #include
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_If:
|
|
|
|
case Tok_Preprocess_IfDef:
|
|
|
|
case Tok_Preprocess_IfNotDef:
|
|
|
|
case Tok_Preprocess_ElIf:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_preprocess_cond();
|
2023-11-21 20:36:56 -08:00
|
|
|
// #<Condition>
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Else:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = preprocess_else;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_Else );
|
2023-11-21 20:36:56 -08:00
|
|
|
// #else
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_EndIf:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = preprocess_endif;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_EndIf );
|
2023-11-21 20:36:56 -08:00
|
|
|
// #endif
|
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Macro:
|
|
|
|
member = parse_simple_preprocess( Tok_Preprocess_Macro );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Macro>
|
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Pragma:
|
2023-11-21 20:36:56 -08:00
|
|
|
member = parse_pragma();
|
|
|
|
// #pragma
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Unsupported:
|
|
|
|
member = parse_simple_preprocess( Tok_Preprocess_Unsupported );
|
2023-11-21 20:36:56 -08:00
|
|
|
// #<UNKNOWN>
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_StaticAssert:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_static_assert();
|
2023-11-21 20:36:56 -08:00
|
|
|
// static_assert
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Attribute_Open:
|
|
|
|
case Tok_Decl_GNU_Attribute:
|
|
|
|
case Tok_Decl_MSVC_Attribute:
|
|
|
|
#define Entry( attribute, str ) case attribute:
|
2023-11-20 12:09:01 -08:00
|
|
|
GEN_DEFINE_ATTRIBUTE_TOKENS
|
|
|
|
#undef Entry
|
|
|
|
{
|
|
|
|
attributes = parse_attributes();
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
//! Fallthrough intended
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Spec_Consteval:
|
|
|
|
case Tok_Spec_Constexpr:
|
|
|
|
case Tok_Spec_Constinit:
|
|
|
|
case Tok_Spec_Explicit:
|
|
|
|
case Tok_Spec_ForceInline:
|
|
|
|
case Tok_Spec_Inline:
|
|
|
|
case Tok_Spec_Mutable:
|
|
|
|
case Tok_Spec_NeverInline:
|
|
|
|
case Tok_Spec_Static:
|
|
|
|
case Tok_Spec_Volatile:
|
|
|
|
case Tok_Spec_Virtual:
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 10:14:14 -08:00
|
|
|
Specifier specs_found[16] { Spec_NumSpecifiers };
|
2023-11-20 12:09:01 -08:00
|
|
|
s32 NumSpecifiers = 0;
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
while ( left && is_specifier(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
Specifier spec = strc_to_specifier( to_str(currtok) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
b32 ignore_spec = false;
|
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
switch ( spec )
|
|
|
|
{
|
2024-12-03 10:14:14 -08:00
|
|
|
case Spec_Constexpr:
|
|
|
|
case Spec_Constinit:
|
|
|
|
case Spec_Explicit:
|
|
|
|
case Spec_Inline:
|
|
|
|
case Spec_ForceInline:
|
|
|
|
case Spec_Mutable:
|
|
|
|
case Spec_NeverInline:
|
|
|
|
case Spec_Static:
|
|
|
|
case Spec_Volatile:
|
|
|
|
case Spec_Virtual:
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
case Spec_Consteval:
|
2023-11-20 12:09:01 -08:00
|
|
|
expects_function = true;
|
|
|
|
break;
|
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
case Spec_Const :
|
2024-04-17 14:40:32 -07:00
|
|
|
ignore_spec = true;
|
|
|
|
break;
|
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
default:
|
2024-12-06 02:29:17 -08:00
|
|
|
log_failure( "Invalid specifier %s for variable\n%s", spec_to_str(spec), to_string(Context) );
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// Every specifier after would be considered part of the type type signature
|
|
|
|
if (ignore_spec)
|
|
|
|
break;
|
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
specs_found[NumSpecifiers] = spec;
|
|
|
|
NumSpecifiers++;
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( NumSpecifiers )
|
|
|
|
{
|
|
|
|
specifiers = def_specifiers( NumSpecifiers, specs_found );
|
|
|
|
}
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes> <Specifiers>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
if ( is_attribute(currtok) )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
// Unfortuantely Unreal has code where there is attirbutes before specifiers
|
|
|
|
CodeAttributes more_attributes = parse_attributes();
|
|
|
|
|
|
|
|
if ( attributes )
|
|
|
|
{
|
2024-12-03 15:47:12 -08:00
|
|
|
String fused = string_make_reserve( GlobalAllocator, attributes->Content.Len + more_attributes->Content.Len );
|
2024-12-04 08:01:53 -08:00
|
|
|
string_append_fmt( & fused, "%S %S", attributes->Content, more_attributes->Content );
|
2024-04-17 14:40:32 -07:00
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
attributes->Name = get_cached_string( { string_length(fused), fused });
|
2024-04-17 14:40:32 -07:00
|
|
|
attributes->Content = attributes->Name;
|
|
|
|
// <Attributes> <Specifiers> <Attributes>
|
|
|
|
}
|
|
|
|
|
|
|
|
attributes = more_attributes;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Operator && currtok.Text[0] == '~' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
member = parse_destructor( specifiers );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attribute> <Specifiers> ~<Name>()
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Decl_Operator )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
member = parse_operator_cast( specifiers );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes> <Specifiers> operator <Type>()
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//! Fallthrough intentional
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Identifier:
|
|
|
|
case Tok_Spec_Const:
|
|
|
|
case Tok_Type_Unsigned:
|
|
|
|
case Tok_Type_Signed:
|
|
|
|
case Tok_Type_Short:
|
|
|
|
case Tok_Type_Long:
|
|
|
|
case Tok_Type_bool:
|
|
|
|
case Tok_Type_char:
|
|
|
|
case Tok_Type_int:
|
|
|
|
case Tok_Type_double:
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( nexttok.Type == Tok_Capture_Start && name.Length && currtok.Type == Tok_Identifier )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-04 08:01:53 -08:00
|
|
|
if ( str_compare_len( name.Text, currtok.Text, name.Length ) == 0 )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-04-17 14:40:32 -07:00
|
|
|
member = parse_constructor( specifiers );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes> <Specifiers> <Name>()
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
member = parse_operator_function_or_variable( expects_function, attributes, specifiers );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes> <Specifiers> operator <Op> ...
|
|
|
|
// or
|
|
|
|
// <Attributes> <Specifiers> <Name> ...
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Token untyped_tok = currtok;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && currtok.Type != Tok_BraceCurly_Close )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
untyped_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)untyped_tok.Text;
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
member = untyped_str( to_str(untyped_tok) );
|
2023-11-21 20:36:56 -08:00
|
|
|
// Something unknown
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( member == Code_Invalid )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Failed to parse member\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
body_append(result, member );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceCurly_Close );
|
2023-11-21 20:36:56 -08:00
|
|
|
// { <Members> }
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
2023-11-21 18:27:33 -08:00
|
|
|
CodeComment parse_comment()
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
push_scope();
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
CodeComment
|
|
|
|
result = (CodeComment) make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Comment;
|
2024-12-02 19:25:39 -08:00
|
|
|
result->Content = get_cached_string( to_str(currtok_noskip) );
|
2023-11-21 18:27:33 -08:00
|
|
|
result->Name = result->Content;
|
|
|
|
// result->Token = currtok_noskip;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Comment );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-21 18:27:33 -08:00
|
|
|
return result;
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
internal
|
|
|
|
Code parse_complicated_definition( TokType which )
|
|
|
|
{
|
|
|
|
push_scope();
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
bool is_inplace = false;
|
|
|
|
|
|
|
|
TokArray tokens = Context.Tokens;
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
s32 idx = tokens.Idx;
|
|
|
|
s32 level = 0;
|
2024-12-04 08:01:53 -08:00
|
|
|
for ( ; idx < array_num(tokens.Arr); idx++ )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tokens.Arr[ idx ].Type == Tok_BraceCurly_Open )
|
2023-11-21 18:27:33 -08:00
|
|
|
level++;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tokens.Arr[ idx ].Type == Tok_BraceCurly_Close )
|
2023-11-21 18:27:33 -08:00
|
|
|
level--;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( level == 0 && tokens.Arr[ idx ].Type == Tok_Statement_End )
|
2023-11-21 18:27:33 -08:00
|
|
|
break;
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
if ( ( idx - 2 ) == tokens.Idx )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2023-11-21 18:27:33 -08:00
|
|
|
// Its a forward declaration only
|
|
|
|
Code result = parse_forward_or_definition( which, is_inplace );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <class, enum, struct, or union> <Name>;
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-21 18:27:33 -08:00
|
|
|
return result;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
Token tok = tokens.Arr[ idx - 1 ];
|
2024-12-06 02:29:17 -08:00
|
|
|
if ( is_specifier(tok) && spec_is_trailing( strc_to_specifier( to_str(tok))) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-04-17 14:40:32 -07:00
|
|
|
// <which> <type_identifier>(...) <specifier> ...;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
s32 spec_idx = idx - 1;
|
2024-12-02 19:25:39 -08:00
|
|
|
Token spec = tokens.Arr[spec_idx];
|
2024-12-06 02:29:17 -08:00
|
|
|
while ( is_specifier(spec) && spec_is_trailing( strc_to_specifier( to_str(spec))) )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
-- spec_idx;
|
2024-12-02 19:25:39 -08:00
|
|
|
spec = tokens.Arr[spec_idx];
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tokens.Arr[spec_idx].Type == Tok_Capture_End )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
// Forward declaration with trailing specifiers for a procedure
|
2024-12-02 19:25:39 -08:00
|
|
|
tok = tokens.Arr[spec_idx];
|
2024-04-17 14:40:32 -07:00
|
|
|
|
|
|
|
Code result = parse_operator_function_or_variable( false, { nullptr }, { nullptr } );
|
|
|
|
// <Attributes> <Specifiers> <ReturnType/ValueType> <operator <Op>, or Name> ...
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-04-17 14:40:32 -07:00
|
|
|
return result;
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Unsupported or bad member definition after %s declaration\n%s", to_str(which), to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok.Type == Tok_Identifier )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-02 19:25:39 -08:00
|
|
|
tok = tokens.Arr[ idx - 2 ];
|
2024-12-03 06:50:30 -08:00
|
|
|
bool is_indirection = tok.Type == Tok_Ampersand || tok.Type == Tok_Star;
|
2024-04-17 14:40:32 -07:00
|
|
|
bool ok_to_parse = false;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok.Type == Tok_BraceCurly_Close )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2023-11-21 18:27:33 -08:00
|
|
|
// Its an inplace definition
|
|
|
|
// <which> <type_identifier> { ... } <identifier>;
|
|
|
|
ok_to_parse = true;
|
|
|
|
is_inplace = true;
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( tok.Type == Tok_Identifier && tokens.Arr[ idx - 3 ].Type == which )
|
2023-11-21 18:27:33 -08:00
|
|
|
{
|
2023-11-21 20:36:56 -08:00
|
|
|
// Its a variable with type ID using <which> namespace.
|
2023-11-21 18:27:33 -08:00
|
|
|
// <which> <type_identifier> <identifier>;
|
|
|
|
ok_to_parse = true;
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( tok.Type == Tok_Assign_Classifer
|
|
|
|
&& ( ( tokens.Arr[idx - 5].Type == which && tokens.Arr[idx - 4].Type == Tok_Decl_Class )
|
2024-12-02 19:25:39 -08:00
|
|
|
|| ( tokens.Arr[idx - 4].Type == which))
|
2024-04-17 14:40:32 -07:00
|
|
|
)
|
|
|
|
{
|
|
|
|
// Its a forward declaration of an enum
|
|
|
|
// <enum> <type_identifier> : <identifier>;
|
|
|
|
// <enum> <class> <type_identifier> : <identifier>;
|
|
|
|
ok_to_parse = true;
|
|
|
|
Code result = parse_enum();
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-04-17 14:40:32 -07:00
|
|
|
return result;
|
|
|
|
}
|
2023-11-21 18:27:33 -08:00
|
|
|
else if ( is_indirection )
|
|
|
|
{
|
|
|
|
// Its a indirection type with type ID using struct namespace.
|
|
|
|
// <which> <type_identifier>* <identifier>;
|
|
|
|
ok_to_parse = true;
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
if ( ! ok_to_parse )
|
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Unsupported or bad member definition after %s declaration\n%s", to_str(which), to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
Code result = parse_operator_function_or_variable( false, { nullptr }, { nullptr } );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes> <Specifiers> <ReturnType/ValueType> <operator <Op>, or Name> ...
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-21 18:27:33 -08:00
|
|
|
return result;
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( tok.Type >= Tok_Type_Unsigned && tok.Type <= Tok_Type_MS_W64 )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-02 19:25:39 -08:00
|
|
|
tok = tokens.Arr[ idx - 2 ];
|
2024-04-17 14:40:32 -07:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok.Type != Tok_Assign_Classifer
|
|
|
|
|| ( ( tokens.Arr[idx - 5].Type != which && tokens.Arr[idx - 4].Type != Tok_Decl_Class )
|
2024-12-02 19:25:39 -08:00
|
|
|
&& ( tokens.Arr[idx - 4].Type != which))
|
2024-04-17 14:40:32 -07:00
|
|
|
)
|
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Unsupported or bad member definition after %s declaration\n%s", to_str(which), to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Its a forward declaration of an enum class
|
|
|
|
// <enum> <type_identifier> : <identifier>;
|
|
|
|
// <enum> <class> <type_identifier> : <identifier>;
|
|
|
|
Code result = parse_enum();
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-04-17 14:40:32 -07:00
|
|
|
return result;
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( tok.Type == Tok_BraceCurly_Close )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2023-11-21 18:27:33 -08:00
|
|
|
// Its a definition
|
|
|
|
Code result = parse_forward_or_definition( which, is_inplace );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <which> { ... };
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-21 18:27:33 -08:00
|
|
|
return result;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( tok.Type == Tok_BraceSquare_Close )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2023-11-21 18:27:33 -08:00
|
|
|
// Its an array definition
|
|
|
|
Code result = parse_operator_function_or_variable( false, { nullptr }, { nullptr } );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <which> <type_identifier> <identifier> [ ... ];
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-21 18:27:33 -08:00
|
|
|
return result;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
else
|
2023-11-21 18:27:33 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Unsupported or bad member definition after %s declaration\n%S", to_str(which).Ptr, to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-21 18:27:33 -08:00
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
internal inline
|
|
|
|
CodeDefine parse_define()
|
|
|
|
{
|
|
|
|
push_scope();
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_Define );
|
2023-11-21 20:36:56 -08:00
|
|
|
// #define
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeDefine
|
|
|
|
define = (CodeDefine) make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
define->Type = CT_Preprocess_Define;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ! check( Tok_Identifier ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, expected identifier after #define\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
Context.Scope->Name = currtok;
|
2024-12-02 19:25:39 -08:00
|
|
|
define->Name = get_cached_string( to_str(currtok) );
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Identifier );
|
2023-11-21 20:36:56 -08:00
|
|
|
// #define <Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ! check( Tok_Preprocess_Content ))
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, expected content after #define %s\n%s", define->Name, to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-10-24 22:04:17 -07:00
|
|
|
if ( currtok.Length == 0 )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 19:25:39 -08:00
|
|
|
define->Content = get_cached_string( to_str(currtok) );
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_Content );
|
2023-11-21 20:36:56 -08:00
|
|
|
// #define <Name> <Content>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return define;
|
|
|
|
}
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
define->Content = get_cached_string( string_to_strc( strip_formatting( to_str(currtok), strip_formatting_dont_preserve_newlines )) );
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_Content );
|
2023-11-21 20:36:56 -08:00
|
|
|
// #define <Name> <Content>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return define;
|
|
|
|
}
|
|
|
|
|
2024-10-24 22:04:17 -07:00
|
|
|
internal inline
|
|
|
|
Code parse_assignment_expression()
|
|
|
|
{
|
|
|
|
Code expr = { nullptr };
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Operator );
|
2024-10-24 22:04:17 -07:00
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> =
|
|
|
|
|
|
|
|
Token expr_tok = currtok;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Statement_End && currtok.Type != Tok_Comma )
|
2024-10-24 22:04:17 -07:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Expected expression after assignment operator\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2024-10-24 22:04:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
s32 level = 0;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && currtok.Type != Tok_Statement_End && (currtok.Type != Tok_Comma || level > 0) )
|
2024-10-24 22:04:17 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if (currtok.Type == Tok_BraceCurly_Open )
|
2024-10-24 22:04:17 -07:00
|
|
|
level++;
|
2024-12-03 06:50:30 -08:00
|
|
|
if (currtok.Type == Tok_BraceCurly_Close )
|
2024-10-24 22:04:17 -07:00
|
|
|
level--;
|
2024-12-03 06:50:30 -08:00
|
|
|
if (currtok.Type == Tok_Capture_Start)
|
2024-10-24 22:04:17 -07:00
|
|
|
level++;
|
2024-12-03 06:50:30 -08:00
|
|
|
else if (currtok.Type == Tok_Capture_End)
|
2024-10-24 22:04:17 -07:00
|
|
|
level--;
|
|
|
|
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
|
|
|
expr_tok.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )expr_tok.Text - 1;
|
2024-12-02 19:25:39 -08:00
|
|
|
expr = untyped_str( to_str(expr_tok) );
|
2024-10-24 22:04:17 -07:00
|
|
|
// = <Expression>
|
|
|
|
return expr;
|
|
|
|
}
|
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
internal inline
|
|
|
|
Code parse_forward_or_definition( TokType which, bool is_inplace )
|
|
|
|
{
|
2024-12-01 21:03:38 -08:00
|
|
|
Code result = InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
switch ( which )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Class:
|
2023-11-20 12:09:01 -08:00
|
|
|
result = parse_class( is_inplace );
|
|
|
|
return result;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Enum:
|
2023-11-20 12:09:01 -08:00
|
|
|
result = parse_enum( is_inplace );
|
|
|
|
return result;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Struct:
|
2023-11-20 12:09:01 -08:00
|
|
|
result = parse_struct( is_inplace );
|
|
|
|
return result;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Union:
|
2023-11-20 12:09:01 -08:00
|
|
|
result = parse_union( is_inplace );
|
|
|
|
return result;
|
|
|
|
|
|
|
|
default:
|
|
|
|
log_failure( "Error, wrong token type given to parse_complicated_definition "
|
|
|
|
"(only supports class, enum, struct, union) \n%s"
|
2024-12-03 06:31:27 -08:00
|
|
|
, to_string(Context) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function parsing is handled in multiple places because its initial signature is shared with variable parsing
|
|
|
|
internal inline
|
|
|
|
CodeFn parse_function_after_name(
|
|
|
|
ModuleFlag mflags
|
|
|
|
, CodeAttributes attributes
|
|
|
|
, CodeSpecifiers specifiers
|
2024-12-03 12:19:39 -08:00
|
|
|
, CodeTypename ret_type
|
2023-11-20 12:09:01 -08:00
|
|
|
, Token name
|
|
|
|
)
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
CodeParam params = parse_params();
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Parameters> )
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
// TODO(Ed), Review old comment : These have to be kept separate from the return type's specifiers.
|
2024-12-02 19:25:39 -08:00
|
|
|
while ( left && is_specifier(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
if ( specifiers.ast == nullptr )
|
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
specifiers = def_specifier( strc_to_specifier( to_str(currtok)) );
|
2023-11-20 12:09:01 -08:00
|
|
|
eat( currtok.Type );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
specifiers_append(specifiers, strc_to_specifier( to_str(currtok)) );
|
2023-11-20 12:09:01 -08:00
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 17:20:30 -08:00
|
|
|
CodeBody body = NullCode;
|
|
|
|
CodeComment inline_cmt = NullCode;
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_BraceCurly_Open ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
body = parse_function_body();
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( body == Code_Invalid )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers> { <Body> }
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( check(Tok_Operator) && currtok.Text[0] == '=' )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat(Tok_Operator);
|
2024-12-06 21:21:09 -08:00
|
|
|
specifiers_append(specifiers, Spec_Pure );
|
2024-04-17 14:40:32 -07:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Number);
|
2024-04-17 14:40:32 -07:00
|
|
|
Token stmt_end = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2024-04-17 14:40:32 -07:00
|
|
|
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers> = 0;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
|
2024-04-17 14:40:32 -07:00
|
|
|
inline_cmt = parse_comment();
|
|
|
|
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers>; <InlineCmt>
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
Token stmt_end = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers>;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
|
2023-11-20 12:09:01 -08:00
|
|
|
inline_cmt = parse_comment();
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes> <Specifiers> <ReturnType> <Name> ( <Paraemters> ) <Specifiers>; <InlineCmt>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
String
|
2024-12-04 08:01:53 -08:00
|
|
|
name_stripped = string_make_strc( GlobalAllocator, to_str(name) );
|
2024-12-01 00:06:30 -08:00
|
|
|
strip_space(name_stripped);
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeFn
|
|
|
|
result = (CodeFn) make_code();
|
2024-12-04 08:01:53 -08:00
|
|
|
result->Name = get_cached_string( string_to_strc(name_stripped) );
|
2023-11-20 12:09:01 -08:00
|
|
|
result->ModuleFlags = mflags;
|
|
|
|
|
|
|
|
if ( body )
|
|
|
|
{
|
|
|
|
switch ( body->Type )
|
|
|
|
{
|
2024-12-03 12:19:39 -08:00
|
|
|
case CT_Function_Body:
|
|
|
|
case CT_Untyped:
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
log_failure("Body must be either of Function_Body or Untyped type, %s\n%s", code_debug_str(body), to_string(Context));
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Function;
|
2023-11-20 12:09:01 -08:00
|
|
|
result->Body = body;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Function_Fwd;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
if ( attributes )
|
|
|
|
result->Attributes = attributes;
|
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
if ( specifiers )
|
|
|
|
result->Specs = specifiers;
|
|
|
|
|
|
|
|
result->ReturnType = ret_type;
|
|
|
|
|
|
|
|
if ( params )
|
|
|
|
result->Params = params;
|
|
|
|
|
|
|
|
if ( inline_cmt )
|
|
|
|
result->InlineCmt = inline_cmt;
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
Code parse_function_body()
|
|
|
|
{
|
2024-12-06 21:21:09 -08:00
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
push_scope();
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceCurly_Open );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeBody
|
|
|
|
result = (CodeBody) make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Function_Body;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// TODO : Support actual parsing of function body
|
2024-05-05 18:53:22 -07:00
|
|
|
Token start = currtok_noskip;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
s32 level = 0;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && ( currtok_noskip.Type != Tok_BraceCurly_Close || level > 0 ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_BraceCurly_Open )
|
2023-11-20 12:09:01 -08:00
|
|
|
level++;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( currtok_noskip.Type == Tok_BraceCurly_Close && level > 0 )
|
2023-11-20 12:09:01 -08:00
|
|
|
level--;
|
|
|
|
|
2024-05-05 18:53:22 -07:00
|
|
|
eat( currtok_noskip.Type );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
Token past = prevtok;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
s32 len = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)start.Text;
|
|
|
|
|
|
|
|
if ( len > 0 )
|
|
|
|
{
|
2024-12-06 21:21:09 -08:00
|
|
|
body_append( result, def_execution( { len, start.Text } ) );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceCurly_Close );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal neverinline
|
2024-12-03 12:19:39 -08:00
|
|
|
CodeBody parse_global_nspace( CodeType which )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-04-17 14:40:32 -07:00
|
|
|
push_scope();
|
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
if ( which != CT_Namespace_Body && which != CT_Global_Body && which != CT_Export_Body && which != CT_Extern_Linkage_Body )
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
if ( which != CT_Global_Body )
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceCurly_Open );
|
2023-11-21 20:36:56 -08:00
|
|
|
// {
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeBody
|
|
|
|
result = (CodeBody) make_code();
|
|
|
|
result->Type = which;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && currtok_noskip.Type != Tok_BraceCurly_Close )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-01 21:03:38 -08:00
|
|
|
Code member = Code_Invalid;
|
2023-11-20 12:09:01 -08:00
|
|
|
CodeAttributes attributes = { nullptr };
|
|
|
|
CodeSpecifiers specifiers = { nullptr };
|
|
|
|
|
|
|
|
bool expects_function = false;
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// Context.Scope->Start = currtok_noskip;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Preprocess_Hash )
|
|
|
|
eat( Tok_Preprocess_Hash );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
switch ( currtok_noskip.Type )
|
|
|
|
{
|
2024-12-07 14:17:02 -08:00
|
|
|
case Tok_Comma:
|
|
|
|
{
|
|
|
|
log_failure("Dangling comma found: %S\nContext:\n%S", to_string(currtok), to_string(Context));
|
|
|
|
pop( & Context);
|
|
|
|
return InvalidCode;
|
|
|
|
}
|
|
|
|
break;
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Statement_End:
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
// TODO(Ed): Convert this to a general warning procedure
|
2024-12-02 19:25:39 -08:00
|
|
|
log_fmt("Dangling end statement found %S\n", to_string(currtok_noskip));
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2024-04-17 14:40:32 -07:00
|
|
|
continue;
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_NewLine:
|
2023-11-20 12:09:01 -08:00
|
|
|
// Empty lines are auto skipped by Tokens.current()
|
|
|
|
member = fmt_newline;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_NewLine );
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Comment:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_comment();
|
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Class:
|
|
|
|
member = parse_complicated_definition( Tok_Decl_Class );
|
2023-11-21 20:36:56 -08:00
|
|
|
// class
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Enum:
|
|
|
|
member = parse_complicated_definition( Tok_Decl_Enum );
|
2023-11-21 20:36:56 -08:00
|
|
|
// enum
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Extern_Linkage:
|
2024-12-03 12:19:39 -08:00
|
|
|
if ( which == CT_Extern_Linkage_Body )
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Nested extern linkage\n%s", to_string(Context) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
member = parse_extern_link();
|
2023-11-21 20:36:56 -08:00
|
|
|
// extern "..." { ... }
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Namespace:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_namespace();
|
2023-11-21 20:36:56 -08:00
|
|
|
// namespace <Name> { ... }
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Struct:
|
|
|
|
member = parse_complicated_definition( Tok_Decl_Struct );
|
2023-11-21 20:36:56 -08:00
|
|
|
// struct ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Template:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_template();
|
2023-11-21 20:36:56 -08:00
|
|
|
// template<...> ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Typedef:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_typedef();
|
2023-11-21 20:36:56 -08:00
|
|
|
// typedef ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Union:
|
|
|
|
member = parse_complicated_definition( Tok_Decl_Union );
|
2023-11-21 20:36:56 -08:00
|
|
|
// union ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Decl_Using:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_using();
|
2023-11-21 20:36:56 -08:00
|
|
|
// using ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Define:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_define();
|
2023-11-21 20:36:56 -08:00
|
|
|
// #define ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Include:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_include();
|
2023-11-21 20:36:56 -08:00
|
|
|
// #include ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_If:
|
|
|
|
case Tok_Preprocess_IfDef:
|
|
|
|
case Tok_Preprocess_IfNotDef:
|
|
|
|
case Tok_Preprocess_ElIf:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_preprocess_cond();
|
2023-11-21 20:36:56 -08:00
|
|
|
// #<Conditional> ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Else:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = preprocess_else;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_Else );
|
2023-11-21 20:36:56 -08:00
|
|
|
// #else
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_EndIf:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = preprocess_endif;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_EndIf );
|
2023-11-21 20:36:56 -08:00
|
|
|
// #endif
|
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Macro:
|
2024-12-04 21:40:51 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
member = parse_simple_preprocess( Tok_Preprocess_Macro );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Macro>
|
2024-12-04 21:40:51 -08:00
|
|
|
|
|
|
|
if ( member == Code_Invalid )
|
|
|
|
{
|
|
|
|
log_failure( "Failed to parse member\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
|
|
|
return InvalidCode;
|
|
|
|
}
|
|
|
|
}
|
2023-11-21 20:36:56 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Pragma:
|
2023-11-21 20:36:56 -08:00
|
|
|
member = parse_pragma();
|
|
|
|
// #pragma ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Unsupported:
|
|
|
|
member = parse_simple_preprocess( Tok_Preprocess_Unsupported );
|
2023-11-21 20:36:56 -08:00
|
|
|
// #<UNSUPPORTED> ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_StaticAssert:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_static_assert();
|
2023-11-21 20:36:56 -08:00
|
|
|
// static_assert( <Conditional Expression>, ... );
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Module_Export:
|
2024-12-03 12:19:39 -08:00
|
|
|
if ( which == CT_Export_Body )
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Nested export declaration\n%s", to_string(Context) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
member = parse_export_body();
|
2023-11-21 20:36:56 -08:00
|
|
|
// export { ... }
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Module_Import:
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
not_implemented( context );
|
2023-11-21 20:36:56 -08:00
|
|
|
// import ...
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
//! Fallthrough intentional
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Attribute_Open:
|
|
|
|
case Tok_Decl_GNU_Attribute:
|
|
|
|
case Tok_Decl_MSVC_Attribute:
|
|
|
|
#define Entry( attribute, str ) case attribute:
|
2023-11-20 12:09:01 -08:00
|
|
|
GEN_DEFINE_ATTRIBUTE_TOKENS
|
|
|
|
#undef Entry
|
|
|
|
{
|
|
|
|
attributes = parse_attributes();
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
//! Fallthrough intentional
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Spec_Consteval:
|
|
|
|
case Tok_Spec_Constexpr:
|
|
|
|
case Tok_Spec_Constinit:
|
|
|
|
case Tok_Spec_Extern:
|
|
|
|
case Tok_Spec_ForceInline:
|
|
|
|
case Tok_Spec_Global:
|
|
|
|
case Tok_Spec_Inline:
|
|
|
|
case Tok_Spec_Internal_Linkage:
|
|
|
|
case Tok_Spec_NeverInline:
|
|
|
|
case Tok_Spec_Static:
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 10:14:14 -08:00
|
|
|
Specifier specs_found[16] { Spec_NumSpecifiers };
|
2023-11-20 12:09:01 -08:00
|
|
|
s32 NumSpecifiers = 0;
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
while ( left && is_specifier(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
Specifier spec = strc_to_specifier( to_str(currtok) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
bool ignore_spec = false;
|
|
|
|
|
|
|
|
switch ( spec )
|
|
|
|
{
|
2024-12-03 10:14:14 -08:00
|
|
|
case Spec_Constexpr:
|
|
|
|
case Spec_Constinit:
|
|
|
|
case Spec_ForceInline:
|
|
|
|
case Spec_Global:
|
|
|
|
case Spec_External_Linkage:
|
|
|
|
case Spec_Internal_Linkage:
|
|
|
|
case Spec_Inline:
|
|
|
|
case Spec_Mutable:
|
|
|
|
case Spec_NeverInline:
|
|
|
|
case Spec_Static:
|
|
|
|
case Spec_Volatile:
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
case Spec_Consteval:
|
2023-11-20 12:09:01 -08:00
|
|
|
expects_function = true;
|
|
|
|
break;
|
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
case Spec_Const:
|
2023-11-20 12:09:01 -08:00
|
|
|
ignore_spec = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2024-12-06 02:29:17 -08:00
|
|
|
StrC spec_str = spec_to_str(spec);
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Invalid specifier %.*s for variable\n%s", spec_str.Len, spec_str, to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ignore_spec)
|
|
|
|
break;
|
|
|
|
|
|
|
|
specs_found[NumSpecifiers] = spec;
|
|
|
|
NumSpecifiers++;
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( NumSpecifiers )
|
|
|
|
{
|
|
|
|
specifiers = def_specifiers( NumSpecifiers, specs_found );
|
|
|
|
}
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes> <Specifiers>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
//! Fallthrough intentional
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Identifier:
|
|
|
|
case Tok_Spec_Const:
|
|
|
|
case Tok_Type_Long:
|
|
|
|
case Tok_Type_Short:
|
|
|
|
case Tok_Type_Signed:
|
|
|
|
case Tok_Type_Unsigned:
|
|
|
|
case Tok_Type_bool:
|
|
|
|
case Tok_Type_char:
|
|
|
|
case Tok_Type_double:
|
|
|
|
case Tok_Type_int:
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-04-17 14:40:32 -07:00
|
|
|
Code constructor_destructor = parse_global_nspace_constructor_destructor( specifiers );
|
|
|
|
// Possible constructor implemented at global file scope.
|
|
|
|
if ( constructor_destructor )
|
|
|
|
{
|
|
|
|
member = constructor_destructor;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool found_operator_cast_outside_class_implmentation = false;
|
|
|
|
s32 idx = Context.Tokens.Idx;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
for ( ; idx < array_num(Context.Tokens.Arr); idx++ )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 19:25:39 -08:00
|
|
|
Token tok = Context.Tokens.Arr[ idx ];
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok.Type == Tok_Identifier )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
idx++;
|
2024-12-02 19:25:39 -08:00
|
|
|
tok = Context.Tokens.Arr[ idx ];
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok.Type == Tok_Access_StaticSymbol )
|
2023-11-20 12:09:01 -08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok.Type == Tok_Decl_Operator )
|
2024-04-17 14:40:32 -07:00
|
|
|
found_operator_cast_outside_class_implmentation = true;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
if ( found_operator_cast_outside_class_implmentation )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-10-25 01:08:20 -07:00
|
|
|
member = parse_operator_cast( specifiers );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes> <Specifiers> <Name>::operator <Type>() { ... }
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
member = parse_operator_function_or_variable( expects_function, attributes, specifiers );
|
2023-11-21 20:36:56 -08:00
|
|
|
// <Attributes> <Specifiers> ...
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( member == Code_Invalid )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-07 14:17:02 -08:00
|
|
|
log_failure( "Failed to parse member\nToken: %s\nContext:\n%s", to_string(currtok_noskip), to_string(Context) );
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// log_fmt("Global Body Member: %s", member->debug_str());
|
2024-12-06 21:21:09 -08:00
|
|
|
body_append(result, member );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
if ( which != CT_Global_Body )
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceCurly_Close );
|
2023-11-21 20:36:56 -08:00
|
|
|
// { <Body> }
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-04-17 14:40:32 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal inline
|
|
|
|
Code parse_global_nspace_constructor_destructor( CodeSpecifiers specifiers )
|
|
|
|
{
|
|
|
|
Code result = { nullptr };
|
|
|
|
|
|
|
|
/*
|
|
|
|
To check if a definition is for a constructor we can go straight to the opening parenthesis for its parameters
|
|
|
|
From There we work backwards to see if we come across two identifiers with the same name between an member access
|
|
|
|
:: operator, there can be template parameters on the left of the :: so we ignore those.
|
|
|
|
Whats important is that its back to back.
|
|
|
|
|
|
|
|
This has multiple possible faults. What we parse using this method may not filter out if something has a "return type"
|
|
|
|
This is bad since technically you could have a namespace nested into another namespace with the same name.
|
|
|
|
If this awful pattern is done the only way to distiguish with this coarse parse is to know there is no return type defined.
|
|
|
|
|
|
|
|
TODO(Ed): We could fix this by attempting to parse a type, but we would have to have a way to have it soft fail and rollback.
|
|
|
|
*/
|
|
|
|
TokArray tokens = Context.Tokens;
|
|
|
|
|
|
|
|
s32 idx = tokens.Idx;
|
2024-12-02 19:25:39 -08:00
|
|
|
Token nav = tokens.Arr[ idx ];
|
2024-12-04 08:01:53 -08:00
|
|
|
for ( ; idx < array_num(tokens.Arr); idx++, nav = tokens.Arr[ idx ] )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
if ( nav.Text[0] == '<' )
|
|
|
|
{
|
|
|
|
// Skip templated expressions as they mey have expressions with the () operators
|
|
|
|
s32 capture_level = 0;
|
|
|
|
s32 template_level = 0;
|
2024-12-04 08:01:53 -08:00
|
|
|
for ( ; idx < array_num(tokens.Arr); idx++, nav = tokens.Arr[idx] )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
if (nav.Text[ 0 ] == '<')
|
|
|
|
++ template_level;
|
|
|
|
|
|
|
|
if (nav.Text[ 0 ] == '>')
|
|
|
|
-- template_level;
|
2024-12-03 06:50:30 -08:00
|
|
|
if (nav.Type == Tok_Operator && nav.Text[1] == '>')
|
2024-04-17 14:40:32 -07:00
|
|
|
-- template_level;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( nav.Type == Tok_Capture_Start)
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
if (template_level != 0 )
|
|
|
|
++ capture_level;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( template_level != 0 && nav.Type == Tok_Capture_End)
|
2024-04-17 14:40:32 -07:00
|
|
|
-- capture_level;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( nav.Type == Tok_Capture_Start )
|
2024-04-17 14:40:32 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
-- idx;
|
2024-12-02 19:25:39 -08:00
|
|
|
Token tok_right = tokens.Arr[idx];
|
2024-04-17 14:40:32 -07:00
|
|
|
Token tok_left = NullToken;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if (tok_right.Type != Tok_Identifier)
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
// We're not dealing with a constructor if there is no identifier right before the opening of a parameter's scope.
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
-- idx;
|
2024-12-02 19:25:39 -08:00
|
|
|
tok_left = tokens.Arr[idx];
|
2024-04-17 14:40:32 -07:00
|
|
|
// <Attributes> <Specifiers> ... <Identifier>
|
|
|
|
|
|
|
|
bool possible_destructor = false;
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok_left.Type == Tok_Operator && tok_left.Text[0] == '~')
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
possible_destructor = true;
|
|
|
|
-- idx;
|
2024-12-02 19:25:39 -08:00
|
|
|
tok_left = tokens.Arr[idx];
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok_left.Type != Tok_Access_StaticSymbol )
|
2024-04-17 14:40:32 -07:00
|
|
|
return result;
|
|
|
|
|
|
|
|
-- idx;
|
2024-12-02 19:25:39 -08:00
|
|
|
tok_left = tokens.Arr[idx];
|
2024-04-17 14:40:32 -07:00
|
|
|
// <Attributes> <Specifiers> ... :: <Identifier>
|
|
|
|
|
|
|
|
// We search toward the left until we find the next valid identifier
|
|
|
|
s32 capture_level = 0;
|
|
|
|
s32 template_level = 0;
|
|
|
|
while ( idx != tokens.Idx )
|
|
|
|
{
|
|
|
|
if (tok_left.Text[ 0 ] == '<')
|
|
|
|
++ template_level;
|
|
|
|
|
|
|
|
if (tok_left.Text[ 0 ] == '>')
|
|
|
|
-- template_level;
|
2024-12-03 06:50:30 -08:00
|
|
|
if (tok_left.Type == Tok_Operator && tok_left.Text[1] == '>')
|
2024-04-17 14:40:32 -07:00
|
|
|
-- template_level;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( template_level != 0 && tok_left.Type == Tok_Capture_Start)
|
2024-04-17 14:40:32 -07:00
|
|
|
++ capture_level;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( template_level != 0 && tok_left.Type == Tok_Capture_End)
|
2024-04-17 14:40:32 -07:00
|
|
|
-- capture_level;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( capture_level == 0 && template_level == 0 && tok_left.Type == Tok_Identifier )
|
2024-04-17 14:40:32 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
-- idx;
|
2024-12-02 19:25:39 -08:00
|
|
|
tok_left = tokens.Arr[idx];
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
bool is_same = str_compare_len( tok_right.Text, tok_left.Text, tok_right.Length ) == 0;
|
2024-12-03 06:50:30 -08:00
|
|
|
if (tok_left.Type == Tok_Identifier && is_same)
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
// We have found the pattern we desired
|
|
|
|
if (possible_destructor)
|
|
|
|
{
|
|
|
|
// <Name> :: ~<Name> (
|
|
|
|
result = parse_destructor( specifiers );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// <Name> :: <Name> (
|
|
|
|
result = parse_constructor( specifiers );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
// TODO(Ed): I want to eventually change the identifier to its own AST type.
|
|
|
|
// This would allow distinction of the qualifier for a symbol <qualifier>::<nested symboL>
|
2024-12-06 21:21:09 -08:00
|
|
|
// This would also allow
|
2023-11-20 12:09:01 -08:00
|
|
|
internal
|
|
|
|
Token parse_identifier( bool* possible_member_function )
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
|
|
|
Token name = currtok;
|
|
|
|
Context.Scope->Name = name;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Identifier );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
parse_template_args( name );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Name><Template Args>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( check( Tok_Access_StaticSymbol ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Access_StaticSymbol );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Qualifier Name> <Template Args> ::
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( left == 0 )
|
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, unexpected end of static symbol identifier\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-03 06:50:30 -08:00
|
|
|
return { nullptr, 0, Tok_Invalid };
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Operator && currtok.Text[0] == '~' )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
bool is_destructor = str_compare( Context.Scope->Prev->ProcName, "parse_destructor" ) == 0;
|
|
|
|
if (is_destructor)
|
|
|
|
{
|
|
|
|
name.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )name.Text;
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-04-17 14:40:32 -07:00
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
log_failure( "Error, had a ~ operator after %S but not a destructor\n%s", to_str( prevtok.Type ), to_string(Context) );
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-03 06:50:30 -08:00
|
|
|
return { nullptr, 0, Tok_Invalid };
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Operator && currtok.Text[0] == '*' && currtok.Length == 1 )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
if ( possible_member_function )
|
|
|
|
*possible_member_function = true;
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Found a member function pointer identifier but the parsing context did not expect it\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-03 06:50:30 -08:00
|
|
|
return { nullptr, 0, Tok_Invalid };
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type != Tok_Identifier )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
log_failure( "Error, expected static symbol identifier, not %s\n%s", to_str( currtok.Type ), to_string(Context) );
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-03 06:50:30 -08:00
|
|
|
return { nullptr, 0, Tok_Invalid };
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
name.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)name.Text;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Identifier );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Qualifier Name> <Template Args> :: <Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
parse_template_args( name );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Qualifier Name> <Template Args> :: <Name> <Template Args>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Qualifier Name> <Template Args> :: <Name> <Template Args> ...
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeInclude parse_include()
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
|
|
|
CodeInclude
|
|
|
|
include = (CodeInclude) make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
include->Type = CT_Preprocess_Include;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_Include );
|
2023-11-22 11:23:21 -08:00
|
|
|
// #include
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ! check( Tok_String ))
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, expected include string after #include\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
Context.Scope->Name = currtok;
|
2024-12-02 19:25:39 -08:00
|
|
|
include->Content = get_cached_string( to_str(currtok) );
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_String );
|
2023-11-22 11:23:21 -08:00
|
|
|
// #include <Path> or "Path"
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return include;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeOperator parse_operator_after_ret_type(
|
|
|
|
ModuleFlag mflags
|
|
|
|
, CodeAttributes attributes
|
|
|
|
, CodeSpecifiers specifiers
|
2024-12-03 12:19:39 -08:00
|
|
|
, CodeTypename ret_type
|
2023-11-20 12:09:01 -08:00
|
|
|
)
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
|
|
|
Token nspace = NullToken;
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Identifier ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
nspace = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && currtok.Type == Tok_Identifier )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Identifier );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Access_StaticSymbol )
|
|
|
|
eat( Tok_Access_StaticSymbol );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
nspace.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)nspace.Text;
|
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <ExportFlag> <Attributes> <Specifiers> <ReturnType> <Qualifier::...>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Decl_Operator );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <ExportFlag> <Attributes> <Specifiers> <ReturnType> <Qualifier::...> operator
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ! left && currtok.Type != Tok_Operator
|
|
|
|
&& currtok.Type != Tok_Star
|
|
|
|
&& currtok.Type != Tok_Ampersand
|
|
|
|
&& currtok.Type != Tok_Ampersand_DBL )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Expected operator after 'operator' keyword\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
Context.Scope->Name = currtok;
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
bool was_new_or_delete = false;
|
|
|
|
|
2024-12-03 10:51:29 -08:00
|
|
|
Operator op = Op_Invalid;
|
2023-11-20 12:09:01 -08:00
|
|
|
switch ( currtok.Text[0] )
|
|
|
|
{
|
|
|
|
case '+':
|
|
|
|
{
|
|
|
|
if ( currtok.Text[1] == '=' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Assign_Add;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else if ( currtok.Text[1] == '+' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Increment;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Add;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
{
|
|
|
|
if ( currtok.Text[1] == '>' )
|
|
|
|
{
|
|
|
|
if ( currtok.Text[2] == '*' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_MemberOfPointer;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_MemberOfPointer;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if ( currtok.Text[1] == '=' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Assign_Subtract;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Subtract;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '*':
|
|
|
|
{
|
|
|
|
if ( currtok.Text[1] == '=' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Assign_Multiply;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Token& finder = prevtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( finder.Type != Tok_Decl_Operator )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( finder.Type == Tok_Identifier)
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Indirection;
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-03 10:51:29 -08:00
|
|
|
if ( op == Op_Invalid)
|
|
|
|
op = Op_Multiply;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '/':
|
|
|
|
{
|
|
|
|
if ( currtok.Text[1] == '=' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Assign_Divide;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Divide;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '%':
|
|
|
|
{
|
|
|
|
if ( currtok.Text[1] == '=' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Assign_Modulo;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Modulo;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '&':
|
|
|
|
{
|
|
|
|
if ( currtok.Text[1] == '=' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Assign_BAnd;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else if ( currtok.Text[1] == '&' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_LAnd;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
|
2024-12-03 10:51:29 -08:00
|
|
|
if ( op == Op_Invalid )
|
|
|
|
op = Op_BAnd;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '|':
|
|
|
|
{
|
|
|
|
if ( currtok.Text[1] == '=' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Assign_BOr;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else if ( currtok.Text[1] == '|' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_LOr;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_BOr;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '^':
|
|
|
|
{
|
|
|
|
if ( currtok.Text[1] == '=' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Assign_BXOr;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_BXOr;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '~':
|
|
|
|
{
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_BNot;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '!':
|
|
|
|
{
|
|
|
|
if ( currtok.Text[1] == '=' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_LNot;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_UnaryNot;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '=':
|
|
|
|
{
|
|
|
|
if ( currtok.Text[1] == '=' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_LEqual;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Assign;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '<':
|
|
|
|
{
|
|
|
|
if ( currtok.Text[1] == '=' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_LEqual;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else if ( currtok.Text[1] == '<' )
|
|
|
|
{
|
|
|
|
if ( currtok.Text[2] == '=' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Assign_LShift;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_LShift;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Lesser;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '>':
|
|
|
|
{
|
|
|
|
if ( currtok.Text[1] == '=' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_GreaterEqual;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else if ( currtok.Text[1] == '>' )
|
|
|
|
{
|
|
|
|
if ( currtok.Text[2] == '=' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Assign_RShift;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_RShift;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Greater;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '(':
|
|
|
|
{
|
|
|
|
if ( currtok.Text[1] == ')' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_FunctionCall;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Invalid;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '[':
|
|
|
|
{
|
|
|
|
if ( currtok.Text[1] == ']' )
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Subscript;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Invalid;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
StrC str_new = operator_to_str(Op_New);
|
|
|
|
StrC str_delete = operator_to_str(Op_Delete);
|
2024-12-04 08:01:53 -08:00
|
|
|
if ( str_compare_len( currtok.Text, str_new.Ptr, max(str_new.Len - 1, currtok.Length)) == 0)
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_New;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Identifier );
|
2024-04-17 14:40:32 -07:00
|
|
|
was_new_or_delete = true;
|
|
|
|
|
|
|
|
s32 idx = Context.Tokens.Idx + 1;
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( Context.Tokens.Arr[ idx ].Type == Tok_NewLine )
|
2024-04-17 14:40:32 -07:00
|
|
|
idx++;
|
|
|
|
}
|
2024-12-02 19:25:39 -08:00
|
|
|
Token next = Context.Tokens.Arr[idx];
|
2024-12-04 08:01:53 -08:00
|
|
|
if ( currtok.Type == Tok_Operator && str_compare_len(currtok.Text, "[]", 2) == 0)
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat(Tok_Operator);
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_NewArray;
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( currtok.Type == Tok_BraceSquare_Open && next.Type == Tok_BraceSquare_Close)
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat(Tok_BraceSquare_Open);
|
|
|
|
eat(Tok_BraceSquare_Close);
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_NewArray;
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
|
|
|
}
|
2024-12-04 08:01:53 -08:00
|
|
|
else if ( str_compare_len( currtok.Text, str_delete.Ptr, max(str_delete.Len - 1, currtok.Length )) == 0)
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_Delete;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat(Tok_Identifier);
|
2024-04-17 14:40:32 -07:00
|
|
|
was_new_or_delete = true;
|
|
|
|
|
|
|
|
s32 idx = Context.Tokens.Idx + 1;
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( Context.Tokens.Arr[ idx ].Type == Tok_NewLine )
|
2024-04-17 14:40:32 -07:00
|
|
|
idx++;
|
|
|
|
}
|
2024-12-02 19:25:39 -08:00
|
|
|
Token next = Context.Tokens.Arr[idx];
|
2024-12-04 08:01:53 -08:00
|
|
|
if ( currtok.Type == Tok_Operator && str_compare_len(currtok.Text, "[]", 2) == 0)
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat(Tok_Operator);
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_DeleteArray;
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( currtok.Type == Tok_BraceSquare_Open && next.Type == Tok_BraceSquare_Close)
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat(Tok_BraceSquare_Open);
|
|
|
|
eat(Tok_BraceSquare_Close);
|
2024-12-03 10:51:29 -08:00
|
|
|
op = Op_DeleteArray;
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-03 10:51:29 -08:00
|
|
|
if ( op == Op_Invalid )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Invalid operator '%s'\n%s", prevtok.Text, to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-03 10:51:29 -08:00
|
|
|
if ( op == Op_Invalid )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Invalid operator '%s'\n%s", currtok.Text, to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
if ( ! was_new_or_delete)
|
|
|
|
eat( currtok.Type );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <ExportFlag> <Attributes> <Specifiers> <ReturnType> <Qualifier::...> operator <Op>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Parse Params
|
|
|
|
CodeParam params = parse_params();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <ExportFlag> <Attributes> <Specifiers> <ReturnType> <Qualifier::...> operator <Op> ( <Parameters> )
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 10:51:29 -08:00
|
|
|
if ( params.ast == nullptr && op == Op_Multiply )
|
|
|
|
op = Op_MemberOfPointer;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
while ( left && is_specifier(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
if ( specifiers.ast == nullptr )
|
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
specifiers = def_specifier( strc_to_specifier( to_str(currtok)) );
|
2023-11-20 12:09:01 -08:00
|
|
|
eat( currtok.Type );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
specifiers_append(specifiers, strc_to_specifier( to_str(currtok)) );
|
2023-11-20 12:09:01 -08:00
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <ExportFlag> <Attributes> <Specifiers> <ReturnType> <Qualifier::...> operator <Op> ( <Parameters> ) <Specifiers>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Parse Body
|
|
|
|
CodeBody body = { nullptr };
|
2024-12-02 17:20:30 -08:00
|
|
|
CodeComment inline_cmt = NullCode;
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_BraceCurly_Open ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
body = parse_function_body();
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( body == Code_Invalid )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <ExportFlag> <Attributes> <Specifiers> <ReturnType> <Qualifier::...> operator <Op> ( <Parameters> ) <Specifiers> { ... }
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Token stmt_end = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <ExportFlag> <Attributes> <Specifiers> <ReturnType> <Qualifier::...> operator <Op> ( <Parameters> ) <Specifiers>;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
|
2023-11-20 12:09:01 -08:00
|
|
|
inline_cmt = parse_comment();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <ExportFlag> <Attributes> <Specifiers> <ReturnType> <Qualifier::...> operator <Op> ( <Parameters> ) <Specifiers>; <InlineCmt>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// OpValidateResult check_result = operator__validate( op, params, ret_type, specifiers );
|
2024-12-02 21:45:30 -08:00
|
|
|
CodeOperator result = def_operator( op, to_str(nspace), { params, ret_type, body, specifiers, attributes, mflags } );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( inline_cmt )
|
|
|
|
result->InlineCmt = inline_cmt;
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
Code parse_operator_function_or_variable( bool expects_function, CodeAttributes attributes, CodeSpecifiers specifiers )
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-12-01 21:03:38 -08:00
|
|
|
Code result = InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
#ifndef GEN_PARSER_DISABLE_MACRO_FUNCTION_SIGNATURES
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Preprocess_Macro )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
// Were dealing with a macro after attributes/specifiers.
|
2024-12-03 06:50:30 -08:00
|
|
|
result = parse_simple_preprocess( Tok_Preprocess_Macro );
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <Macro>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
CodeTypename type = parse_type();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <ReturnType/ValueType>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( type == InvalidCode )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool found_operator = false;
|
|
|
|
s32 idx = Context.Tokens.Idx;
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
for ( ; idx < array_num(Context.Tokens.Arr); idx++ )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 19:25:39 -08:00
|
|
|
Token tok = Context.Tokens.Arr[ idx ];
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok.Type == Tok_Identifier )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
idx++;
|
2024-12-02 19:25:39 -08:00
|
|
|
tok = Context.Tokens.Arr[ idx ];
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok.Type == Tok_Access_StaticSymbol )
|
2023-11-20 12:09:01 -08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok.Type == Tok_Decl_Operator )
|
2023-11-20 12:09:01 -08:00
|
|
|
found_operator = true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( found_operator )
|
|
|
|
{
|
|
|
|
// Dealing with an operator overload
|
2024-12-01 02:30:37 -08:00
|
|
|
result = parse_operator_after_ret_type( ModuleFlag_None, attributes, specifiers, type );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <ReturnType> operator ...
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Token name = parse_identifier();
|
|
|
|
Context.Scope->Name = name;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
bool detected_capture = check( Tok_Capture_Start );
|
2024-10-24 22:04:17 -07:00
|
|
|
|
|
|
|
// Check three tokens ahead to make sure that were not dealing with a constructor initialization...
|
|
|
|
// ( 350.0f , <--- Could be the scenario
|
|
|
|
// Example : <Capture_Start> <Value> <Comma>
|
|
|
|
// idx +1 +2
|
2024-12-03 06:50:30 -08:00
|
|
|
bool detected_comma = Context.Tokens.Arr[ Context.Tokens.Idx + 2 ].Type == Tok_Comma;
|
2024-10-24 22:04:17 -07:00
|
|
|
if ( detected_capture && ! detected_comma )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
// Dealing with a function
|
2024-12-01 02:30:37 -08:00
|
|
|
result = parse_function_after_name( ModuleFlag_None, attributes, specifiers, type, name );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <ReturnType> <Name> ( ...
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( expects_function )
|
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Expected function declaration (consteval was used)\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Dealing with a variable
|
2024-12-02 19:25:39 -08:00
|
|
|
result = parse_variable_after_name( ModuleFlag_None, attributes, specifiers, type, to_str(name) );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> ...
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodePragma parse_pragma()
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
|
|
|
CodePragma
|
|
|
|
pragma = (CodePragma) make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
pragma->Type = CT_Preprocess_Pragma;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_Pragma );
|
2023-11-22 11:23:21 -08:00
|
|
|
// #pragma
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ! check( Tok_Preprocess_Content ))
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, expected content after #pragma\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
Context.Scope->Name = currtok;
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
pragma->Content = get_cached_string( to_str(currtok) );
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_Content );
|
2023-11-22 11:23:21 -08:00
|
|
|
// #pragma <Content>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return pragma;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal inline
|
|
|
|
CodeParam parse_params( bool use_template_capture )
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
|
|
|
if ( ! use_template_capture )
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_Start );
|
2024-04-17 14:40:32 -07:00
|
|
|
// (
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Operator ) && currtok.Text[ 0 ] == '<' )
|
|
|
|
eat( Tok_Operator );
|
2024-04-17 14:40:32 -07:00
|
|
|
// <
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ! use_template_capture && check( Tok_Capture_End ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_End );
|
2023-11-22 11:23:21 -08:00
|
|
|
// )
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return { nullptr };
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( check( Tok_Operator ) && currtok.Text[ 0 ] == '>' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Operator );
|
2023-11-22 11:23:21 -08:00
|
|
|
// >
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return { nullptr };
|
|
|
|
}
|
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
Code macro = { nullptr };
|
|
|
|
CodeTypename type = { nullptr };
|
|
|
|
Code value = { nullptr };
|
|
|
|
Token name = NullToken;
|
|
|
|
Code post_name_macro = { nullptr };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Varadic_Argument ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Varadic_Argument );
|
2023-11-22 11:23:21 -08:00
|
|
|
// ( or < ...
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return param_varadic;
|
2023-11-22 11:23:21 -08:00
|
|
|
// ( ... )
|
|
|
|
// or < ... >
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
#define CheckEndParams() \
|
2024-12-03 06:50:30 -08:00
|
|
|
(use_template_capture ? (currtok.Text[ 0 ] != '>') : (currtok.Type != Tok_Capture_End))
|
2024-04-17 14:40:32 -07:00
|
|
|
|
|
|
|
// Ex: Unreal has this type of macro: vvvvvvvvv
|
|
|
|
// COREUOBJECT_API void CallFunction( FFrame& Stack, RESULT_DECL, UFunction* Function );
|
|
|
|
// and: vvvv
|
|
|
|
// AddComponentByClass(UPARAM(meta = (AllowAbstract = "false")) TSubclassOf<UActorComponent> Class, bool bManualAttachment, ...
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check(Tok_Preprocess_Macro))
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
macro = parse_simple_preprocess(Tok_Preprocess_Macro);
|
2024-04-17 14:40:32 -07:00
|
|
|
// ( <Macro>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type != Tok_Comma )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-04-17 14:40:32 -07:00
|
|
|
type = parse_type( use_template_capture );
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( type == Code_Invalid )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
|
|
|
// ( <Macro> <ValueType>
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Identifier ) )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
name = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Identifier );
|
2024-04-17 14:40:32 -07:00
|
|
|
// ( <Macro> <ValueType> <Name>
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-10-24 22:04:17 -07:00
|
|
|
// Unreal has yet another type of macro:
|
|
|
|
// template<class T UE_REQUIRES(TPointerIsConvertibleFromTo<T, UInterface>::Value)>
|
|
|
|
// class T ... and then ^this^ UE_REQUIRES shows up
|
|
|
|
// So we need to consume that.
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Preprocess_Macro ))
|
2024-10-24 22:04:17 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
post_name_macro = parse_simple_preprocess( Tok_Preprocess_Macro );
|
2024-10-24 22:04:17 -07:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// In template captures you can have a typename have direct assignment without a name
|
|
|
|
// typename = typename ...
|
|
|
|
// Which would result in a static value type from a struct expansion (traditionally)
|
|
|
|
if ( ( name.Text || use_template_capture ) && bitfield_is_equal( u32, currtok.Flags, TF_Assign ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Operator );
|
2024-04-17 14:40:32 -07:00
|
|
|
// ( <Macro> <ValueType> <Name> =
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Token value_tok = currtok;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Comma )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Expected value after assignment operator\n%s.", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
s32 capture_level = 0;
|
|
|
|
s32 template_level = 0;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( (left && ( currtok.Type != Tok_Comma ) && template_level >= 0 && CheckEndParams()) || (capture_level > 0 || template_level > 0) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-04-17 14:40:32 -07:00
|
|
|
if (currtok.Text[ 0 ] == '<')
|
|
|
|
++ template_level;
|
|
|
|
|
|
|
|
if (currtok.Text[ 0 ] == '>')
|
|
|
|
-- template_level;
|
2024-12-03 06:50:30 -08:00
|
|
|
if (currtok.Type == Tok_Operator && currtok.Text[1] == '>')
|
2024-04-17 14:40:32 -07:00
|
|
|
-- template_level;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Capture_Start)
|
2024-04-17 14:40:32 -07:00
|
|
|
++ capture_level;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Capture_End)
|
2024-04-17 14:40:32 -07:00
|
|
|
-- capture_level;
|
|
|
|
|
|
|
|
value_tok.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )value_tok.Text;
|
2023-11-20 12:09:01 -08:00
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
value = untyped_str( string_to_strc(strip_formatting( to_str(value_tok), strip_formatting_dont_preserve_newlines )) );
|
2024-04-17 14:40:32 -07:00
|
|
|
// ( <Macro> <ValueType> <Name> = <Expression>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
CodeParam result = ( CodeParam )make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Parameters;
|
2024-04-17 14:40:32 -07:00
|
|
|
|
|
|
|
result->Macro = macro;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( name.Length > 0 )
|
2024-12-02 19:25:39 -08:00
|
|
|
result->Name = get_cached_string( to_str(name) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
result->ValueType = type;
|
|
|
|
|
|
|
|
if ( value )
|
|
|
|
result->Value = value;
|
|
|
|
|
|
|
|
result->NumEntries++;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( check(Tok_Comma) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Comma );
|
2024-04-17 14:40:32 -07:00
|
|
|
// ( <Macro> <ValueType> <Name> = <Expression>,
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Code type = { nullptr };
|
|
|
|
Code value = { nullptr };
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Varadic_Argument ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Varadic_Argument );
|
2024-12-06 21:21:09 -08:00
|
|
|
params_append(result, param_varadic );
|
2023-11-20 12:09:01 -08:00
|
|
|
continue;
|
2024-04-17 14:40:32 -07:00
|
|
|
// ( <Macro> <ValueType> <Name> = <Expression>, ...
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// Ex: Unreal has this type of macro: vvvvvvvvv
|
|
|
|
// COREUOBJECT_API void CallFunction( FFrame& Stack, RESULT_DECL, UFunction* Function );
|
|
|
|
// and: vvvv
|
|
|
|
// AddComponentByClass(UPARAM(meta = (AllowAbstract = "false")) TSubclassOf<UActorComponent> Class, bool bManualAttachment, ...
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check(Tok_Preprocess_Macro))
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
macro = parse_simple_preprocess(Tok_Preprocess_Macro);
|
2024-04-17 14:40:32 -07:00
|
|
|
// ( <Macro>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type != Tok_Comma )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
type = parse_type( use_template_capture );
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( type == Code_Invalid )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
|
|
|
// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
name = { nullptr, 0, Tok_Invalid, false };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Identifier ) )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
name = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Identifier );
|
2024-04-17 14:40:32 -07:00
|
|
|
// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name>
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-10-24 22:04:17 -07:00
|
|
|
// Unreal has yet another type of macro:
|
|
|
|
// template<class T UE_REQUIRES(TPointerIsConvertibleFromTo<T, UInterface>::Value)>
|
|
|
|
// class T ... and then ^this^ UE_REQUIRES shows up
|
|
|
|
// So we need to consume that.
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Preprocess_Macro ))
|
2024-10-24 22:04:17 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
post_name_macro = parse_simple_preprocess( Tok_Preprocess_Macro );
|
2024-10-24 22:04:17 -07:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// In template captures you can have a typename have direct assignment without a name
|
|
|
|
// typename = typename ...
|
|
|
|
// Which would result in a static value type from a struct expansion (traditionally)
|
|
|
|
if ( ( name.Text || use_template_capture ) && bitfield_is_equal( u32, currtok.Flags, TF_Assign ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Operator );
|
2024-04-17 14:40:32 -07:00
|
|
|
// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name> =
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Token value_tok = currtok;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Comma )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Expected value after assignment operator\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
s32 capture_level = 0;
|
|
|
|
s32 template_level = 0;
|
2024-10-25 02:01:37 -07:00
|
|
|
while ( (left
|
2024-12-03 06:50:30 -08:00
|
|
|
&& currtok.Type != Tok_Comma
|
2024-04-17 14:40:32 -07:00
|
|
|
&& template_level >= 0
|
2024-10-25 02:01:37 -07:00
|
|
|
&& CheckEndParams()) || (capture_level > 0 || template_level > 0) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-04-17 14:40:32 -07:00
|
|
|
if (currtok.Text[ 0 ] == '<')
|
|
|
|
++ template_level;
|
|
|
|
|
|
|
|
if (currtok.Text[ 0 ] == '>')
|
|
|
|
-- template_level;
|
2024-12-03 06:50:30 -08:00
|
|
|
if (currtok.Type == Tok_Operator && currtok.Text[1] == '>')
|
2024-04-17 14:40:32 -07:00
|
|
|
-- template_level;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Capture_Start)
|
2024-04-17 14:40:32 -07:00
|
|
|
++ capture_level;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Capture_End)
|
2024-04-17 14:40:32 -07:00
|
|
|
-- capture_level;
|
|
|
|
|
|
|
|
value_tok.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )value_tok.Text;
|
2023-11-20 12:09:01 -08:00
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
value = untyped_str( string_to_strc(strip_formatting( to_str(value_tok), strip_formatting_dont_preserve_newlines )) );
|
2024-04-17 14:40:32 -07:00
|
|
|
// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name> = <Expression>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-04-17 14:40:32 -07:00
|
|
|
// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name> = <Expression>, ..
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
CodeParam param = ( CodeParam )make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
param->Type = CT_Parameters;
|
2024-04-17 14:40:32 -07:00
|
|
|
|
|
|
|
param->Macro = macro;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( name.Length > 0 )
|
2024-12-02 19:25:39 -08:00
|
|
|
param->Name = get_cached_string( to_str(name) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-10-24 22:04:17 -07:00
|
|
|
param->PostNameMacro = post_name_macro;
|
|
|
|
param->ValueType = type;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( value )
|
|
|
|
param->Value = value;
|
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
params_append(result, param );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! use_template_capture )
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_End );
|
2024-04-17 14:40:32 -07:00
|
|
|
// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name> = <Expression>, .. )
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ! check( Tok_Operator ) || currtok.Text[ 0 ] != '>' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Expected '<' after 'template' keyword\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Operator );
|
2024-04-17 14:40:32 -07:00
|
|
|
// < <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name> = <Expression>, .. >
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
2024-04-17 14:40:32 -07:00
|
|
|
#undef context
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodePreprocessCond parse_preprocess_cond()
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
if ( ! is_preprocess_cond(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, expected preprocess conditional\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
CodePreprocessCond
|
|
|
|
cond = (CodePreprocessCond) make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
cond->Type = scast(CodeType, currtok.Type - ( Tok_Preprocess_If - CT_Preprocess_If ) );
|
2023-11-20 12:09:01 -08:00
|
|
|
eat( currtok.Type );
|
2023-11-22 11:23:21 -08:00
|
|
|
// #<Conditional>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ! check( Tok_Preprocess_Content ))
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, expected content after #define\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
Context.Scope->Name = currtok;
|
2024-12-02 19:25:39 -08:00
|
|
|
cond->Content = get_cached_string( to_str(currtok) );
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_Content );
|
2023-11-22 11:23:21 -08:00
|
|
|
// #<Conditiona> <Content>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return cond;
|
|
|
|
}
|
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
internal
|
2024-12-05 21:33:53 -08:00
|
|
|
Code parse_simple_preprocess( TokType which, bool dont_consume_braces )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2023-11-22 11:23:21 -08:00
|
|
|
// TODO(Ed): We can handle a macro a bit better than this. It's AST can be made more robust..
|
|
|
|
// Make an AST_Macro, it should have an Name be the macro itself, with the function body being an optional function body node.
|
|
|
|
// If we want it to terminate or have an inline comment we can possbily use its parent typedef for that info...
|
2023-11-20 12:09:01 -08:00
|
|
|
push_scope();
|
|
|
|
|
|
|
|
Token tok = currtok;
|
|
|
|
eat( which );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Macro>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
if ( ! dont_consume_braces && peektok.Type == Tok_BraceCurly_Open )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
// Eat the block scope right after the macro. Were assuming the macro defines a function definition's signature
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceCurly_Open );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Macro> {
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-22 11:23:21 -08:00
|
|
|
// TODO(Ed) : Parse this properly later (expression and statement support)
|
2023-11-20 12:09:01 -08:00
|
|
|
s32 level = 0;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && ( currtok.Type != Tok_BraceCurly_Close || level > 0 ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_BraceCurly_Open )
|
2023-11-20 12:09:01 -08:00
|
|
|
level++;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( currtok.Type == Tok_BraceCurly_Close && level > 0 )
|
2023-11-20 12:09:01 -08:00
|
|
|
level--;
|
|
|
|
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceCurly_Close );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Macro> { <Body> }
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
StrC prev_proc = Context.Scope->Prev->ProcName;
|
2024-12-04 08:01:53 -08:00
|
|
|
if ( str_compare_len( prev_proc.Ptr, "parse_typedef", prev_proc.Len ) != 0 )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Statement_End ))
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
Token stmt_end = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Macro> { <Content> };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
|
|
|
|
eat( Tok_Comment );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Macro> { <Content> }; <InlineCmt>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tok.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)tok.Text;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-07 16:44:58 -08:00
|
|
|
// If the macro is just a macro in the body of an AST it may have a semi-colon for the user to close on purpsoe
|
|
|
|
// (especially for functional macros)
|
|
|
|
StrC& calling_proc = Context.Scope->Prev->ProcName;
|
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
if (strc_contains(Context.Scope->Prev->ProcName, txt("parse_enum")))
|
|
|
|
{
|
|
|
|
// Do nothing
|
2024-12-06 02:29:17 -08:00
|
|
|
goto Leave_Scope_Early;
|
2024-12-05 21:33:53 -08:00
|
|
|
}
|
|
|
|
else if (strc_contains(Context.Scope->Prev->ProcName, txt("parse_typedef")))
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-07 16:44:58 -08:00
|
|
|
// TODO(Ed): Reveiw the context for this?
|
2024-12-04 21:40:51 -08:00
|
|
|
if ( peektok.Type == Tok_Statement_End )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
Token stmt_end = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Macro>;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-07 16:44:58 -08:00
|
|
|
// TODO(Ed): Reveiw the context for this? (ESPECIALLY THIS)
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
|
|
|
|
eat( Tok_Comment );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Macro>; <InlineCmt>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-07 16:44:58 -08:00
|
|
|
}
|
|
|
|
else if (
|
|
|
|
strc_contains(calling_proc, txt("parse_global_nspace"))
|
|
|
|
&& strc_contains(calling_proc, txt("parse_class_struct_body"))
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (peektok.Type == Tok_Statement_End)
|
|
|
|
{
|
|
|
|
Token stmt_end = currtok;
|
|
|
|
eat( Tok_Statement_End );
|
|
|
|
// <Macro>;
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-04 21:40:51 -08:00
|
|
|
tok.Length = ( (sptr)currtok_noskip.Text + currtok_noskip.Length ) - (sptr)tok.Text;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-06 02:29:17 -08:00
|
|
|
Leave_Scope_Early:
|
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
char const* content = str_fmt_buf( "%.*s ", tok.Length, tok.Text );
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
Code result = untyped_str( to_strc_from_c_str(content) );
|
2023-11-20 12:09:01 -08:00
|
|
|
Context.Scope->Name = tok;
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
Code parse_static_assert()
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
|
|
|
Code
|
|
|
|
assert = make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
assert->Type = CT_Untyped;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Token content = currtok;
|
|
|
|
|
|
|
|
Context.Scope->Name = content;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_StaticAssert );
|
|
|
|
eat( Tok_Capture_Start );
|
2023-11-22 11:23:21 -08:00
|
|
|
// static_assert(
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-22 11:23:21 -08:00
|
|
|
// TODO(Ed) : Parse this properly.
|
2023-11-20 12:09:01 -08:00
|
|
|
s32 level = 0;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && ( currtok.Type != Tok_Capture_End || level > 0 ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Capture_Start )
|
2023-11-20 12:09:01 -08:00
|
|
|
level++;
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( currtok.Type == Tok_Capture_End )
|
2023-11-20 12:09:01 -08:00
|
|
|
level--;
|
|
|
|
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_End );
|
|
|
|
eat( Tok_Statement_End );
|
2023-11-22 11:23:21 -08:00
|
|
|
// static_assert( <Content> );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
content.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)content.Text;
|
|
|
|
|
|
|
|
char const* str = str_fmt_buf( "%.*s\n", content.Length, content.Text );
|
|
|
|
assert->Content = get_cached_string( { content.Length + 1, str } );
|
|
|
|
assert->Name = assert->Content;
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return assert;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
This a brute-froce make all the arguments part of the token provided.
|
|
|
|
Can have in-place function signatures, regular identifiers, in-place typenames, compile-time expressions, parameter-pack expansion, etc.
|
|
|
|
This means that validation can only go so far, and so if there is any different in formatting
|
|
|
|
passed the basic stripping supported it report a soft failure.
|
|
|
|
*/
|
|
|
|
internal inline
|
|
|
|
void parse_template_args( Token& token )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Operator && currtok.Text[ 0 ] == '<' && currtok.Length == 1 )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Operator );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
s32 level = 0;
|
2024-04-17 14:40:32 -07:00
|
|
|
while ( left && level >= 0 && ( currtok.Text[ 0 ] != '>' || level > 0 ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-04-17 14:40:32 -07:00
|
|
|
if ( currtok.Text[ 0 ] == '<' )
|
2023-11-20 12:09:01 -08:00
|
|
|
level++;
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
if ( currtok.Text[ 0 ] == '>' )
|
|
|
|
level--;
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Operator && currtok.Text[1] == '>')
|
2023-11-20 12:09:01 -08:00
|
|
|
level--;
|
|
|
|
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// < <Content>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// Due to the >> token, this could have been eaten early...
|
|
|
|
if (level == 0)
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Operator );
|
2023-11-22 11:23:21 -08:00
|
|
|
// < <Content> >
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Extend length of name to last token
|
2024-04-17 14:40:32 -07:00
|
|
|
token.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )token.Text;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Variable parsing is handled in multiple places because its initial signature is shared with function parsing
|
|
|
|
internal
|
|
|
|
CodeVar parse_variable_after_name(
|
|
|
|
ModuleFlag mflags
|
|
|
|
, CodeAttributes attributes
|
|
|
|
, CodeSpecifiers specifiers
|
2024-12-03 12:19:39 -08:00
|
|
|
, CodeTypename type
|
2023-11-20 12:09:01 -08:00
|
|
|
, StrC name
|
|
|
|
)
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
|
|
|
Code array_expr = parse_array_decl();
|
|
|
|
Code expr = { nullptr };
|
|
|
|
Code bitfield_expr = { nullptr };
|
|
|
|
|
2024-10-24 22:04:17 -07:00
|
|
|
b32 using_constructor_initializer = false;
|
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) )
|
|
|
|
{
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> = <Expression>
|
2024-04-17 14:40:32 -07:00
|
|
|
expr = parse_assignment_expression();
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_BraceCurly_Open )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
Token expr_tok = currtok;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceCurly_Open );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> {
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
s32 level = 0;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && ( currtok.Type != Tok_BraceCurly_Close || level > 0 ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_BraceCurly_Open )
|
2023-11-20 12:09:01 -08:00
|
|
|
level++;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( currtok.Type == Tok_BraceCurly_Close && level > 0 )
|
2023-11-20 12:09:01 -08:00
|
|
|
level--;
|
|
|
|
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceCurly_Close );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
expr_tok.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)expr_tok.Text;
|
2024-12-02 19:25:39 -08:00
|
|
|
expr = untyped_str( to_str(expr_tok) );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> = { <Expression> }
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Capture_Start )
|
2024-10-24 22:04:17 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_Start);
|
2024-10-24 22:04:17 -07:00
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> (
|
|
|
|
|
|
|
|
Token expr_token = currtok;
|
|
|
|
|
|
|
|
using_constructor_initializer = true;
|
|
|
|
|
|
|
|
s32 level = 0;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && ( currtok.Type != Tok_Capture_End || level > 0 ) )
|
2024-10-24 22:04:17 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Capture_Start )
|
2024-10-24 22:04:17 -07:00
|
|
|
level++;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( currtok.Type == Tok_Capture_End && level > 0 )
|
2024-10-24 22:04:17 -07:00
|
|
|
level--;
|
|
|
|
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
|
|
|
expr_token.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)expr_token.Text;
|
2024-12-02 19:25:39 -08:00
|
|
|
expr = untyped_str( to_str(expr_token) );
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_End );
|
2024-10-24 22:04:17 -07:00
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> ( <Expression> )
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Assign_Classifer )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Assign_Classifer );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> :
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Token expr_tok = currtok;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Statement_End )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Expected expression after bitfield \n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && currtok.Type != Tok_Statement_End )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
|
|
|
expr_tok.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)expr_tok.Text;
|
2024-12-02 19:25:39 -08:00
|
|
|
bitfield_expr = untyped_str( to_str(expr_tok) );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> : <Expression>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 17:20:30 -08:00
|
|
|
CodeVar next_var = NullCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
Token stmt_end = NullToken;
|
2024-12-02 17:20:30 -08:00
|
|
|
CodeComment inline_cmt = NullCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
if ( type )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Comma )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
// Were dealing with a statement with more than one declaration
|
|
|
|
// This is only handled this way if its the first declaration
|
|
|
|
// Otherwise its looped through in parse_variable_declaration_list
|
|
|
|
next_var = parse_variable_declaration_list();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> : <Expression>, ...
|
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> = <Expression>, ...
|
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> { <Expression> }, ...
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we're dealing with a "comma-procedding then we cannot expect a statement end or inline comment
|
|
|
|
// Any comma procedding variable will not have a type provided so it can act as a indicator to skip this
|
|
|
|
Token stmt_end = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> : <Expression>, ...;
|
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> = <Expression>, ...;
|
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> { <Expression> }, ...;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Check for inline comment : <type> <identifier> = <expression>; // <inline comment>
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( left && ( currtok_noskip.Type == Tok_Comment ) && currtok_noskip.Line == stmt_end.Line )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
inline_cmt = parse_comment();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> : <Expression>, ...; <InlineCmt>
|
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> = <Expression>, ...; <InlineCmt>
|
|
|
|
// <Attributes> <Specifiers> <ValueType> <Name> { <Expression> }, ...; <InlineCmt>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CodeVar
|
|
|
|
result = (CodeVar) make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Variable;
|
2023-11-20 12:09:01 -08:00
|
|
|
result->Name = get_cached_string( name );
|
|
|
|
result->ModuleFlags = mflags;
|
|
|
|
|
|
|
|
// Type can be null if we're dealing with a declaration from a variable declaration-list
|
|
|
|
if ( type )
|
|
|
|
result->ValueType = type;
|
|
|
|
|
|
|
|
if (array_expr )
|
|
|
|
type->ArrExpr = array_expr;
|
|
|
|
|
|
|
|
if ( bitfield_expr )
|
|
|
|
result->BitfieldSize = bitfield_expr;
|
|
|
|
|
|
|
|
if ( attributes )
|
|
|
|
result->Attributes = attributes;
|
|
|
|
|
|
|
|
if ( specifiers )
|
|
|
|
result->Specs = specifiers;
|
|
|
|
|
|
|
|
if ( expr )
|
|
|
|
result->Value = expr;
|
|
|
|
|
|
|
|
if ( inline_cmt )
|
|
|
|
result->InlineCmt = inline_cmt;
|
|
|
|
|
|
|
|
if ( next_var )
|
|
|
|
{
|
|
|
|
result->NextVar = next_var;
|
|
|
|
result->NextVar->Parent = result;
|
|
|
|
}
|
|
|
|
|
2024-10-24 22:04:17 -07:00
|
|
|
result->VarConstructorInit = using_constructor_initializer;
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Note(Ed): This does not support the following:
|
|
|
|
* Function Pointers
|
|
|
|
*/
|
2024-04-17 15:29:30 -07:00
|
|
|
internal
|
|
|
|
CodeVar parse_variable_declaration_list()
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-12-02 17:20:30 -08:00
|
|
|
CodeVar result = NullCode;
|
|
|
|
CodeVar last_var = NullCode;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( check( Tok_Comma ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Comma );
|
2023-11-22 11:23:21 -08:00
|
|
|
// ,
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 17:20:30 -08:00
|
|
|
CodeSpecifiers specifiers = NullCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
while ( left && is_specifier(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
Specifier spec = strc_to_specifier( to_str(currtok) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
switch ( spec )
|
|
|
|
{
|
2024-12-03 10:14:14 -08:00
|
|
|
case Spec_Const:
|
|
|
|
if ( specifiers->NumEntries && specifiers->ArrSpecs[ specifiers->NumEntries - 1 ] != Spec_Ptr )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
log_failure( "Error, const specifier must come after pointer specifier for variable declaration proceeding comma\n"
|
|
|
|
"(Parser will add and continue to specifiers, but will most likely fail to compile)\n%s"
|
2024-12-03 06:31:27 -08:00
|
|
|
, to_string(Context) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
specifiers_append(specifiers, spec );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
case Spec_Ptr:
|
|
|
|
case Spec_Ref:
|
|
|
|
case Spec_RValue:
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
log_failure( "Error, invalid specifier '%s' proceeding comma\n"
|
|
|
|
"(Parser will add and continue to specifiers, but will most likely fail to compile)\n%s"
|
2024-12-03 06:31:27 -08:00
|
|
|
, currtok.Text, to_string(Context) );
|
2023-11-20 12:09:01 -08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-10-24 22:04:17 -07:00
|
|
|
// eat(currtok.Type);
|
2024-05-05 18:53:22 -07:00
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
if ( specifiers )
|
2024-12-06 21:21:09 -08:00
|
|
|
specifiers_append(specifiers, spec );
|
2023-11-20 12:09:01 -08:00
|
|
|
else
|
|
|
|
specifiers = def_specifier( spec );
|
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// , <Specifiers>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
StrC name = to_str(currtok);
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Identifier );
|
2023-11-22 11:23:21 -08:00
|
|
|
// , <Specifiers> <Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 17:20:30 -08:00
|
|
|
CodeVar var = parse_variable_after_name( ModuleFlag_None, NullCode, specifiers, NullCode, name );
|
2023-11-22 11:23:21 -08:00
|
|
|
// , <Specifiers> <Name> ...
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( ! result )
|
|
|
|
{
|
|
|
|
result.ast = var.ast;
|
|
|
|
last_var.ast = var.ast;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
last_var->NextVar.ast = var.ast;
|
|
|
|
last_var->NextVar->Parent.ast = rcast(AST*, var.ast);
|
|
|
|
last_var.ast = var.ast;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeClass parse_class( bool inplace_def )
|
|
|
|
{
|
|
|
|
push_scope();
|
2024-12-03 06:50:30 -08:00
|
|
|
CodeClass result = (CodeClass) parse_class_struct( Tok_Decl_Class, inplace_def );
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
2024-04-17 14:40:32 -07:00
|
|
|
CodeConstructor parse_constructor( CodeSpecifiers specifiers )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
Token identifier = parse_identifier();
|
|
|
|
CodeParam params = parse_params();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Name> ( <Parameters> )
|
|
|
|
|
2024-12-02 17:20:30 -08:00
|
|
|
Code initializer_list = NullCode;
|
|
|
|
CodeBody body = NullCode;
|
|
|
|
CodeComment inline_cmt = NullCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-22 11:23:21 -08:00
|
|
|
// TODO(Ed) : Need to support postfix specifiers
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Assign_Classifer ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Assign_Classifer );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Name> ( <Parameters> ) :
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
Token initializer_list_tok = currtok;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
s32 level = 0;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && ( currtok.Type != Tok_BraceCurly_Open || level > 0 ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if (currtok.Type == Tok_Capture_Start)
|
2023-11-20 12:09:01 -08:00
|
|
|
level++;
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( currtok.Type == Tok_Capture_End )
|
2023-11-20 12:09:01 -08:00
|
|
|
level--;
|
|
|
|
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
initializer_list_tok.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )initializer_list_tok.Text;
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Name> ( <Parameters> ) : <InitializerList>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
initializer_list = untyped_str( to_str(initializer_list_tok) );
|
2024-04-17 14:40:32 -07:00
|
|
|
|
|
|
|
// TODO(Ed): Constructors can have post-fix specifiers
|
|
|
|
|
|
|
|
body = parse_function_body();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Name> ( <Parameters> ) : <InitializerList> { <Body> }
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( check( Tok_BraceCurly_Open ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
body = parse_function_body();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Name> ( <Parameters> ) { <Body> }
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( check( Tok_Operator) && currtok.Text[ 0 ] == '=' )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
body = parse_assignment_expression();
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
Token stmt_end = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Name> ( <Parameters> );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
|
2023-11-20 12:09:01 -08:00
|
|
|
inline_cmt = parse_comment();
|
2024-04-17 14:40:32 -07:00
|
|
|
// <Name> ( <Parameters> ); <InlineCmt>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
CodeConstructor result = ( CodeConstructor )make_code();
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
result->Name = get_cached_string( to_str(identifier));
|
2024-04-17 14:40:32 -07:00
|
|
|
|
|
|
|
result->Specs = specifiers;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( params )
|
|
|
|
result->Params = params;
|
|
|
|
|
|
|
|
if ( initializer_list )
|
|
|
|
result->InitializerList = initializer_list;
|
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
if ( body && body->Type == CT_Function_Body )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
result->Body = body;
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Constructor;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
else
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Constructor_Fwd;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( inline_cmt )
|
|
|
|
result->InlineCmt = inline_cmt;
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeDestructor parse_destructor( CodeSpecifiers specifiers )
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
bool has_context = Context.Scope && Context.Scope->Prev;
|
|
|
|
bool is_in_global_nspace = has_context && str_compare( Context.Scope->Prev->ProcName, "parse_global_nspace" ) == 0;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Spec_Virtual ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
if ( specifiers )
|
2024-12-06 21:21:09 -08:00
|
|
|
specifiers_append(specifiers, Spec_Virtual );
|
2023-11-20 12:09:01 -08:00
|
|
|
else
|
2024-12-03 10:14:14 -08:00
|
|
|
specifiers = def_specifier( Spec_Virtual );
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Spec_Virtual );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Virtual Specifier>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
Token prefix_identifier = NullToken;
|
|
|
|
if (is_in_global_nspace)
|
|
|
|
prefix_identifier = parse_identifier();
|
|
|
|
|
|
|
|
if ( left && currtok.Text[ 0 ] == '~' )
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Operator );
|
2023-11-20 12:09:01 -08:00
|
|
|
else
|
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Expected destructor '~' token\n%s", to_string(Context) );
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Virtual Specifier> ~
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-22 11:23:21 -08:00
|
|
|
Token identifier = parse_identifier();
|
|
|
|
CodeBody body = { nullptr };
|
2024-12-02 17:20:30 -08:00
|
|
|
CodeComment inline_cmt = NullCode;
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Virtual Specifier> ~<Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_Start );
|
|
|
|
eat( Tok_Capture_End );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Virtual Specifier> ~<Name>()
|
|
|
|
|
|
|
|
bool pure_virtual = false;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Operator ) && currtok.Text[ 0 ] == '=' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Virtual Specifier> ~<Name>() =
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
bool skip_formatting = true;
|
2024-12-02 19:25:39 -08:00
|
|
|
Token upcoming = nexttok;
|
|
|
|
if ( left && upcoming.Text[ 0 ] == '0' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Operator );
|
|
|
|
eat( Tok_Number );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Virtual Specifier> ~<Name>() = 0
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
specifiers_append(specifiers, Spec_Pure );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-04 08:01:53 -08:00
|
|
|
else if ( left && str_compare_len( upcoming.Text, "default", sizeof("default") - 1 ) == 0)
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
body = parse_assignment_expression();
|
|
|
|
// <Virtual Specifier> ~<
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
else
|
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Pure or default specifier expected due to '=' token\n%s", to_string(Context) );
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2023-11-22 11:23:21 -08:00
|
|
|
pure_virtual = true;
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ! pure_virtual && check( Tok_BraceCurly_Open ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
body = parse_function_body();
|
2024-04-17 14:40:32 -07:00
|
|
|
// <Virtual Specifier> ~<Name>() { ... }
|
2023-11-20 12:09:01 -08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
Token stmt_end = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Virtual Specifier> ~<Name>() <Pure Specifier>;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
|
2023-11-20 12:09:01 -08:00
|
|
|
inline_cmt = parse_comment();
|
2024-04-17 14:40:32 -07:00
|
|
|
// <Virtual Specifier> ~<Name>() <Pure Specifier>; <InlineCmt>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
CodeDestructor result = ( CodeDestructor )make_code();
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
if ( is_valid(prefix_identifier) )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
prefix_identifier.Length += 1 + identifier.Length;
|
2024-12-02 19:25:39 -08:00
|
|
|
result->Name = get_cached_string( to_str(prefix_identifier) );
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( specifiers )
|
|
|
|
result->Specs = specifiers;
|
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
if ( body && body->Type == CT_Function_Body )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
result->Body = body;
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Destructor;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
else
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Destructor_Fwd;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( inline_cmt )
|
|
|
|
result->InlineCmt = inline_cmt;
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeEnum parse_enum( bool inplace_def )
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
Specifier specs_found[16] { Spec_NumSpecifiers };
|
2024-12-04 21:40:51 -08:00
|
|
|
s32 NumSpecifiers = 0;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeAttributes attributes = { nullptr };
|
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
Token name = { nullptr, 0, Tok_Invalid };
|
|
|
|
Code array_expr = { nullptr };
|
|
|
|
CodeTypename type = { nullptr };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
char entries_code[ kilobytes(128) ] { 0 };
|
|
|
|
s32 entries_length = 0;
|
|
|
|
|
|
|
|
bool is_enum_class = false;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Decl_Enum );
|
2023-11-22 11:23:21 -08:00
|
|
|
// enum
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Decl_Class )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Decl_Class);
|
2023-11-20 12:09:01 -08:00
|
|
|
is_enum_class = true;
|
2023-11-22 11:23:21 -08:00
|
|
|
// enum class
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
attributes = parse_attributes();
|
2023-11-22 11:23:21 -08:00
|
|
|
// enum <class> <Attributes>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Identifier ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
name = currtok;
|
|
|
|
Context.Scope->Name = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Identifier );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// enum <class> <Attributes> <Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-01 02:30:37 -08:00
|
|
|
b32 use_macro_underlying = false;
|
2024-12-04 21:40:51 -08:00
|
|
|
Code underlying_macro = { nullptr };
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Assign_Classifer )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Assign_Classifer );
|
2023-11-22 11:23:21 -08:00
|
|
|
// enum <class> <Attributes> <Name> :
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
type = parse_type();
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( type == Code_Invalid )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Failed to parse enum classifier\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// enum <class> <Attributes> <Name> : <UnderlyingType>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-05 21:33:53 -08:00
|
|
|
else if ( currtok.Type == Tok_Preprocess_Macro )
|
2024-12-01 02:30:37 -08:00
|
|
|
{
|
|
|
|
// We'll support the enum_underlying macro
|
2024-12-05 21:33:53 -08:00
|
|
|
StrC sig = txt("enum_underlying(");
|
|
|
|
if ( strc_contains(to_str(currtok), sig) )
|
2024-12-01 02:30:37 -08:00
|
|
|
{
|
|
|
|
use_macro_underlying = true;
|
2024-12-05 21:33:53 -08:00
|
|
|
underlying_macro = parse_simple_preprocess( Tok_Preprocess_Macro, dont_consume_braces );
|
2024-12-01 02:30:37 -08:00
|
|
|
}
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeBody body = { nullptr };
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_BraceCurly_Open )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
body = (CodeBody) make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
body->Type = CT_Enum_Body;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceCurly_Open );
|
2023-11-22 11:23:21 -08:00
|
|
|
// enum <class> <Attributes> <Name> : <UnderlyingType> {
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-01 21:03:38 -08:00
|
|
|
Code member = InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-22 11:23:21 -08:00
|
|
|
bool expects_entry = true;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && currtok_noskip.Type != Tok_BraceCurly_Close )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2023-11-22 11:23:21 -08:00
|
|
|
if ( ! expects_entry )
|
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Did not expect an entry after last member of enum body.\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2023-11-22 11:23:21 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Preprocess_Hash )
|
|
|
|
eat( Tok_Preprocess_Hash );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
switch ( currtok_noskip.Type )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_NewLine:
|
2024-12-02 19:25:39 -08:00
|
|
|
member = untyped_str( to_str(currtok_noskip) );
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_NewLine );
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Comment:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_comment();
|
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Define:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_define();
|
2023-11-22 11:23:21 -08:00
|
|
|
// #define
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_If:
|
|
|
|
case Tok_Preprocess_IfDef:
|
|
|
|
case Tok_Preprocess_IfNotDef:
|
|
|
|
case Tok_Preprocess_ElIf:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_preprocess_cond();
|
2023-11-22 11:23:21 -08:00
|
|
|
// #<if, ifdef, ifndef, elif> ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Else:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = preprocess_else;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_Else );
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_EndIf:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = preprocess_endif;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_EndIf );
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Macro:
|
|
|
|
member = parse_simple_preprocess( Tok_Preprocess_Macro );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Macro>
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Pragma:
|
2023-11-20 12:09:01 -08:00
|
|
|
member = parse_pragma();
|
2023-11-22 11:23:21 -08:00
|
|
|
// #pragma
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
case Tok_Preprocess_Unsupported:
|
|
|
|
member = parse_simple_preprocess( Tok_Preprocess_Unsupported );
|
2023-11-22 11:23:21 -08:00
|
|
|
// #<UNSUPPORTED>
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Token entry = currtok;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Identifier);
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Operator && currtok.Text[0] == '=' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Operator );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Name> =
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-04 21:40:51 -08:00
|
|
|
while ( currtok.Type != Tok_Comma && currtok.Type != Tok_BraceCurly_Close )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-04 21:40:51 -08:00
|
|
|
eat( currtok.Type );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Name> = <Expression>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// Unreal UMETA macro support
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Preprocess_Macro )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_Macro );
|
2024-04-17 14:40:32 -07:00
|
|
|
// <Name> = <Expression> <Macro>
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Comma )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-04 21:40:51 -08:00
|
|
|
//Token prev = * previous(Context.Tokens, dont_skip_formatting);
|
|
|
|
//entry.Length = ( (sptr)prev.Text + prev.Length ) - (sptr)entry.Text;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Comma );
|
2024-04-17 14:40:32 -07:00
|
|
|
// <Name> = <Expression> <Macro>,
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-05-05 18:53:22 -07:00
|
|
|
// Consume inline comments
|
2024-12-03 06:50:30 -08:00
|
|
|
// if ( currtok.Type == Tok_Comment && prevtok.Line == currtok.Line )
|
2024-10-24 22:04:17 -07:00
|
|
|
// {
|
2024-12-03 06:50:30 -08:00
|
|
|
// eat( Tok_Comment );
|
2024-05-05 18:53:22 -07:00
|
|
|
// <Name> = <Expression> <Macro>, // <Inline Comment>
|
2024-10-24 22:04:17 -07:00
|
|
|
// }
|
2024-12-06 02:29:17 -08:00
|
|
|
|
2024-12-04 21:40:51 -08:00
|
|
|
Token prev = * previous(Context.Tokens, dont_skip_formatting);
|
|
|
|
entry.Length = ( (sptr)prev.Text + prev.Length ) - (sptr)entry.Text;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
member = untyped_str( to_str(entry) );
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( member == Code_Invalid )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Failed to parse member\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-06 21:21:09 -08:00
|
|
|
body_append(body, member );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceCurly_Close );
|
2023-11-22 11:23:21 -08:00
|
|
|
// enum <class> <Attributes> <Name> : <UnderlyingType> { <Body> }
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 17:20:30 -08:00
|
|
|
CodeComment inline_cmt = NullCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( ! inplace_def )
|
|
|
|
{
|
|
|
|
Token stmt_end = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2023-11-22 11:23:21 -08:00
|
|
|
// enum <class> <Attributes> <Name> : <UnderlyingType> { <Body> };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
|
2023-11-20 12:09:01 -08:00
|
|
|
inline_cmt = parse_comment();
|
2023-11-22 11:23:21 -08:00
|
|
|
// enum <class> <Attributes> <Name> : <UnderlyingType> { <Body> }; <InlineCmt>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
CodeEnum
|
|
|
|
result = (CodeEnum) make_code();
|
|
|
|
|
|
|
|
if ( body.ast )
|
|
|
|
{
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = is_enum_class ? CT_Enum_Class : CT_Enum;
|
2023-11-20 12:09:01 -08:00
|
|
|
result->Body = body;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = is_enum_class ? CT_Enum_Class_Fwd : CT_Enum_Fwd;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
result->Name = get_cached_string( to_str(name) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( attributes )
|
|
|
|
result->Attributes = attributes;
|
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
result->UnderlyingTypeMacro = underlying_macro;
|
|
|
|
result->UnderlyingType = type;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( inline_cmt )
|
|
|
|
result->InlineCmt = inline_cmt;
|
|
|
|
|
2024-12-01 02:30:37 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal inline
|
|
|
|
CodeBody parse_export_body()
|
|
|
|
{
|
|
|
|
push_scope();
|
2024-12-03 12:19:39 -08:00
|
|
|
CodeBody result = parse_global_nspace( CT_Export_Body );
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal inline
|
|
|
|
CodeBody parse_extern_link_body()
|
|
|
|
{
|
|
|
|
push_scope();
|
2024-12-03 12:19:39 -08:00
|
|
|
CodeBody result = parse_global_nspace( CT_Extern_Linkage_Body );
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeExtern parse_extern_link()
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Decl_Extern_Linkage );
|
2023-11-22 11:23:21 -08:00
|
|
|
// extern
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Token name = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_String );
|
2023-11-22 11:23:21 -08:00
|
|
|
// extern "<Name>"
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
name.Text += 1;
|
|
|
|
name.Length -= 1;
|
|
|
|
|
|
|
|
CodeExtern
|
|
|
|
result = (CodeExtern) make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Extern_Linkage;
|
2024-12-02 19:25:39 -08:00
|
|
|
result->Name = get_cached_string( to_str(name) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Code entry = parse_extern_link_body();
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( entry == Code_Invalid )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Failed to parse body\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// extern "<Name>" { <Body> }
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
result->Body = entry;
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeFriend parse_friend()
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Decl_Friend );
|
2023-11-22 11:23:21 -08:00
|
|
|
// friend
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-04 12:00:37 -08:00
|
|
|
CodeFn function = { nullptr };
|
|
|
|
CodeOperator op = { nullptr };
|
|
|
|
CodeSpecifiers specifiers = { nullptr };
|
|
|
|
|
|
|
|
// Specifiers Parsing
|
|
|
|
{
|
|
|
|
Specifier specs_found[ 16 ] { Spec_NumSpecifiers };
|
|
|
|
s32 NumSpecifiers = 0;
|
|
|
|
|
|
|
|
while ( left && is_specifier(currtok) )
|
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
Specifier spec = strc_to_specifier( to_str(currtok) );
|
2024-12-04 12:00:37 -08:00
|
|
|
|
|
|
|
switch ( spec )
|
|
|
|
{
|
|
|
|
case Spec_Const :
|
|
|
|
case Spec_Inline :
|
|
|
|
case Spec_ForceInline :
|
|
|
|
break;
|
|
|
|
|
|
|
|
default :
|
2024-12-06 02:29:17 -08:00
|
|
|
log_failure( "Invalid specifier %s for friend definition\n%s", spec_to_str( spec ), to_string(Context) );
|
2024-12-04 12:00:37 -08:00
|
|
|
pop(& Context);
|
|
|
|
return InvalidCode;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignore const it will be handled by the type
|
|
|
|
if ( spec == Spec_Const )
|
|
|
|
break;
|
|
|
|
|
|
|
|
specs_found[ NumSpecifiers ] = spec;
|
|
|
|
NumSpecifiers++;
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( NumSpecifiers )
|
|
|
|
{
|
|
|
|
specifiers = def_specifiers( NumSpecifiers, specs_found );
|
|
|
|
}
|
|
|
|
// <friend> <specifiers>
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Type declaration or return type
|
2024-12-03 12:19:39 -08:00
|
|
|
CodeTypename type = parse_type();
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( type == Code_Invalid )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 12:41:41 -08:00
|
|
|
// friend <Type>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Funciton declaration
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Identifier )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
// Name
|
2024-04-17 14:40:32 -07:00
|
|
|
Token name = parse_identifier();
|
2023-11-20 12:09:01 -08:00
|
|
|
Context.Scope->Name = name;
|
2023-11-22 11:23:21 -08:00
|
|
|
// friend <ReturnType> <Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-04 12:00:37 -08:00
|
|
|
function = parse_function_after_name( ModuleFlag_None, NullCode, specifiers, type, name );
|
2024-04-17 14:40:32 -07:00
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
// Parameter list
|
2024-04-17 14:40:32 -07:00
|
|
|
// CodeParam params = parse_params();
|
2023-11-22 11:23:21 -08:00
|
|
|
// friend <ReturnType> <Name> ( <Parameters> )
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// function = make_code();
|
|
|
|
// function->Type = Function_Fwd;
|
|
|
|
// function->Name = get_cached_string( name );
|
|
|
|
// function->ReturnType = type;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// if ( params )
|
|
|
|
// function->Params = params;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 17:42:35 -08:00
|
|
|
|
2024-12-03 17:21:08 -08:00
|
|
|
// Operator declaration or definition
|
|
|
|
if ( currtok.Type == Tok_Decl_Operator )
|
|
|
|
{
|
2024-12-04 12:00:37 -08:00
|
|
|
op = parse_operator_after_ret_type( ModuleFlag_None, NullCode, specifiers, type );
|
2024-12-03 17:21:08 -08:00
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 17:20:30 -08:00
|
|
|
CodeComment inline_cmt = NullCode;
|
2024-12-03 12:19:39 -08:00
|
|
|
if ( function && function->Type == CT_Function_Fwd )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
Token stmt_end = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2024-04-17 14:40:32 -07:00
|
|
|
// friend <Type>;
|
|
|
|
// friend <ReturnType> <Name> ( <Parameters> );
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
|
2024-04-17 14:40:32 -07:00
|
|
|
inline_cmt = parse_comment();
|
2023-11-22 11:23:21 -08:00
|
|
|
// friend <Type>; <InlineCmt>
|
|
|
|
// friend <ReturnType> <Name> ( <Parameters> ); <InlineCmt>
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
CodeFriend result = ( CodeFriend )make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Friend;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( function )
|
|
|
|
result->Declaration = function;
|
2024-12-03 17:21:08 -08:00
|
|
|
else if ( op )
|
|
|
|
result->Declaration = op;
|
2023-11-20 12:09:01 -08:00
|
|
|
else
|
|
|
|
result->Declaration = type;
|
|
|
|
|
|
|
|
if ( inline_cmt )
|
|
|
|
result->InlineCmt = inline_cmt;
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeFn parse_function()
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
Specifier specs_found[16] { Spec_NumSpecifiers };
|
2023-11-20 12:09:01 -08:00
|
|
|
s32 NumSpecifiers = 0;
|
|
|
|
|
|
|
|
CodeAttributes attributes = { nullptr };
|
|
|
|
CodeSpecifiers specifiers = { nullptr };
|
2024-12-01 02:30:37 -08:00
|
|
|
ModuleFlag mflags = ModuleFlag_None;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check(Tok_Module_Export) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-01 02:30:37 -08:00
|
|
|
mflags = ModuleFlag_Export;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Module_Export );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
attributes = parse_attributes();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> <Attributes>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
while ( left && is_specifier(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
Specifier spec = strc_to_specifier( to_str(currtok) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
switch ( spec )
|
|
|
|
{
|
2024-12-03 10:14:14 -08:00
|
|
|
case Spec_Const:
|
|
|
|
case Spec_Consteval:
|
|
|
|
case Spec_Constexpr:
|
|
|
|
case Spec_External_Linkage:
|
|
|
|
case Spec_ForceInline:
|
|
|
|
case Spec_Inline:
|
|
|
|
case Spec_NeverInline:
|
|
|
|
case Spec_Static:
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2024-12-06 02:29:17 -08:00
|
|
|
log_failure( "Invalid specifier %s for functon\n%s", spec_to_str(spec), to_string(Context) );
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
if ( spec == Spec_Const )
|
2023-11-20 12:09:01 -08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
specs_found[NumSpecifiers] = spec;
|
|
|
|
NumSpecifiers++;
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( NumSpecifiers )
|
|
|
|
{
|
|
|
|
specifiers = def_specifiers( NumSpecifiers, specs_found );
|
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> <Attributes> <Specifiers>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
CodeTypename ret_type = parse_type();
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( ret_type == Code_Invalid )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> <Attributes> <Specifiers> <ReturnType>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Token name = parse_identifier();
|
|
|
|
Context.Scope->Name = name;
|
2024-12-02 19:25:39 -08:00
|
|
|
if ( ! is_valid(name) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> <Attributes> <Specifiers> <ReturnType> <Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeFn result = parse_function_after_name( mflags, attributes, specifiers, ret_type, name );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> <Attributes> <Specifiers> <ReturnType> <Name> ...
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeNS parse_namespace()
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Decl_Namespace );
|
2023-11-22 11:23:21 -08:00
|
|
|
// namespace
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Token name = parse_identifier();
|
|
|
|
Context.Scope->Name = name;
|
2023-11-22 11:23:21 -08:00
|
|
|
// namespace <Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
CodeBody body = parse_global_nspace( CT_Namespace_Body );
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( body == Code_Invalid )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// namespace <Name> { <Body> }
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeNS
|
|
|
|
result = (CodeNS) make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Namespace;
|
2024-12-02 19:25:39 -08:00
|
|
|
result->Name = get_cached_string( to_str(name) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
result->Body = body;
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeOperator parse_operator()
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
|
|
|
CodeAttributes attributes = { nullptr };
|
|
|
|
CodeSpecifiers specifiers = { nullptr };
|
2024-12-01 02:30:37 -08:00
|
|
|
ModuleFlag mflags = ModuleFlag_None;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
Specifier specs_found[16] { Spec_NumSpecifiers };
|
2023-11-20 12:09:01 -08:00
|
|
|
s32 NumSpecifiers = 0;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check(Tok_Module_Export) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-01 02:30:37 -08:00
|
|
|
mflags = ModuleFlag_Export;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Module_Export );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
attributes = parse_attributes();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> <Attributes>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
while ( left && is_specifier(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
Specifier spec = strc_to_specifier( to_str(currtok) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
switch ( spec )
|
|
|
|
{
|
2024-12-03 10:14:14 -08:00
|
|
|
case Spec_Const:
|
|
|
|
case Spec_Constexpr:
|
|
|
|
case Spec_ForceInline:
|
|
|
|
case Spec_Inline:
|
|
|
|
case Spec_NeverInline:
|
|
|
|
case Spec_Static:
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2024-12-06 02:29:17 -08:00
|
|
|
log_failure( "Invalid specifier " "%s" " for operator\n%s", spec_to_str(spec), to_string(Context) );
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
if ( spec == Spec_Const )
|
2023-11-20 12:09:01 -08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
specs_found[NumSpecifiers] = spec;
|
|
|
|
NumSpecifiers++;
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( NumSpecifiers )
|
|
|
|
{
|
|
|
|
specifiers = def_specifiers( NumSpecifiers, specs_found );
|
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> <Attributes> <Specifiers>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Parse Return Type
|
2024-12-03 12:19:39 -08:00
|
|
|
CodeTypename ret_type = parse_type();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> <Attributes> <Specifiers> <ReturnType>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeOperator result = parse_operator_after_ret_type( mflags, attributes, specifiers, ret_type );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> <Attributes> <Specifiers> <ReturnType> ...
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeOpCast parse_operator_cast( CodeSpecifiers specifiers )
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
|
|
|
// Operator's namespace if not within same class.
|
|
|
|
Token name = NullToken;
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Identifier ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
name = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && currtok.Type == Tok_Identifier )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Identifier );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Specifiers> <Qualifier>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Access_StaticSymbol )
|
|
|
|
eat( Tok_Access_StaticSymbol );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Specifiers> <Qualifier> ::
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Specifiers> <Qualifier> :: ...
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
name.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)name.Text;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Decl_Operator );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Specifiers> <Qualifier> :: ... operator
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Code type = parse_type();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Specifiers> <Qualifier> :: ... operator <UnderlyingType>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 15:47:12 -08:00
|
|
|
Context.Scope->Name = { type->Name.Ptr, type->Name.Len };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_Start );
|
|
|
|
eat( Tok_Capture_End );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Specifiers> <Qualifier> :: ... operator <UnderlyingType>()
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-22 11:23:21 -08:00
|
|
|
// TODO(Ed) : operator cast can have const, volatile, l-value, r-value noexecept qualifying specifiers.
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check(Tok_Spec_Const))
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
if ( specifiers.ast == nullptr )
|
2024-12-03 10:14:14 -08:00
|
|
|
specifiers = def_specifier( Spec_Const );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
else
|
2024-12-06 21:21:09 -08:00
|
|
|
specifiers_append(specifiers, Spec_Const );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Spec_Const );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Specifiers> <Qualifier> :: ... operator <UnderlyingType>() <const>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 17:20:30 -08:00
|
|
|
Code body = NullCode;
|
|
|
|
CodeComment inline_cmt = NullCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_BraceCurly_Open) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceCurly_Open );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Specifiers> <Qualifier> :: ... operator <UnderlyingType>() <const> {
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Token body_str = currtok;
|
|
|
|
|
|
|
|
s32 level = 0;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && ( currtok.Type != Tok_BraceCurly_Close || level > 0 ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_BraceCurly_Open )
|
2023-11-20 12:09:01 -08:00
|
|
|
level++;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( currtok.Type == Tok_BraceCurly_Close )
|
2023-11-20 12:09:01 -08:00
|
|
|
level--;
|
|
|
|
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
body_str.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)body_str.Text;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_BraceCurly_Close );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Specifiers> <Qualifier> :: ... operator <UnderlyingType>() <const> { <Body> }
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
body = untyped_str( to_str(body_str) );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Token stmt_end = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Specifiers> <Qualifier> :: ... operator <UnderlyingType>() <const>;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
|
2023-11-20 12:09:01 -08:00
|
|
|
inline_cmt = parse_comment();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Specifiers> <Qualifier> :: ... operator <UnderlyingType>() <const>; <InlineCmt>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
CodeOpCast result = (CodeOpCast) make_code();
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
if ( is_valid(name) )
|
|
|
|
result->Name = get_cached_string( to_str(name) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if (body)
|
|
|
|
{
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Operator_Cast;
|
2023-11-20 12:09:01 -08:00
|
|
|
result->Body = body;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Operator_Cast_Fwd;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( specifiers )
|
|
|
|
result->Specs = specifiers;
|
|
|
|
|
|
|
|
result->ValueType = type;
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal inline
|
|
|
|
CodeStruct parse_struct( bool inplace_def )
|
|
|
|
{
|
|
|
|
push_scope();
|
2024-12-03 06:50:30 -08:00
|
|
|
CodeStruct result = (CodeStruct) parse_class_struct( Tok_Decl_Struct, inplace_def );
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeTemplate parse_template()
|
|
|
|
{
|
2024-04-17 14:40:32 -07:00
|
|
|
#define UseTemplateCapture true
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
push_scope();
|
|
|
|
|
2024-12-01 02:30:37 -08:00
|
|
|
ModuleFlag mflags = ModuleFlag_None;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Module_Export ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-01 02:30:37 -08:00
|
|
|
mflags = ModuleFlag_Export;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Module_Export );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> template
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Decl_Template );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> template
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Code params = parse_params( UseTemplateCapture );
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( params == Code_Invalid )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> template< <Parameters> >
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Code definition = { nullptr };
|
|
|
|
|
|
|
|
while ( left )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Decl_Class ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
definition = parse_class();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> template< <Parameters> > class ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Decl_Struct ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
definition = parse_struct();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> template< <Parameters> > struct ...
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Decl_Union ) )
|
2023-11-22 11:23:21 -08:00
|
|
|
{
|
|
|
|
definition = parse_union();
|
|
|
|
// <export> template< <Parameters> > union ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Decl_Using ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
definition = parse_using();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> template< <Parameters> > using ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Its either a function or a variable
|
2024-12-03 06:50:30 -08:00
|
|
|
Token name = { nullptr, 0, Tok_Invalid };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeAttributes attributes = { nullptr };
|
2024-04-17 14:40:32 -07:00
|
|
|
CodeSpecifiers specifiers = { nullptr };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
bool expects_function = false;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
Specifier specs_found[ 16 ] { Spec_NumSpecifiers };
|
2023-11-20 12:09:01 -08:00
|
|
|
s32 NumSpecifiers = 0;
|
|
|
|
|
|
|
|
attributes = parse_attributes();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> template< <Parameters> > <Attributes>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// Specifiers Parsing
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 19:25:39 -08:00
|
|
|
while ( left && is_specifier(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
Specifier spec = strc_to_specifier( to_str(currtok) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
switch ( spec )
|
|
|
|
{
|
2024-12-03 10:14:14 -08:00
|
|
|
case Spec_Const :
|
|
|
|
case Spec_Constexpr :
|
|
|
|
case Spec_Constinit :
|
|
|
|
case Spec_External_Linkage :
|
|
|
|
case Spec_Global :
|
|
|
|
case Spec_Inline :
|
|
|
|
case Spec_ForceInline :
|
|
|
|
case Spec_Local_Persist :
|
|
|
|
case Spec_Mutable :
|
|
|
|
case Spec_Static :
|
|
|
|
case Spec_Thread_Local :
|
|
|
|
case Spec_Volatile :
|
2024-04-17 14:40:32 -07:00
|
|
|
break;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
case Spec_Consteval :
|
2024-04-17 14:40:32 -07:00
|
|
|
expects_function = true;
|
|
|
|
break;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
default :
|
2024-12-06 02:29:17 -08:00
|
|
|
log_failure( "Invalid specifier %s for variable or function\n%s", spec_to_str( spec ), to_string(Context) );
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// Ignore const it will be handled by the type
|
2024-12-03 10:14:14 -08:00
|
|
|
if ( spec == Spec_Const )
|
2024-04-17 14:40:32 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
specs_found[ NumSpecifiers ] = spec;
|
|
|
|
NumSpecifiers++;
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( NumSpecifiers )
|
|
|
|
{
|
|
|
|
specifiers = def_specifiers( NumSpecifiers, specs_found );
|
|
|
|
}
|
|
|
|
// <export> template< <Parameters> > <Attributes> <Specifiers>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
|
|
|
|
bool has_context = Context.Scope && Context.Scope->Prev;
|
|
|
|
bool is_in_global_nspace = has_context && str_compare( Context.Scope->Prev->ProcName, "parse_global_nspace" ) == 0;
|
|
|
|
|
|
|
|
// Possible constructor implemented at global file scope.
|
|
|
|
if (is_in_global_nspace)
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-04-17 14:40:32 -07:00
|
|
|
Code constructor_destructor = parse_global_nspace_constructor_destructor( specifiers );
|
|
|
|
if ( constructor_destructor )
|
|
|
|
{
|
|
|
|
definition = constructor_destructor;
|
|
|
|
// <Attributes> <Specifiers> <Name> :: <Name> <Type> () { ... }
|
|
|
|
break;
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// Possible user Defined operator casts
|
|
|
|
if (is_in_global_nspace)
|
|
|
|
{
|
|
|
|
bool found_operator_cast_outside_class_implmentation = false;
|
|
|
|
s32 idx = Context.Tokens.Idx;
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
for ( ; idx < array_num(Context.Tokens.Arr); idx++ )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-02 19:25:39 -08:00
|
|
|
Token tok = Context.Tokens.Arr[ idx ];
|
2024-04-17 14:40:32 -07:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok.Type == Tok_Identifier )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
idx++;
|
2024-12-02 19:25:39 -08:00
|
|
|
tok = Context.Tokens.Arr[ idx ];
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok.Type == Tok_Access_StaticSymbol )
|
2024-04-17 14:40:32 -07:00
|
|
|
continue;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok.Type == Tok_Decl_Operator )
|
2024-04-17 14:40:32 -07:00
|
|
|
found_operator_cast_outside_class_implmentation = true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( found_operator_cast_outside_class_implmentation )
|
|
|
|
{
|
|
|
|
definition = parse_operator_cast( specifiers );
|
|
|
|
// <Attributes> <Specifiers> <Name> :: operator <Type> () { ... }
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
definition = parse_operator_function_or_variable( expects_function, attributes, specifiers );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <export> template< <Parameters> > <Attributes> <Specifiers> ...
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
CodeTemplate result = ( CodeTemplate )make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Template;
|
2023-11-20 12:09:01 -08:00
|
|
|
result->Params = params;
|
|
|
|
result->Declaration = definition;
|
|
|
|
result->ModuleFlags = mflags;
|
2024-12-01 09:48:58 -08:00
|
|
|
// result->Name = definition->Name;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
2024-04-17 14:40:32 -07:00
|
|
|
#undef UseTemplateCapture
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
This is a mess, but it works
|
|
|
|
Parsing typename is arguably one of the worst aspects of C/C++.
|
|
|
|
This is an effort to parse it without a full blown or half-blown compliant parser.
|
|
|
|
|
|
|
|
Recursive function typenames are not supported, if they are used expect it to serailize just fine, but validation with AST::is_equal
|
|
|
|
will not be possible if two ASTs share the same definiton but the formatting is slightly different:
|
|
|
|
AST_1->Name: (* A ( int (*) (short a,unsigned b,long c) ) )
|
|
|
|
AST_2->Name: (* A ( int(*)(short a, unsigned b, long c) ) )
|
|
|
|
|
|
|
|
The excess whitespace cannot be stripped however, because there is no semantic awareness within the first capture group.
|
|
|
|
*/
|
2024-04-17 15:29:30 -07:00
|
|
|
internal
|
2024-12-03 12:19:39 -08:00
|
|
|
CodeTypename parse_type( bool from_template, bool* typedef_is_function )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
|
|
|
Token context_tok = prevtok;
|
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
Specifier specs_found[ 16 ] { Spec_NumSpecifiers };
|
2023-11-20 12:09:01 -08:00
|
|
|
s32 NumSpecifiers = 0;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
Token name = { nullptr, 0, Tok_Invalid };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Attributes are assumed to be before the type signature
|
|
|
|
CodeAttributes attributes = parse_attributes();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Prefix specifiers
|
2024-12-02 19:25:39 -08:00
|
|
|
while ( left && is_specifier(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
Specifier spec = strc_to_specifier( to_str(currtok) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
if ( spec != Spec_Const )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, invalid specifier used in type definition: %s\n%s", currtok.Text, to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
specs_found[ NumSpecifiers ] = spec;
|
2023-11-20 12:09:01 -08:00
|
|
|
NumSpecifiers++;
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( left == 0 )
|
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, unexpected end of type definition\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( from_template && currtok.Type == Tok_Decl_Class )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-04-17 14:40:32 -07:00
|
|
|
// If a value's type is being parsed from a template, class can be used instead of typename.
|
2023-11-20 12:09:01 -08:00
|
|
|
name = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat(Tok_Decl_Class);
|
2024-04-17 14:40:32 -07:00
|
|
|
// <class>
|
|
|
|
}
|
|
|
|
|
|
|
|
// All kinds of nonsense can makeup a type signature, first we check for a in-place definition of a class, enum, struct, or union
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( currtok.Type == Tok_Decl_Class || currtok.Type == Tok_Decl_Enum || currtok.Type == Tok_Decl_Struct
|
|
|
|
|| currtok.Type == Tok_Decl_Union )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2023-11-20 12:09:01 -08:00
|
|
|
eat( currtok.Type );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <class, enum, struct, union>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-10-24 22:04:17 -07:00
|
|
|
name = parse_identifier();
|
2024-04-17 14:40:32 -07:00
|
|
|
|
|
|
|
// name.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )name.Text;
|
2024-12-03 06:50:30 -08:00
|
|
|
// eat( Tok_Identifier );
|
2023-11-20 12:09:01 -08:00
|
|
|
Context.Scope->Name = name;
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <class, enum, struct, union> <Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
// Decltype draft implementaiton
|
2023-11-20 12:09:01 -08:00
|
|
|
#if 0
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( currtok.Type == Tok_DeclType )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
// Will have a capture and its own parsing rules, were going to just shove everything in a string (for now).
|
|
|
|
name = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_DeclType );
|
2024-04-17 14:40:32 -07:00
|
|
|
// <Attributes> <Specifiers> decltype
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_Start );
|
|
|
|
while ( left && currtok.Type != Tok_Capture_End )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Capture_Start )
|
2024-04-17 14:40:32 -07:00
|
|
|
level++;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Capture_End )
|
2024-04-17 14:40:32 -07:00
|
|
|
level--;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
eat( currtok.Type );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_End );
|
2024-04-17 14:40:32 -07:00
|
|
|
|
|
|
|
name.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)name.Text;
|
|
|
|
Context.Scope->Name = name;
|
|
|
|
// <Attributes> <Specifiers> decltype( <Expression > )
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Check if native type keywords are used, eat them for the signature.
|
2023-11-21 18:27:33 -08:00
|
|
|
// <attributes> <specifiers> <native types ...> ...
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( currtok.Type >= Tok_Type_Unsigned && currtok.Type <= Tok_Type_MS_W64 )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
// TODO(Ed) : Review this... Its necessary for parsing however the algo's path to this is lost...
|
|
|
|
name = currtok;
|
|
|
|
eat( currtok.Type );
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && currtok.Type >= Tok_Type_Unsigned && currtok.Type <= Tok_Type_MS_W64 )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
name.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )name.Text;
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <Compound type expression>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( currtok.Type == Tok_Type_Typename )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
name = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat(Tok_Type_Typename);
|
2024-04-17 14:40:32 -07:00
|
|
|
// <typename>
|
2024-10-24 23:59:56 -07:00
|
|
|
|
|
|
|
if ( ! from_template )
|
|
|
|
{
|
|
|
|
name = parse_identifier();
|
|
|
|
Context.Scope->Name = name;
|
2024-12-02 19:25:39 -08:00
|
|
|
if ( ! is_valid(name) )
|
2024-10-24 23:59:56 -07:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, failed to type signature\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2024-10-24 23:59:56 -07:00
|
|
|
}
|
|
|
|
}
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// The usual Identifier type signature that may have namespace qualifiers
|
|
|
|
else
|
|
|
|
{
|
2024-04-17 14:40:32 -07:00
|
|
|
name = parse_identifier();
|
2023-11-20 12:09:01 -08:00
|
|
|
Context.Scope->Name = name;
|
2024-12-02 19:25:39 -08:00
|
|
|
if ( ! is_valid(name) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, failed to type signature\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <Qualifier ::> <Identifier>
|
|
|
|
// <Attributes> <Specifiers> <Identifier>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Suffix specifiers for typename.
|
2024-12-02 19:25:39 -08:00
|
|
|
while ( left && is_specifier(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
Specifier spec = strc_to_specifier( to_str(currtok) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
if ( spec != Spec_Const && spec != Spec_Ptr && spec != Spec_Ref && spec != Spec_RValue )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, invalid specifier used in type definition: %s\n%s", currtok.Text, to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
specs_found[ NumSpecifiers ] = spec;
|
2023-11-20 12:09:01 -08:00
|
|
|
NumSpecifiers++;
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef GEN_USE_NEW_TYPENAME_PARSING
|
|
|
|
if ( NumSpecifiers )
|
|
|
|
{
|
2024-04-17 14:40:32 -07:00
|
|
|
specifiers = def_specifiers( NumSpecifiers, specs_found );
|
2023-11-20 12:09:01 -08:00
|
|
|
NumSpecifiers = 0;
|
|
|
|
}
|
|
|
|
#endif
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <Specifiers> <Identifier> <Specifiers>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// For function type signatures
|
2024-12-03 12:19:39 -08:00
|
|
|
CodeTypename return_type = NullCode;
|
|
|
|
CodeParam params = NullCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
#ifdef GEN_USE_NEW_TYPENAME_PARSING
|
2024-12-02 17:20:30 -08:00
|
|
|
CodeParam params_nested = NullCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
#endif
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
bool is_function_typename = false;
|
|
|
|
Token* last_capture = nullptr;
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
Token* scanner = Context.Tokens.Arr + Context.Tokens.Idx;
|
|
|
|
|
|
|
|
// An identifier being within a typename's signature only occurs if were parsing a typename for a typedef.
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( typedef_is_function && scanner->Type == Tok_Identifier )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
is_function_typename = true;
|
2024-04-17 14:40:32 -07:00
|
|
|
++scanner;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
is_function_typename = scanner->Type == Tok_Capture_Start;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Token* first_capture = scanner;
|
|
|
|
if ( is_function_typename )
|
|
|
|
{
|
|
|
|
// Go to the end of the signature
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( scanner->Type != Tok_Statement_End && scanner->Type != Tok_BraceCurly_Open )
|
2024-04-17 14:40:32 -07:00
|
|
|
++scanner;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Go back to the first capture start found
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( scanner->Type != Tok_Capture_Start )
|
2024-04-17 14:40:32 -07:00
|
|
|
--scanner;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
last_capture = scanner;
|
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
bool has_context = Context.Scope && Context.Scope->Prev;
|
2023-11-20 12:09:01 -08:00
|
|
|
bool is_for_opcast = has_context && str_compare( Context.Scope->Prev->ProcName, "parse_operator_cast" ) == 0;
|
|
|
|
if ( is_for_opcast && is_function_typename && last_capture )
|
|
|
|
{
|
|
|
|
// If we're parsing for an operator cast, having one capture start is not enough
|
|
|
|
// we need to make sure that the capture is not for the cast definition.
|
|
|
|
is_function_typename = false;
|
|
|
|
|
|
|
|
if ( last_capture == first_capture )
|
|
|
|
{
|
|
|
|
// The capture start in question is the first capture start, this is not a function typename.
|
|
|
|
is_function_typename = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( is_function_typename )
|
|
|
|
{
|
|
|
|
// We're dealing with a function typename.
|
|
|
|
// By this point, decltype should have been taken care of for return type, along with any all its specifiers
|
|
|
|
|
|
|
|
// The previous information with exception to attributes will be considered the return type.
|
2024-12-03 12:19:39 -08:00
|
|
|
return_type = ( CodeTypename )make_code();
|
|
|
|
return_type->Type = CT_Typename;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// String
|
|
|
|
// name_stripped = String::make( GlobalAllocator, name );
|
|
|
|
// name_stripped.strip_space();
|
2024-12-02 19:25:39 -08:00
|
|
|
return_type->Name = get_cached_string( to_str(name) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
#ifdef GEN_USE_NEW_TYPENAME_PARSING
|
2023-11-20 12:09:01 -08:00
|
|
|
if ( specifiers )
|
|
|
|
{
|
|
|
|
return_type->Specs = specifiers;
|
|
|
|
specifiers = nullptr;
|
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
#else
|
2023-11-20 12:09:01 -08:00
|
|
|
if ( NumSpecifiers )
|
2024-12-03 10:14:14 -08:00
|
|
|
return_type->Specs = def_specifiers( NumSpecifiers, ( Specifier* )specs_found );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Reset specifiers, the function itself will have its own suffix specifiers possibly.
|
|
|
|
NumSpecifiers = 0;
|
2024-04-17 14:40:32 -07:00
|
|
|
#endif
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <ReturnType>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
name = { nullptr, 0, Tok_Invalid };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// The next token can either be a capture for the identifier or it could be the identifier exposed.
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ! check( Tok_Capture_Start ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
// Started with an identifier immeidately, which means its of the format: <ReturnType> <identifier> <capture>;
|
|
|
|
name = parse_identifier();
|
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <ReturnType> <Identifier>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
// If the next token is a capture start and is not the last capture, then we're dealing with function typename whoose identifier is within the
|
|
|
|
// capture.
|
2023-11-20 12:09:01 -08:00
|
|
|
else if ( ( Context.Tokens.Arr + Context.Tokens.Idx ) != last_capture )
|
|
|
|
{
|
|
|
|
// WIP : Possible alternative without much pain...
|
|
|
|
// If this were to be parsed properly...
|
|
|
|
// Eat Capture Start
|
|
|
|
// Deal with possible binding specifiers (*, &, &&) and modifiers on those bindings (const, volatile)
|
|
|
|
// Parse specifiers for the typename with an optional identifier,
|
2024-04-17 14:40:32 -07:00
|
|
|
// we can shove these specific specifiers into a specs, and then leave the suffix ones for a separate member of the AST.
|
2023-11-20 12:09:01 -08:00
|
|
|
// Parse immeidate capture which would be with parse_params()
|
|
|
|
// Eat Capture End
|
2024-04-17 14:40:32 -07:00
|
|
|
#ifdef GEN_USE_NEW_TYPENAME_PARSING
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_Start );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <ReturnType> (
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Binding specifiers
|
|
|
|
while ( left && currtok.is_specifier() )
|
|
|
|
{
|
2024-12-03 10:14:14 -08:00
|
|
|
Specifier spec = to_type( currtok );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
if ( spec != Spec_Ptr && spec != Spec_Ref && spec != Spec_RValue )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, invalid specifier used in type definition: %s\n%s", currtok.Text, to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
specs_found[ NumSpecifiers ] = spec;
|
2023-11-20 12:09:01 -08:00
|
|
|
NumSpecifiers++;
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( NumSpecifiers )
|
|
|
|
{
|
|
|
|
specifiers = def_specifiers( NumSpecifiers, specs_found );
|
|
|
|
}
|
|
|
|
NumSpecifiers = 0;
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <ReturnType> ( <Specifiers>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Identifier ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
name = parse_identifier();
|
2024-04-17 14:40:32 -07:00
|
|
|
// <Attributes> <ReturnType> ( <Specifiers> <Identifier>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Immeidate parameters
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Capture_Start ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
params_nested = parse_params();
|
2024-04-17 14:40:32 -07:00
|
|
|
// <Attributes> <ReturnType> ( <Specifiers> <Identifier> ( <Parameters> )
|
2023-11-22 11:23:21 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_End );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <ReturnType> ( <Specifiers> <Identifier> ( <Parameters> ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
#else
|
2023-11-20 12:09:01 -08:00
|
|
|
// Starting immediatley with a capture, most likely declaring a typename for a member function pointer.
|
|
|
|
// Everything within this capture will just be shoved into the name field including the capture tokens themselves.
|
|
|
|
name = currtok;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_Start );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <ReturnType> (
|
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
s32 level = 0;
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( left && ( currtok.Type != Tok_Capture_End || level > 0 ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Capture_Start )
|
2023-11-20 12:09:01 -08:00
|
|
|
level++;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Capture_End )
|
2023-11-20 12:09:01 -08:00
|
|
|
level--;
|
|
|
|
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Capture_End );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <ReturnType> ( <Expression> )
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
name.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )name.Text;
|
|
|
|
#endif
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Were now dealing with the parameters of the function
|
|
|
|
params = parse_params();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <ReturnType> <All Kinds of nonsense> ( <Parameters> )
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Look for suffix specifiers for the function
|
2024-12-02 19:25:39 -08:00
|
|
|
while ( left && is_specifier(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
Specifier spec = strc_to_specifier( to_str(currtok) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
if ( spec != Spec_Const
|
2024-04-17 14:40:32 -07:00
|
|
|
// TODO : Add support for NoExcept, l-value, volatile, l-value, etc
|
2024-12-03 10:14:14 -08:00
|
|
|
// && spec != Spec_NoExcept
|
|
|
|
&& spec != Spec_RValue )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, invalid specifier used in type definition: %s\n%s", currtok.Text, to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
specs_found[ NumSpecifiers ] = spec;
|
2023-11-20 12:09:01 -08:00
|
|
|
NumSpecifiers++;
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
2024-04-17 14:40:32 -07:00
|
|
|
#ifdef GEN_USE_NEW_TYPENAME_PARSING
|
2023-11-20 12:09:01 -08:00
|
|
|
if ( NumSpecifiers )
|
|
|
|
{
|
|
|
|
func_suffix_specs = def_specifiers( NumSpecifiers, specs_found );
|
|
|
|
NumSpecifiers = 0;
|
|
|
|
}
|
2024-04-17 14:40:32 -07:00
|
|
|
#endif
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <ReturnType> <All Kinds of nonsense> ( <Parameters> ) <Specifiers>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <All Kinds of nonsense>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
bool is_param_pack = false;
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Varadic_Argument ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
is_param_pack = true;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Varadic_Argument );
|
2023-11-22 11:23:21 -08:00
|
|
|
// <Attributes> <All kinds of nonsense> ...
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
CodeTypename result = ( CodeTypename )make_code();
|
2024-12-06 02:29:17 -08:00
|
|
|
result->Type = CT_Typename;
|
2023-11-20 12:09:01 -08:00
|
|
|
// result->Token = Context.Scope->Start;
|
|
|
|
|
|
|
|
// Need to wait until were using the new parsing method to do this.
|
2024-12-02 19:25:39 -08:00
|
|
|
String name_stripped = strip_formatting( to_str(name), strip_formatting_dont_preserve_newlines );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// name_stripped.strip_space();
|
|
|
|
|
|
|
|
#ifdef GEN_USE_NEW_TYPENAME_PARSING
|
|
|
|
if ( params_nested )
|
|
|
|
{
|
|
|
|
name_stripped.append( params_nested->to_string() );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-12-04 08:01:53 -08:00
|
|
|
result->Name = get_cached_string( string_to_strc(name_stripped) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( attributes )
|
|
|
|
result->Attributes = attributes;
|
|
|
|
|
|
|
|
#ifdef GEN_USE_NEW_TYPENAME_PARSING
|
|
|
|
if ( specifiers )
|
|
|
|
{
|
|
|
|
result->Specs = specifiers;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( func_suffix_specs )
|
|
|
|
{
|
|
|
|
result->FuncSuffixSpecs = func_suffix_specs;
|
|
|
|
}
|
|
|
|
#else
|
2024-04-17 14:40:32 -07:00
|
|
|
if ( NumSpecifiers )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 10:14:14 -08:00
|
|
|
Code specifiers = def_specifiers( NumSpecifiers, ( Specifier* )specs_found );
|
2024-04-17 14:40:32 -07:00
|
|
|
result->Specs = specifiers;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ( is_param_pack )
|
|
|
|
result->IsParamPack = true;
|
|
|
|
|
|
|
|
// These following are only populated if its a function typename
|
|
|
|
if ( return_type )
|
|
|
|
{
|
|
|
|
result->ReturnType = return_type;
|
|
|
|
|
|
|
|
if ( typedef_is_function )
|
|
|
|
*typedef_is_function = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( params )
|
|
|
|
result->Params = params;
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeTypedef parse_typedef()
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
|
|
|
bool is_function = false;
|
2024-12-03 06:50:30 -08:00
|
|
|
Token name = { nullptr, 0, Tok_Invalid };
|
2023-11-20 12:09:01 -08:00
|
|
|
Code array_expr = { nullptr };
|
|
|
|
Code type = { nullptr };
|
|
|
|
|
2024-12-01 02:30:37 -08:00
|
|
|
ModuleFlag mflags = ModuleFlag_None;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check(Tok_Module_Export) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-01 02:30:37 -08:00
|
|
|
mflags = ModuleFlag_Export;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Module_Export );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Decl_Typedef );
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> typedef
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
constexpr bool from_typedef = true;
|
|
|
|
|
|
|
|
#if GEN_PARSER_DISABLE_MACRO_TYPEDEF
|
|
|
|
if ( false )
|
|
|
|
#else
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Preprocess_Macro ))
|
2023-11-20 12:09:01 -08:00
|
|
|
#endif
|
|
|
|
{
|
|
|
|
type = t_empty;
|
|
|
|
name = currtok;
|
|
|
|
Context.Scope->Name = name;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Preprocess_Macro );
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFalgs> typedef <Preprocessed_Macro>
|
2024-12-05 00:41:08 -08:00
|
|
|
|
|
|
|
if ( currtok.Type == Tok_Identifier )
|
|
|
|
{
|
|
|
|
type = untyped_str({ name.Length, name.Text });
|
|
|
|
name = currtok;
|
|
|
|
eat(Tok_Identifier);
|
|
|
|
}
|
2024-12-06 21:21:09 -08:00
|
|
|
// <ModuleFalgs> typedef <Preprocessed_Macro> <Identifier>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bool is_complicated =
|
2024-12-03 06:50:30 -08:00
|
|
|
currtok.Type == Tok_Decl_Enum
|
|
|
|
|| currtok.Type == Tok_Decl_Class
|
|
|
|
|| currtok.Type == Tok_Decl_Struct
|
|
|
|
|| currtok.Type == Tok_Decl_Union;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-01 15:50:37 -08:00
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
// This code is highly correlated with parse_complicated_definition
|
2023-11-20 12:09:01 -08:00
|
|
|
if ( is_complicated )
|
|
|
|
{
|
|
|
|
TokArray tokens = Context.Tokens;
|
2024-12-01 15:50:37 -08:00
|
|
|
TokType which = currtok.Type;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
s32 idx = tokens.Idx;
|
|
|
|
s32 level = 0;
|
2024-12-04 08:01:53 -08:00
|
|
|
for ( ; idx < array_num(tokens.Arr); idx ++ )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tokens.Arr[idx].Type == Tok_BraceCurly_Open )
|
2023-11-20 12:09:01 -08:00
|
|
|
level++;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tokens.Arr[idx].Type == Tok_BraceCurly_Close )
|
2023-11-20 12:09:01 -08:00
|
|
|
level--;
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( level == 0 && tokens.Arr[idx].Type == Tok_Statement_End )
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-12-01 15:50:37 -08:00
|
|
|
Token pre_foward_tok = currtok;
|
|
|
|
if ( (idx - 3 ) == tokens.Idx )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-01 15:50:37 -08:00
|
|
|
log_fmt("Identified forward typedef\n");
|
2023-11-20 12:09:01 -08:00
|
|
|
// Its a forward declaration only
|
2024-12-01 15:50:37 -08:00
|
|
|
type = parse_forward_or_definition( which, from_typedef );
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFalgs> typedef <UnderlyingType: Forward Decl>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-01 15:50:37 -08:00
|
|
|
else
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-01 15:50:37 -08:00
|
|
|
Token tok = tokens.Arr[ idx - 1 ];
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok.Type == Tok_Identifier )
|
2024-12-01 15:50:37 -08:00
|
|
|
{
|
|
|
|
log_fmt("Found id\n");
|
|
|
|
tok = tokens.Arr[ idx - 2 ];
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
bool is_indirection = tok.Type == Tok_Ampersand
|
|
|
|
|| tok.Type == Tok_Star;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-01 15:50:37 -08:00
|
|
|
bool ok_to_parse = false;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-01 15:50:37 -08:00
|
|
|
Token temp_3 = tokens.Arr[ idx - 3 ];
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( tok.Type == Tok_BraceCurly_Close )
|
2024-12-01 15:50:37 -08:00
|
|
|
{
|
|
|
|
// Its an inplace definition
|
|
|
|
// typedef <which> <type_identifier> { ... } <identifier>;
|
|
|
|
ok_to_parse = true;
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( tok.Type == Tok_Identifier && tokens.Arr[ idx - 3 ].Type == which )
|
2024-12-01 15:50:37 -08:00
|
|
|
{
|
|
|
|
// Its a variable with type ID using which namespace.
|
|
|
|
// typedef <which> <type_identifier> <identifier>;
|
|
|
|
ok_to_parse = true;
|
|
|
|
}
|
|
|
|
else if ( is_indirection )
|
|
|
|
{
|
|
|
|
// Its a indirection type with type ID using struct namespace.
|
|
|
|
// typedef <which> <type_identifier>* <identifier>;
|
|
|
|
ok_to_parse = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! ok_to_parse )
|
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Unsupported or bad member definition after struct declaration\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2024-12-01 15:50:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(Ed) : I'm not sure if I have to use parse_type here, I'd rather not as that would complicate parse_type.
|
|
|
|
// type = parse_type();
|
|
|
|
type = parse_forward_or_definition( which, from_typedef );
|
|
|
|
// <ModuleFalgs> typedef <UnderlyingType>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( tok.Type == Tok_BraceCurly_Close )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-01 15:50:37 -08:00
|
|
|
// Its a definition
|
|
|
|
// <which> { ... };
|
|
|
|
type = parse_forward_or_definition( currtok.Type, from_typedef );
|
|
|
|
// <ModuleFalgs> typedef <UnderlyingType>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( tok.Type == Tok_BraceSquare_Close)
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-01 15:50:37 -08:00
|
|
|
// Its an array definition
|
|
|
|
// <which> <type_identifier> <identifier> [ ... ];
|
|
|
|
type = parse_type();
|
|
|
|
// <ModuleFalgs> typedef <UnderlyingType>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-01 15:50:37 -08:00
|
|
|
else
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Unsupported or bad member definition after struct declaration\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
|
|
|
bool from_template = false;
|
|
|
|
type = parse_type( from_template, &is_function );
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFalgs> typedef <UnderlyingType>
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Identifier ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
name = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Identifier );
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFalgs> typedef <UnderlyingType> <Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
else if ( ! is_function )
|
|
|
|
{
|
2024-12-03 06:31:27 -08:00
|
|
|
log_failure( "Error, expected identifier for typedef\n%s", to_string(Context) );
|
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
array_expr = parse_array_decl();
|
|
|
|
// <UnderlyingType> + <ArrayExpr>
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Token stmt_end = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFalgs> typedef <UnderlyingType> <Name>;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 17:20:30 -08:00
|
|
|
CodeComment inline_cmt = NullCode;
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
|
2023-11-20 12:09:01 -08:00
|
|
|
inline_cmt = parse_comment();
|
2023-11-22 11:23:21 -08:00
|
|
|
// <ModuleFalgs> typedef <UnderlyingType> <Name> <ArrayExpr>; <InlineCmt>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeTypedef
|
|
|
|
result = (CodeTypedef) make_code();
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Typedef;
|
2023-11-20 12:09:01 -08:00
|
|
|
result->ModuleFlags = mflags;
|
|
|
|
|
|
|
|
if ( is_function )
|
|
|
|
{
|
|
|
|
result->Name = type->Name;
|
|
|
|
result->IsFunction = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-02 19:25:39 -08:00
|
|
|
result->Name = get_cached_string( to_str(name) );
|
2023-11-20 12:09:01 -08:00
|
|
|
result->IsFunction = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( type )
|
|
|
|
{
|
2024-12-02 17:20:30 -08:00
|
|
|
result->UnderlyingType = type;
|
|
|
|
result->UnderlyingType->Parent.ast = rcast(AST*, result.ast);
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
// Type needs to be aware of its parent so that it can be serialized properly.
|
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
if ( type->Type == CT_Typename && array_expr && array_expr->Type != CT_Invalid )
|
|
|
|
cast(CodeTypename, type)->ArrExpr = array_expr;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( inline_cmt )
|
|
|
|
result->InlineCmt = inline_cmt;
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal neverinline
|
|
|
|
CodeUnion parse_union( bool inplace_def )
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-12-01 02:30:37 -08:00
|
|
|
ModuleFlag mflags = ModuleFlag_None;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check(Tok_Module_Export) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-01 02:30:37 -08:00
|
|
|
mflags = ModuleFlag_Export;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Module_Export );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Decl_Union );
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> union
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeAttributes attributes = parse_attributes();
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> union <Attributes>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
StrC name = { 0, nullptr };
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check( Tok_Identifier ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 19:25:39 -08:00
|
|
|
name = to_str(currtok);
|
2023-11-20 12:09:01 -08:00
|
|
|
Context.Scope->Name = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Identifier );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> union <Attributes> <Name>
|
2024-12-06 02:29:17 -08:00
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
CodeBody body = { nullptr };
|
2024-12-06 02:29:17 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
if ( ! inplace_def || ! check(Tok_Identifier) )
|
|
|
|
{
|
|
|
|
eat( Tok_BraceCurly_Open );
|
|
|
|
// <ModuleFlags> union <Attributes> <Name> {
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
body = make_code();
|
|
|
|
body->Type = CT_Union_Body;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
while ( ! check_noskip( Tok_BraceCurly_Close ) )
|
|
|
|
{
|
|
|
|
if ( currtok_noskip.Type == Tok_Preprocess_Hash )
|
|
|
|
eat( Tok_Preprocess_Hash );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
Code member = { nullptr };
|
|
|
|
switch ( currtok_noskip.Type )
|
|
|
|
{
|
|
|
|
case Tok_NewLine:
|
|
|
|
member = fmt_newline;
|
|
|
|
eat( Tok_NewLine );
|
|
|
|
break;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
case Tok_Comment:
|
|
|
|
member = parse_comment();
|
|
|
|
break;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
// TODO(Ed) : Unions can have constructors and destructors
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
case Tok_Decl_Class:
|
|
|
|
member = parse_complicated_definition( Tok_Decl_Class );
|
|
|
|
break;
|
2023-11-22 11:23:21 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
case Tok_Decl_Enum:
|
|
|
|
member = parse_complicated_definition( Tok_Decl_Enum );
|
|
|
|
break;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
case Tok_Decl_Struct:
|
|
|
|
member = parse_complicated_definition( Tok_Decl_Struct );
|
|
|
|
break;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
case Tok_Decl_Union:
|
|
|
|
member = parse_complicated_definition( Tok_Decl_Union );
|
|
|
|
break;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
case Tok_Preprocess_Define:
|
|
|
|
member = parse_define();
|
|
|
|
break;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
case Tok_Preprocess_If:
|
|
|
|
case Tok_Preprocess_IfDef:
|
|
|
|
case Tok_Preprocess_IfNotDef:
|
|
|
|
case Tok_Preprocess_ElIf:
|
|
|
|
member = parse_preprocess_cond();
|
|
|
|
break;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
case Tok_Preprocess_Else:
|
|
|
|
member = preprocess_else;
|
|
|
|
eat( Tok_Preprocess_Else );
|
|
|
|
break;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
case Tok_Preprocess_EndIf:
|
|
|
|
member = preprocess_endif;
|
|
|
|
eat( Tok_Preprocess_EndIf );
|
|
|
|
break;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
case Tok_Preprocess_Macro:
|
|
|
|
member = parse_simple_preprocess( Tok_Preprocess_Macro );
|
|
|
|
break;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
case Tok_Preprocess_Pragma:
|
|
|
|
member = parse_pragma();
|
|
|
|
break;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
case Tok_Preprocess_Unsupported:
|
|
|
|
member = parse_simple_preprocess( Tok_Preprocess_Unsupported );
|
|
|
|
break;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
default:
|
|
|
|
member = parse_variable();
|
|
|
|
break;
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
if ( member )
|
2024-12-06 21:21:09 -08:00
|
|
|
body_append(body, member );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-05 21:33:53 -08:00
|
|
|
// <ModuleFlags> union <Attributes> <Name> { <Body>
|
2024-12-06 02:29:17 -08:00
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
eat( Tok_BraceCurly_Close );
|
|
|
|
// <ModuleFlags> union <Attributes> <Name> { <Body> }
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! inplace_def )
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> union <Attributes> <Name> { <Body> };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeUnion
|
|
|
|
result = (CodeUnion) make_code();
|
2024-12-05 21:33:53 -08:00
|
|
|
result->Type = body ? CT_Union : CT_Union_Fwd;
|
2023-11-20 12:09:01 -08:00
|
|
|
result->ModuleFlags = mflags;
|
|
|
|
|
|
|
|
if ( name )
|
|
|
|
result->Name = get_cached_string( name );
|
|
|
|
|
2024-12-05 21:33:53 -08:00
|
|
|
result->Body = body;
|
|
|
|
result->Attributes = attributes;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeUsing parse_using()
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
Specifier specs_found[16] { Spec_Invalid };
|
2023-11-20 12:09:01 -08:00
|
|
|
s32 NumSpecifiers = 0;
|
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
Token name = { nullptr, 0, Tok_Invalid };
|
|
|
|
Code array_expr = { nullptr };
|
|
|
|
CodeTypename type = { nullptr };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
bool is_namespace = false;
|
|
|
|
|
2024-12-01 02:30:37 -08:00
|
|
|
ModuleFlag mflags = ModuleFlag_None;
|
2023-11-20 12:09:01 -08:00
|
|
|
CodeAttributes attributes = { nullptr };
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check(Tok_Module_Export) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-01 02:30:37 -08:00
|
|
|
mflags = ModuleFlag_Export;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Module_Export );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Decl_Using );
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> using
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok.Type == Tok_Decl_Namespace )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
is_namespace = true;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Decl_Namespace );
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> using namespace
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
name = currtok;
|
|
|
|
Context.Scope->Name = name;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Identifier );
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> using <namespace> <Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
if ( ! is_namespace )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2023-11-21 18:27:33 -08:00
|
|
|
if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) )
|
|
|
|
{
|
|
|
|
attributes = parse_attributes();
|
|
|
|
// <ModuleFlags> using <Name> <Attributes>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Operator );
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> using <Name> <Attributes> =
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
type = parse_type();
|
|
|
|
// <ModuleFlags> using <Name> <Attributes> = <UnderlyingType>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2023-11-21 18:27:33 -08:00
|
|
|
array_expr = parse_array_decl();
|
|
|
|
// <UnderlyingType> + <ArrExpr>
|
|
|
|
}
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Token stmt_end = currtok;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Statement_End );
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> using <namespace> <Attributes> <Name> = <UnderlyingType>;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 17:20:30 -08:00
|
|
|
CodeComment inline_cmt = NullCode;
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
inline_cmt = parse_comment();
|
|
|
|
}
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> using <namespace> <Attributes> <Name> = <UnderlyingType>; <InlineCmt>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
CodeUsing
|
|
|
|
result = (CodeUsing) make_code();
|
2024-12-02 19:25:39 -08:00
|
|
|
result->Name = get_cached_string( to_str(name) );
|
2023-11-20 12:09:01 -08:00
|
|
|
result->ModuleFlags = mflags;
|
|
|
|
|
|
|
|
if ( is_namespace)
|
|
|
|
{
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Using_Namespace;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-03 12:19:39 -08:00
|
|
|
result->Type = CT_Using;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( type )
|
|
|
|
result->UnderlyingType = type;
|
|
|
|
|
|
|
|
if ( array_expr )
|
|
|
|
type->ArrExpr = array_expr;
|
|
|
|
|
|
|
|
if ( attributes )
|
|
|
|
result->Attributes = attributes;
|
|
|
|
|
|
|
|
if ( inline_cmt )
|
|
|
|
result->InlineCmt = inline_cmt;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal
|
|
|
|
CodeVar parse_variable()
|
|
|
|
{
|
|
|
|
push_scope();
|
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
Specifier specs_found[16] { Spec_NumSpecifiers };
|
2024-12-03 12:19:39 -08:00
|
|
|
s32 NumSpecifiers = 0;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-01 02:30:37 -08:00
|
|
|
ModuleFlag mflags = ModuleFlag_None;
|
2023-11-20 12:09:01 -08:00
|
|
|
CodeAttributes attributes = { nullptr };
|
|
|
|
CodeSpecifiers specifiers = { nullptr };
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( check(Tok_Module_Export) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-01 02:30:37 -08:00
|
|
|
mflags = ModuleFlag_Export;
|
2024-12-03 06:50:30 -08:00
|
|
|
eat( Tok_Module_Export );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
attributes = parse_attributes();
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> <Attributes>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
while ( left && is_specifier(currtok) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-06 02:29:17 -08:00
|
|
|
Specifier spec = strc_to_specifier( to_str(currtok) );
|
2024-12-03 12:19:39 -08:00
|
|
|
switch ( spec )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 10:14:14 -08:00
|
|
|
case Spec_Const:
|
|
|
|
case Spec_Constexpr:
|
|
|
|
case Spec_Constinit:
|
|
|
|
case Spec_External_Linkage:
|
|
|
|
case Spec_Global:
|
|
|
|
case Spec_Inline:
|
|
|
|
case Spec_Local_Persist:
|
|
|
|
case Spec_Mutable:
|
|
|
|
case Spec_Static:
|
|
|
|
case Spec_Thread_Local:
|
|
|
|
case Spec_Volatile:
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2024-12-06 02:29:17 -08:00
|
|
|
log_failure( "Invalid specifier %s for variable\n%s", spec_to_str( spec ), to_string(Context) );
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2024-12-01 21:03:38 -08:00
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ignore const specifiers, they're handled by the type
|
2024-12-03 10:14:14 -08:00
|
|
|
if ( spec == Spec_Const )
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
specs_found[NumSpecifiers] = spec;
|
|
|
|
NumSpecifiers++;
|
|
|
|
eat( currtok.Type );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( NumSpecifiers )
|
|
|
|
{
|
|
|
|
specifiers = def_specifiers( NumSpecifiers, specs_found );
|
|
|
|
}
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> <Attributes> <Specifiers>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 12:19:39 -08:00
|
|
|
CodeTypename type = parse_type();
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> <Attributes> <Specifiers> <ValueType>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-01 21:03:38 -08:00
|
|
|
if ( type == Code_Invalid )
|
|
|
|
return InvalidCode;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
Context.Scope->Name = parse_identifier();
|
2023-11-21 18:27:33 -08:00
|
|
|
// <ModuleFlags> <Attributes> <Specifiers> <ValueType> <Name>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
CodeVar result = parse_variable_after_name( mflags, attributes, specifiers, type, to_str(Context.Scope->Name) );
|
2023-11-21 18:27:33 -08:00
|
|
|
// Regular : <ModuleFlags> <Attributes> <Specifiers> <ValueType> <Name> = <Value>; <InlineCmt>
|
|
|
|
// Bitfield : <ModuleFlags> <Attributes> <Specifiers> <ValueType> <Name> : <BitfieldSize> = <Value>; <InlineCmt>
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:31:27 -08:00
|
|
|
pop(& Context);
|
2023-11-20 12:09:01 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
GEN_NS_PARSER_END
|
2024-10-27 18:18:41 -07:00
|
|
|
|
|
|
|
#ifdef CHECK_WAS_DEFINED
|
|
|
|
#pragma pop_macro("check")
|
|
|
|
#endif
|