2023-08-28 20:46:50 -07:00
# ifdef GEN_INTELLISENSE_DIRECTIVES
2023-08-21 17:30:13 -07:00
# pragma once
2023-08-21 20:28:39 -07:00
# include "gen/etoktype.cpp"
2023-08-21 20:02:20 -07:00
# include "interface.upfront.cpp"
2023-08-28 20:46:50 -07:00
# endif
2023-08-21 17:30:13 -07:00
2023-07-24 14:45:27 -07:00
namespace Parser
{
2023-09-25 09:12:11 -07:00
enum TokFlags : u32
{
TF_Operator = bit ( 0 ) ,
TF_Assign = bit ( 0 ) ,
TF_Preprocess = bit ( 1 ) ,
TF_Comment = bit ( 2 ) ,
TF_Attribute = bit ( 3 ) ,
TF_AccessSpecifier = bit ( 4 ) ,
TF_Specifier = bit ( 5 ) ,
TF_EndDefinition = bit ( 6 ) , // Either ; or }
} ;
2023-07-27 14:12:58 -07:00
struct Token
{
char const * Text ;
sptr Length ;
TokType Type ;
2023-07-28 18:44:31 -07:00
s32 Line ;
s32 Column ;
2023-08-02 09:39:35 -07:00
bool IsAssign ;
2023-07-29 02:52:06 -07:00
// TokFlags Flags;
2023-07-27 14:12:58 -07:00
operator bool ( )
{
return Text & & Length & & Type ! = TokType : : Invalid ;
}
operator StrC ( )
{
return { Length , Text } ;
}
2023-07-28 18:44:31 -07:00
bool is_access_specifier ( )
{
return Type > = TokType : : Access_Private & & Type < = TokType : : Access_Public ;
}
2023-07-27 14:12:58 -07:00
2023-07-28 18:44:31 -07:00
bool is_attribute ( )
{
2023-07-31 21:42:08 -07:00
return Type > TokType : : __Attributes_Start ;
2023-07-28 18:44:31 -07:00
}
2023-07-27 14:12:58 -07:00
2023-07-28 18:44:31 -07:00
bool is_preprocessor ( )
{
2023-07-29 22:21:04 -07:00
return Type > = TokType : : Preprocess_Define & & Type < = TokType : : Preprocess_Pragma ;
}
bool is_preprocess_cond ( )
{
return Type > = TokType : : Preprocess_If & & Type < = TokType : : Preprocess_EndIf ;
2023-07-28 18:44:31 -07:00
}
2023-07-27 14:12:58 -07:00
2023-07-28 18:44:31 -07:00
bool is_specifier ( )
{
return ( Type < = TokType : : Star & & Type > = TokType : : Spec_Alignas )
| | Type = = TokType : : Ampersand
| | Type = = TokType : : Ampersand_DBL
;
}
AccessSpec to_access_specifier ( )
{
return scast ( AccessSpec , Type ) ;
}
2023-08-23 10:17:22 -07:00
String to_string ( )
{
String result = String : : make_reserve ( GlobalAllocator , kilobytes ( 4 ) ) ;
StrC type_str = ETokType : : to_str ( Type ) ;
result . append_fmt ( " Line: %d Column: %d, Type: %.*s Content: %.*s "
, Line , Column
, type_str . Len , type_str . Ptr
, Length , Text
) ;
return result ;
}
2023-07-28 18:44:31 -07:00
} ;
2023-07-27 14:12:58 -07:00
2023-07-29 02:52:06 -07:00
constexpr Token NullToken { nullptr , 0 , TokType : : Invalid , false , 0 , 0 } ;
2023-07-24 14:45:27 -07:00
struct TokArray
{
Array < Token > Arr ;
s32 Idx ;
2023-07-28 18:44:31 -07:00
bool __eat ( TokType type ) ;
2023-07-24 14:45:27 -07:00
2023-08-22 21:05:58 -07:00
Token & current ( bool skip_formatting = true )
2023-07-24 14:45:27 -07:00
{
2023-08-22 21:05:58 -07:00
if ( skip_formatting )
2023-08-04 13:12:13 -07:00
{
2023-08-22 21:05:58 -07:00
while ( Arr [ Idx ] . Type = = TokType : : NewLine | | Arr [ Idx ] . Type = = TokType : : Comment )
2023-08-04 13:12:13 -07:00
Idx + + ;
}
2023-08-03 20:18:33 -07:00
2023-07-24 14:45:27 -07:00
return Arr [ Idx ] ;
}
2023-08-22 21:05:58 -07:00
Token & previous ( bool skip_formatting = false )
2023-07-24 14:45:27 -07:00
{
2023-08-03 20:18:33 -07:00
s32 idx = this - > Idx ;
2023-08-04 13:12:13 -07:00
2023-08-22 21:05:58 -07:00
if ( skip_formatting )
2023-08-04 13:12:13 -07:00
{
while ( Arr [ idx ] . Type = = TokType : : NewLine )
idx - - ;
return Arr [ idx ] ;
}
2023-07-24 14:45:27 -07:00
2023-08-03 20:18:33 -07:00
return Arr [ idx - 1 ] ;
2023-07-24 14:45:27 -07:00
}
2023-08-01 02:17:24 -07:00
2023-08-22 21:05:58 -07:00
Token & next ( bool skip_formatting = false )
2023-08-07 00:10:45 -07:00
{
s32 idx = this - > Idx ;
2023-08-22 21:05:58 -07:00
if ( skip_formatting )
2023-08-07 00:10:45 -07:00
{
while ( Arr [ idx ] . Type = = TokType : : NewLine )
idx + + ;
return Arr [ idx ] ;
}
return Arr [ idx + 1 ] ;
}
2023-08-01 02:17:24 -07:00
Token & operator [ ] ( s32 idx )
{
return Arr [ idx ] ;
}
2023-07-24 14:45:27 -07:00
} ;
2023-08-22 21:05:58 -07:00
constexpr bool dont_skip_formatting = false ;
2023-08-04 13:12:13 -07:00
2023-07-28 18:44:31 -07:00
struct StackNode
{
StackNode * Prev ;
2023-07-29 14:14:02 -07:00
Token Start ;
2023-07-28 18:44:31 -07:00
Token Name ; // The name of the AST node (if parsed)
StrC ProcName ; // The name of the procedure
} ;
struct ParseContext
{
TokArray Tokens ;
StackNode * Scope ;
2023-07-29 14:14:02 -07:00
void push ( StackNode * node )
{
node - > Prev = Scope ;
Scope = node ;
2023-08-23 15:16:45 -07:00
#if 0 && Build_Debug
log_fmt ( " \t Entering Context: %.*s \n " , Scope - > ProcName . Len , Scope - > ProcName . Ptr ) ;
# endif
2023-07-29 14:14:02 -07:00
}
void pop ( )
{
2023-08-23 15:16:45 -07:00
#if 0 && Build_Debug
log_fmt ( " \t Popping Context: %.*s \n " , Scope - > ProcName . Len , Scope - > ProcName . Ptr ) ;
# endif
2023-07-29 14:14:02 -07:00
Scope = Scope - > Prev ;
}
2023-07-28 18:44:31 -07:00
String to_string ( )
{
String result = String : : make_reserve ( GlobalAllocator , kilobytes ( 4 ) ) ;
2023-07-29 14:14:02 -07:00
Token scope_start = Scope - > Start ;
Token last_valid = Tokens . Idx > = Tokens . Arr . num ( ) ? Tokens . Arr [ Tokens . Arr . num ( ) - 1 ] : Tokens . current ( ) ;
2023-07-29 10:15:53 -07:00
2023-07-29 14:14:02 -07:00
sptr length = scope_start . Length ;
char const * current = scope_start . Text + length ;
while ( current < = Tokens . Arr . back ( ) . Text & & * current ! = ' \n ' & & length < 74 )
2023-07-29 02:52:06 -07:00
{
current + + ;
2023-07-29 10:15:53 -07:00
length + + ;
2023-07-29 02:52:06 -07:00
}
2023-07-29 14:14:02 -07:00
String line = String : : make ( GlobalAllocator , { length , scope_start . Text } ) ;
2023-07-31 21:42:08 -07:00
result . append_fmt ( " \t Scope : %s \n " , line ) ;
2023-07-29 02:52:06 -07:00
line . free ( ) ;
2023-09-05 21:30:34 -07:00
sptr dist = ( sptr ) last_valid . Text - ( sptr ) scope_start . Text + 2 ;
2023-07-29 14:14:02 -07:00
sptr length_from_err = dist ;
String line_from_err = String : : make ( GlobalAllocator , { length_from_err , last_valid . Text } ) ;
2023-08-02 09:39:35 -07:00
if ( length_from_err < 100 )
result . append_fmt ( " \t (%d, %d):%*c \n " , last_valid . Line , last_valid . Column , length_from_err , ' ^ ' ) ;
else
result . append_fmt ( " \t (%d, %d) \n " , last_valid . Line , last_valid . Column ) ;
2023-07-29 14:14:02 -07:00
2023-07-29 03:32:16 -07:00
StackNode * curr_scope = Scope ;
2023-07-29 14:14:02 -07:00
s32 level = 0 ;
2023-07-28 18:44:31 -07:00
do
{
2023-07-29 03:32:16 -07:00
if ( curr_scope - > Name )
2023-07-29 02:52:06 -07:00
{
2023-08-04 13:12:13 -07:00
result . append_fmt ( " \t %d: %s, AST Name: %.*s \n " , level , curr_scope - > ProcName . Ptr , curr_scope - > Name . Length , curr_scope - > Name . Text ) ;
2023-07-29 02:52:06 -07:00
}
else
{
2023-07-29 14:14:02 -07:00
result . append_fmt ( " \t %d: %s \n " , level , curr_scope - > ProcName . Ptr ) ;
2023-07-29 02:52:06 -07:00
}
2023-07-28 18:44:31 -07:00
2023-07-29 03:32:16 -07:00
curr_scope = curr_scope - > Prev ;
2023-07-29 14:14:02 -07:00
level + + ;
2023-07-28 18:44:31 -07:00
}
2023-07-29 10:15:53 -07:00
while ( curr_scope ) ;
2023-07-28 18:44:31 -07:00
return result ;
}
} ;
global ParseContext Context ;
bool TokArray : : __eat ( TokType type )
{
if ( Arr . num ( ) - Idx < = 0 )
{
2023-07-29 02:52:06 -07:00
log_failure ( " No tokens left. \n %s " , Context . to_string ( ) ) ;
2023-07-28 18:44:31 -07:00
return false ;
}
2023-09-07 19:51:15 -07:00
if ( ( Arr [ Idx ] . Type = = TokType : : NewLine & & type ! = TokType : : NewLine )
| | ( Arr [ Idx ] . Type = = TokType : : Comment & & type ! = TokType : : Comment ) )
2023-08-03 20:18:33 -07:00
{
Idx + + ;
}
2023-07-28 18:44:31 -07:00
if ( Arr [ Idx ] . Type ! = type )
{
2023-08-04 13:12:13 -07:00
log_failure ( " Parse Error, TokArray::eat, Expected: ' %s ' not ' %.*s ' (%d, %d)` \n %s "
, ETokType : : to_str ( type ) . Ptr
, Arr [ Idx ] . Length , Arr [ Idx ] . Text
2023-07-29 22:21:04 -07:00
, current ( ) . Line
, current ( ) . Column
, Context . to_string ( )
) ;
2023-07-28 18:44:31 -07:00
return false ;
}
2023-08-23 15:16:45 -07:00
#if 0 && Build_Debug
log_fmt ( " Ate: %S \n " , Arr [ Idx ] . to_string ( ) ) ;
# endif
2023-07-28 18:44:31 -07:00
Idx + + ;
return true ;
}
2023-07-30 15:55:57 -07:00
global Array < Token > Tokens ;
2023-08-21 20:49:23 -07:00
neverinline
2023-07-29 22:21:04 -07:00
TokArray lex ( StrC content )
2023-07-24 14:45:27 -07:00
{
# define current ( * scanner )
2023-07-28 18:44:31 -07:00
# define move_forward() \
{ \
if ( current = = ' \n ' ) \
{ \
line + + ; \
2023-08-03 20:18:33 -07:00
column = 1 ; \
2023-07-28 18:44:31 -07:00
} \
else \
{ \
column + + ; \
} \
left - - ; \
scanner + + ; \
}
2023-07-24 14:45:27 -07:00
# define SkipWhitespace() \
while ( left & & char_is_space ( current ) ) \
{ \
move_forward ( ) ; \
}
2023-09-07 19:51:15 -07:00
# define end_line() \
2023-08-21 23:09:20 -07:00
do \
{ \
while ( left & & current = = ' ' ) \
{ \
move_forward ( ) ; \
} \
if ( left & & current = = ' \r ' ) \
{ \
move_forward ( ) ; \
move_forward ( ) ; \
} \
else if ( left & & current = = ' \n ' ) \
{ \
move_forward ( ) ; \
} \
} \
while ( 0 )
2023-07-24 14:45:27 -07:00
s32 left = content . Len ;
char const * scanner = content . Ptr ;
char const * word = scanner ;
s32 word_length = 0 ;
2023-07-31 21:42:08 -07:00
s32 line = 1 ;
s32 column = 1 ;
2023-07-28 18:44:31 -07:00
2023-07-24 14:45:27 -07:00
SkipWhitespace ( ) ;
if ( left < = 0 )
{
log_failure ( " gen::lex: no tokens found (only whitespace provided) " ) ;
return { { nullptr } , 0 } ;
}
2023-09-07 19:51:15 -07:00
local_persist Arena_64KB defines_map_arena = Arena_64KB : : init ( ) ;
HashTable < StrC > defines = HashTable < StrC > : : init ( defines_map_arena ) ;
2023-07-24 14:45:27 -07:00
2023-07-30 15:55:57 -07:00
Tokens . clear ( ) ;
2023-07-24 14:45:27 -07:00
while ( left )
{
2023-08-23 10:17:22 -07:00
#if 0
if ( Tokens . num ( ) )
{
log_fmt ( " \n LastTok: %S " , Tokens . back ( ) . to_string ( ) ) ;
}
# endif
2023-08-04 13:12:13 -07:00
Token token = { scanner , 0 , TokType : : Invalid , line , column , false } ;
2023-08-02 09:39:35 -07:00
2023-08-03 20:18:33 -07:00
bool is_define = false ;
if ( column = = 1 )
2023-08-02 09:39:35 -07:00
{
2023-08-03 20:18:33 -07:00
if ( current = = ' \r ' )
2023-08-04 13:12:13 -07:00
{
move_forward ( ) ;
2023-08-03 20:18:33 -07:00
token . Length = 1 ;
2023-08-04 13:12:13 -07:00
}
2023-08-03 20:18:33 -07:00
if ( current = = ' \n ' )
{
2023-08-04 13:12:13 -07:00
move_forward ( ) ;
2023-08-03 20:18:33 -07:00
2023-08-08 19:14:58 -07:00
token . Type = TokType : : NewLine ;
token . Length + + ;
2023-08-03 20:18:33 -07:00
Tokens . append ( token ) ;
continue ;
}
}
2023-07-30 15:55:57 -07:00
2023-08-04 13:12:13 -07:00
token . Length = 0 ;
2023-07-24 14:45:27 -07:00
SkipWhitespace ( ) ;
if ( left < = 0 )
break ;
switch ( current )
{
case ' # ' :
2023-07-29 22:21:04 -07:00
{
2023-08-01 17:56:00 -07:00
char const * hash = scanner ;
2023-08-06 10:28:19 -07:00
Tokens . append ( { hash , 1 , TokType : : Preprocess_Hash , line , column , false } ) ;
2023-08-01 17:56:00 -07:00
2023-07-24 14:45:27 -07:00
move_forward ( ) ;
2023-07-30 15:55:57 -07:00
SkipWhitespace ( ) ;
2023-07-24 14:45:27 -07:00
2023-07-30 15:55:57 -07:00
token . Text = scanner ;
while ( left & & ! char_is_space ( current ) )
2023-07-29 22:21:04 -07:00
{
move_forward ( ) ;
token . Length + + ;
}
token . Type = ETokType : : to_type ( token ) ;
2023-07-31 21:42:08 -07:00
if ( ! token . is_preprocessor ( ) )
{
token . Type = TokType : : Preprocess_Unsupported ;
// Its an unsupported directive, skip it
s32 within_string = false ;
s32 within_char = false ;
while ( left )
{
2023-09-05 21:30:34 -07:00
if ( current = = ' " ' & & ! within_char )
2023-07-31 21:42:08 -07:00
within_string ^ = true ;
2023-09-05 21:30:34 -07:00
if ( current = = ' \' ' & & ! within_string )
2023-07-31 21:42:08 -07:00
within_char ^ = true ;
if ( current = = ' \\ ' & & ! within_string & & ! within_char )
{
move_forward ( ) ;
token . Length + + ;
if ( current = = ' \r ' )
{
move_forward ( ) ;
2023-08-04 13:12:13 -07:00
token . Length + + ;
2023-07-31 21:42:08 -07:00
}
if ( current = = ' \n ' )
{
move_forward ( ) ;
2023-08-04 13:12:13 -07:00
token . Length + + ;
2023-07-31 21:42:08 -07:00
continue ;
}
else
{
log_failure ( " gen::Parser::lex: Invalid escape sequence ' \\ %c' (%d, %d) "
2023-08-04 13:12:13 -07:00
" in preprocessor directive (%d, %d) \n %.100s "
2023-07-31 21:42:08 -07:00
, current , line , column
2023-08-04 13:12:13 -07:00
, token . Line , token . Column , token . Text ) ;
2023-07-31 21:42:08 -07:00
break ;
}
}
2023-08-04 13:12:13 -07:00
if ( current = = ' \r ' )
{
2023-08-08 19:14:58 -07:00
move_forward ( ) ;
token . Length + + ;
2023-08-04 13:12:13 -07:00
}
2023-07-31 21:42:08 -07:00
if ( current = = ' \n ' )
{
2023-08-08 19:14:58 -07:00
move_forward ( ) ;
token . Length + + ;
2023-07-31 21:42:08 -07:00
break ;
}
move_forward ( ) ;
token . Length + + ;
}
2023-08-04 13:12:13 -07:00
token . Length = token . Length + token . Text - hash ;
2023-08-01 17:56:00 -07:00
token . Text = hash ;
2023-07-31 21:42:08 -07:00
Tokens . append ( token ) ;
continue ; // Skip found token, its all handled here.
}
2023-08-01 11:02:54 -07:00
if ( token . Type = = TokType : : Preprocess_Else | | token . Type = = TokType : : Preprocess_EndIf )
{
Tokens . append ( token ) ;
2023-08-21 23:09:20 -07:00
end_line ( ) ;
2023-08-01 11:02:54 -07:00
continue ;
}
2023-07-29 22:21:04 -07:00
Tokens . append ( token ) ;
2023-07-31 21:42:08 -07:00
SkipWhitespace ( ) ;
2023-07-30 15:55:57 -07:00
if ( token . Type = = TokType : : Preprocess_Define )
{
2023-08-02 09:39:35 -07:00
Token name = { scanner , 0 , TokType : : Identifier , line , column , false } ;
2023-07-30 15:55:57 -07:00
name . Text = scanner ;
name . Length = 1 ;
move_forward ( ) ;
while ( left & & ( char_is_alphanumeric ( current ) | | current = = ' _ ' ) )
{
move_forward ( ) ;
name . Length + + ;
}
2023-08-02 09:39:35 -07:00
if ( left & & current = = ' ( ' )
{
move_forward ( ) ;
name . Length + + ;
}
2023-07-30 15:55:57 -07:00
Tokens . append ( name ) ;
2023-07-31 21:42:08 -07:00
u64 key = crc32 ( name . Text , name . Length ) ;
2023-07-30 15:55:57 -07:00
defines . set ( key , name ) ;
}
2023-08-02 09:39:35 -07:00
Token content = { scanner , 0 , TokType : : Preprocess_Content , line , column , false } ;
2023-07-29 22:21:04 -07:00
if ( token . Type = = TokType : : Preprocess_Include )
2023-07-24 14:45:27 -07:00
{
2023-07-29 22:21:04 -07:00
content . Type = TokType : : String ;
2023-07-30 15:55:57 -07:00
if ( current ! = ' " ' & & current ! = ' < ' )
2023-07-29 22:21:04 -07:00
{
2023-07-30 15:55:57 -07:00
String directive_str = String : : fmt_buf ( GlobalAllocator , " %.*s " , min ( 80 , left + content . Length ) , token . Text ) ;
log_failure ( " gen::Parser::lex: Expected ' \" ' or '<' after #include, not '%c' (%d, %d) \n %s "
2023-07-29 22:21:04 -07:00
, current
2023-07-30 15:55:57 -07:00
, content . Line
, content . Column
, directive_str . Data
2023-07-29 22:21:04 -07:00
) ;
return { { nullptr } , 0 } ;
}
2023-07-30 15:55:57 -07:00
while ( left & & current ! = ' " ' & & current ! = ' > ' )
2023-07-28 18:44:31 -07:00
{
2023-07-29 22:21:04 -07:00
move_forward ( ) ;
content . Length + + ;
2023-07-28 18:44:31 -07:00
}
2023-07-29 22:21:04 -07:00
move_forward ( ) ;
content . Length + + ;
Tokens . append ( content ) ;
continue ; // Skip found token, its all handled here.
}
2023-07-30 15:55:57 -07:00
s32 within_string = false ;
s32 within_char = false ;
2023-08-26 08:55:05 -07:00
// SkipWhitespace();
2023-07-29 22:21:04 -07:00
while ( left )
{
2023-08-23 18:19:31 -07:00
if ( current = = ' " ' & & ! within_char )
2023-07-30 15:55:57 -07:00
within_string ^ = true ;
2023-08-23 18:19:31 -07:00
if ( current = = ' \' ' & & ! within_string )
2023-07-30 15:55:57 -07:00
within_char ^ = true ;
if ( current = = ' \\ ' & & ! within_string & & ! within_char )
2023-07-24 14:45:27 -07:00
{
move_forward ( ) ;
2023-07-29 22:21:04 -07:00
content . Length + + ;
2023-07-24 14:45:27 -07:00
2023-07-30 15:55:57 -07:00
if ( current = = ' \r ' )
{
move_forward ( ) ;
content . Length + + ;
}
2023-07-29 22:21:04 -07:00
if ( current = = ' \n ' )
{
move_forward ( ) ;
content . Length + + ;
continue ;
}
else
2023-07-24 14:45:27 -07:00
{
2023-07-30 15:55:57 -07:00
String directive_str = String : : make_length ( GlobalAllocator , token . Text , token . Length ) ;
String content_str = String : : fmt_buf ( GlobalAllocator , " %.*s " , min ( 400 , left + content . Length ) , content . Text ) ;
2023-07-29 22:21:04 -07:00
log_failure ( " gen::Parser::lex: Invalid escape sequence ' \\ %c' (%d, %d) "
2023-07-30 15:55:57 -07:00
" in preprocessor directive '%s' (%d, %d) \n %s "
, current , line , column
, directive_str , content . Line , content . Column
, content_str ) ;
2023-07-29 22:21:04 -07:00
break ;
2023-07-24 14:45:27 -07:00
}
}
2023-08-06 10:28:19 -07:00
if ( current = = ' \r ' )
{
2023-08-08 19:14:58 -07:00
move_forward ( ) ;
2023-08-06 10:28:19 -07:00
}
2023-07-29 22:21:04 -07:00
if ( current = = ' \n ' )
{
2023-08-08 19:14:58 -07:00
move_forward ( ) ;
2023-07-29 22:21:04 -07:00
break ;
}
2023-07-24 14:45:27 -07:00
move_forward ( ) ;
2023-07-29 22:21:04 -07:00
content . Length + + ;
2023-07-24 14:45:27 -07:00
}
2023-07-29 22:21:04 -07:00
Tokens . append ( content ) ;
continue ; // Skip found token, its all handled here.
}
2023-07-24 14:45:27 -07:00
case ' . ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Access_MemberSymbol ;
2023-07-28 18:44:31 -07:00
if ( left ) {
2023-07-24 14:45:27 -07:00
move_forward ( ) ;
2023-07-28 18:44:31 -07:00
}
2023-07-24 14:45:27 -07:00
if ( current = = ' . ' )
{
move_forward ( ) ;
if ( current = = ' . ' )
{
token . Length = 3 ;
token . Type = TokType : : Varadic_Argument ;
move_forward ( ) ;
}
else
{
2023-07-29 22:21:04 -07:00
String context_str = String : : fmt_buf ( GlobalAllocator , " %s " , scanner , min ( 100 , left ) ) ;
2023-07-30 15:55:57 -07:00
log_failure ( " gen::lex: invalid varadic argument, expected '...' got '..%c' (%d, %d) \n %s " , current , line , column , context_str ) ;
2023-07-24 14:45:27 -07:00
}
}
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' & ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Ampersand ;
if ( left )
move_forward ( ) ;
if ( current = = ' & ' ) // &&
{
token . Length = 2 ;
token . Type = TokType : : Ampersand_DBL ;
if ( left )
move_forward ( ) ;
}
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' : ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Assign_Classifer ;
2023-09-07 19:51:15 -07:00
// Can be either a classifier (ParentType, Bitfield width), or ternary else
// token.Type = TokType::Colon;
2023-07-24 14:45:27 -07:00
if ( left )
move_forward ( ) ;
if ( current = = ' : ' )
{
move_forward ( ) ;
token . Type = TokType : : Access_StaticSymbol ;
token . Length + + ;
}
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' { ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : BraceCurly_Open ;
if ( left )
move_forward ( ) ;
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' } ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : BraceCurly_Close ;
if ( left )
move_forward ( ) ;
2023-08-21 23:09:20 -07:00
end_line ( ) ;
2023-07-24 14:45:27 -07:00
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' [ ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : BraceSquare_Open ;
if ( left )
{
move_forward ( ) ;
if ( current = = ' ] ' )
{
token . Length = 2 ;
token . Type = TokType : : Operator ;
move_forward ( ) ;
}
}
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' ] ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : BraceSquare_Close ;
if ( left )
move_forward ( ) ;
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' ( ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Capture_Start ;
if ( left )
move_forward ( ) ;
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' ) ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Capture_End ;
if ( left )
move_forward ( ) ;
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' \' ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Char ;
move_forward ( ) ;
2023-07-30 15:55:57 -07:00
if ( left & & current = = ' \\ ' )
{
move_forward ( ) ;
token . Length + + ;
if ( current = = ' \' ' )
{
move_forward ( ) ;
token . Length + + ;
}
}
2023-07-24 14:45:27 -07:00
while ( left & & current ! = ' \' ' )
{
move_forward ( ) ;
token . Length + + ;
}
if ( left )
{
move_forward ( ) ;
token . Length + + ;
}
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' , ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Comma ;
if ( left )
move_forward ( ) ;
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' * ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Star ;
if ( left )
move_forward ( ) ;
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' ; ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Statement_End ;
if ( left )
move_forward ( ) ;
2023-08-21 23:09:20 -07:00
end_line ( ) ;
2023-07-24 14:45:27 -07:00
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' " ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : String ;
move_forward ( ) ;
while ( left )
{
if ( current = = ' " ' )
{
move_forward ( ) ;
break ;
}
if ( current = = ' \\ ' )
{
move_forward ( ) ;
token . Length + + ;
if ( left )
{
move_forward ( ) ;
token . Length + + ;
}
continue ;
}
move_forward ( ) ;
token . Length + + ;
}
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-30 15:55:57 -07:00
case ' ? ' :
2023-09-07 19:51:15 -07:00
{
2023-07-30 15:55:57 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Operator ;
2023-09-07 19:51:15 -07:00
// token.Type = TokType::Ternary;
2023-07-30 15:55:57 -07:00
token . IsAssign = false ;
if ( left )
move_forward ( ) ;
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' = ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Operator ;
2023-09-07 19:51:15 -07:00
// token.Type = TokType::Assign;
2023-07-24 14:45:27 -07:00
token . IsAssign = true ;
2023-09-07 19:51:15 -07:00
// token.Flags |= TokFlags::Assignment;
2023-07-24 14:45:27 -07:00
if ( left )
move_forward ( ) ;
2023-07-30 15:55:57 -07:00
if ( current = = ' = ' )
{
token . Length + + ;
token . IsAssign = false ;
if ( left )
move_forward ( ) ;
}
2023-07-24 14:45:27 -07:00
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' + ' :
2023-09-07 19:51:15 -07:00
{
// token.Type = TokType::Add
}
2023-07-24 14:45:27 -07:00
case ' % ' :
2023-09-07 19:51:15 -07:00
{
// token.Type = TokType::Modulo;
}
2023-07-24 14:45:27 -07:00
case ' ^ ' :
2023-09-07 19:51:15 -07:00
{
// token.Type = TokType::B_XOr;
}
2023-07-24 14:45:27 -07:00
case ' ~ ' :
2023-09-07 19:51:15 -07:00
{
// token.Type = TokType::Unary_Not;
}
2023-07-24 14:45:27 -07:00
case ' ! ' :
2023-09-07 19:51:15 -07:00
{
// token.Type = TokType::L_Not;
}
2023-07-24 14:45:27 -07:00
case ' < ' :
2023-09-07 19:51:15 -07:00
{
// token.Type = TokType::Lesser;
}
2023-07-24 14:45:27 -07:00
case ' > ' :
2023-09-07 19:51:15 -07:00
{
// token.Type = TokType::Greater;
}
2023-07-24 14:45:27 -07:00
case ' | ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Operator ;
2023-09-07 19:51:15 -07:00
// token.Type = TokType::L_Or;
2023-07-24 14:45:27 -07:00
if ( left )
move_forward ( ) ;
if ( current = = ' = ' )
{
token . Length + + ;
token . IsAssign = true ;
2023-09-07 19:51:15 -07:00
// token.Flags |= TokFlags::Assignment;
// token.Type = TokType::Assign_L_Or;
2023-07-24 14:45:27 -07:00
if ( left )
move_forward ( ) ;
}
else while ( left & & current = = * ( scanner - 1 ) & & token . Length < 3 )
{
token . Length + + ;
if ( left )
move_forward ( ) ;
}
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
// Dash is unfortunatlly a bit more complicated...
case ' - ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Operator ;
2023-09-07 19:51:15 -07:00
// token.Type = TokType::Subtract;
2023-07-24 14:45:27 -07:00
if ( left )
{
move_forward ( ) ;
if ( current = = ' > ' )
{
token . Length + + ;
move_forward ( ) ;
if ( current = = ' * ' )
{
token . Length + + ;
move_forward ( ) ;
}
}
else if ( current = = ' = ' )
{
token . Length + + ;
token . IsAssign = true ;
2023-09-07 19:51:15 -07:00
// token.Flags |= TokFlags::Assignment;
// token.Type = TokType::Assign_Subtract;
2023-07-24 14:45:27 -07:00
if ( left )
move_forward ( ) ;
}
else while ( left & & current = = * ( scanner - 1 ) & & token . Length < 3 )
{
token . Length + + ;
if ( left )
move_forward ( ) ;
}
}
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
case ' / ' :
2023-09-07 19:51:15 -07:00
{
2023-07-24 14:45:27 -07:00
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Operator ;
2023-09-07 19:51:15 -07:00
// token.Type = TokType::Divide;
2023-08-23 10:17:22 -07:00
move_forward ( ) ;
2023-07-24 14:45:27 -07:00
if ( left )
{
if ( current = = ' / ' )
{
2023-08-22 21:05:58 -07:00
token . Type = TokType : : Comment ;
2023-08-06 10:28:19 -07:00
token . Length = 2 ;
2023-07-24 14:45:27 -07:00
move_forward ( ) ;
2023-08-04 13:12:13 -07:00
while ( left & & current ! = ' \n ' & & current ! = ' \r ' )
2023-07-24 14:45:27 -07:00
{
move_forward ( ) ;
2023-08-22 21:05:58 -07:00
token . Length + + ;
2023-07-24 14:45:27 -07:00
}
2023-08-04 13:12:13 -07:00
if ( current = = ' \r ' )
{
move_forward ( ) ;
2023-08-22 21:05:58 -07:00
token . Length + + ;
2023-08-04 13:12:13 -07:00
}
if ( current = = ' \n ' )
{
move_forward ( ) ;
2023-08-22 21:05:58 -07:00
token . Length + + ;
2023-08-04 13:12:13 -07:00
}
2023-08-22 21:05:58 -07:00
Tokens . append ( token ) ;
2023-08-06 10:28:19 -07:00
continue ;
2023-07-24 14:45:27 -07:00
}
else if ( current = = ' * ' )
{
2023-08-22 21:05:58 -07:00
token . Type = TokType : : Comment ;
2023-08-06 10:28:19 -07:00
token . Length = 2 ;
2023-07-24 14:45:27 -07:00
move_forward ( ) ;
2023-08-22 21:05:58 -07:00
bool star = current = = ' * ' ;
2023-07-30 15:55:57 -07:00
bool slash = scanner [ 1 ] = = ' / ' ;
bool at_end = star & & slash ;
while ( left & & ! at_end )
2023-07-24 14:45:27 -07:00
{
move_forward ( ) ;
2023-08-22 21:05:58 -07:00
token . Length + + ;
2023-07-30 15:55:57 -07:00
2023-08-22 21:05:58 -07:00
star = current = = ' * ' ;
2023-07-30 15:55:57 -07:00
slash = scanner [ 1 ] = = ' / ' ;
at_end = star & & slash ;
2023-07-24 14:45:27 -07:00
}
2023-08-23 10:17:22 -07:00
token . Length + = 2 ;
2023-07-24 14:45:27 -07:00
move_forward ( ) ;
move_forward ( ) ;
2023-08-06 10:28:19 -07:00
2023-08-23 10:17:22 -07:00
if ( current = = ' \r ' )
{
move_forward ( ) ;
token . Length + + ;
}
if ( current = = ' \n ' )
{
move_forward ( ) ;
token . Length + + ;
}
Tokens . append ( token ) ;
2023-09-07 19:51:15 -07:00
// end_line();
2023-08-06 10:28:19 -07:00
continue ;
2023-07-24 14:45:27 -07:00
}
}
goto FoundToken ;
2023-09-07 19:51:15 -07:00
}
2023-07-24 14:45:27 -07:00
}
if ( char_is_alpha ( current ) | | current = = ' _ ' )
{
token . Text = scanner ;
token . Length = 1 ;
move_forward ( ) ;
while ( left & & ( char_is_alphanumeric ( current ) | | current = = ' _ ' ) )
{
move_forward ( ) ;
token . Length + + ;
}
goto FoundToken ;
}
else if ( char_is_digit ( current ) )
{
// This is a very brute force lex, no checks are done for validity of literal.
token . Text = scanner ;
token . Length = 1 ;
token . Type = TokType : : Number ;
move_forward ( ) ;
if ( left
& & ( current = = ' x ' | | current = = ' X '
| | current = = ' b ' | | current = = ' B '
| | current = = ' o ' | | current = = ' O ' )
)
{
move_forward ( ) ;
token . Length + + ;
while ( left & & char_is_hex_digit ( current ) )
{
move_forward ( ) ;
token . Length + + ;
}
goto FoundToken ;
}
while ( left & & char_is_digit ( current ) )
{
move_forward ( ) ;
token . Length + + ;
}
if ( left & & current = = ' . ' )
{
move_forward ( ) ;
token . Length + + ;
while ( left & & char_is_digit ( current ) )
{
move_forward ( ) ;
token . Length + + ;
}
}
goto FoundToken ;
}
else
{
2023-08-23 15:16:45 -07:00
s32 start = max ( 0 , Tokens . num ( ) - 100 ) ;
log_fmt ( " \n %d \n " , start ) ;
for ( s32 idx = start ; idx < Tokens . num ( ) ; idx + + )
{
log_fmt ( " Token %d Type: %s : %.*s \n "
, idx
, ETokType : : to_str ( Tokens [ idx ] . Type ) . Ptr
, Tokens [ idx ] . Length , Tokens [ idx ] . Text
) ;
}
2023-07-24 14:45:27 -07:00
2023-08-23 15:16:45 -07:00
String context_str = String : : fmt_buf ( GlobalAllocator , " %.*s " , min ( 100 , left ) , scanner ) ;
2023-07-30 15:55:57 -07:00
log_failure ( " Failed to lex token '%c' (%d, %d) \n %s " , current , line , column , context_str ) ;
2023-07-24 14:45:27 -07:00
// Skip to next whitespace since we can't know if anything else is valid until then.
while ( left & & ! char_is_space ( current ) )
{
move_forward ( ) ;
}
}
FoundToken :
if ( token . Type ! = TokType : : Invalid )
{
Tokens . append ( token ) ;
continue ;
}
2023-07-27 14:12:58 -07:00
TokType type = ETokType : : to_type ( token ) ;
2023-07-24 14:45:27 -07:00
2023-07-31 21:42:08 -07:00
if ( type = = ETokType : : Decl_Extern_Linkage )
{
SkipWhitespace ( ) ;
if ( current ! = ' " ' )
type = ETokType : : Spec_Extern ;
token . Type = type ;
Tokens . append ( token ) ;
continue ;
}
2023-07-30 15:55:57 -07:00
if ( type ! = TokType : : Invalid )
{
token . Type = type ;
Tokens . append ( token ) ;
continue ;
}
2023-08-02 09:39:35 -07:00
u64 key = 0 ;
if ( current = = ' ( ' )
key = crc32 ( token . Text , token . Length + 1 ) ;
else
key = crc32 ( token . Text , token . Length ) ;
2023-07-30 15:55:57 -07:00
StrC * define = defines . get ( key ) ;
if ( define )
{
token . Type = TokType : : Preprocess_Macro ;
// Want to ignore any arguments the define may have as they can be execution expressions.
if ( left & & current = = ' ( ' )
{
move_forward ( ) ;
token . Length + + ;
s32 level = 0 ;
while ( left & & ( current ! = ' ) ' | | level > 0 ) )
{
if ( current = = ' ( ' )
level + + ;
else if ( current = = ' ) ' & & level > 0 )
level - - ;
move_forward ( ) ;
token . Length + + ;
}
move_forward ( ) ;
token . Length + + ;
}
2023-08-04 13:12:13 -07:00
2023-08-08 19:14:58 -07:00
if ( current = = ' \r ' & & scanner [ 1 ] = = ' \n ' )
2023-08-04 13:12:13 -07:00
{
move_forward ( ) ;
}
2023-08-08 19:14:58 -07:00
else if ( current = = ' \n ' )
2023-08-04 13:12:13 -07:00
{
move_forward ( ) ;
}
2023-07-30 15:55:57 -07:00
}
else
{
token . Type = TokType : : Identifier ;
}
2023-07-24 14:45:27 -07:00
Tokens . append ( token ) ;
}
if ( Tokens . num ( ) = = 0 )
{
log_failure ( " Failed to lex any tokens " ) ;
return { { nullptr } , 0 } ;
}
2023-07-30 15:55:57 -07:00
defines . clear ( ) ;
2023-09-07 19:51:15 -07:00
// defines_map_arena.free();
2023-07-24 14:45:27 -07:00
return { Tokens , 0 } ;
# undef current
# undef move_forward
# undef SkipWhitespace
}
}
2023-07-30 15:55:57 -07:00
internal
void init_parser ( )
{
using namespace Parser ;
Tokens = Array < Token > : : init_reserve ( LexArena
, ( LexAllocator_Size - sizeof ( Array < Token > : : Header ) ) / sizeof ( Token )
) ;
}
internal
void deinit_parser ( )
{
Parser : : Tokens = { nullptr } ;
}
2023-07-24 14:45:27 -07:00
# pragma region Helper Macros
2023-07-28 18:44:31 -07:00
2023-07-29 22:21:04 -07:00
# define check_parse_args( def ) \
if ( def . Len < = 0 ) \
{ \
2023-07-29 03:32:16 -07:00
log_failure ( " gen:: " stringize ( __func__ ) " : length must greater than 0 " ) ; \
2023-07-31 21:42:08 -07:00
Parser : : Context . pop ( ) ; \
2023-07-29 22:21:04 -07:00
return CodeInvalid ; \
} \
if ( def . Ptr = = nullptr ) \
{ \
2023-07-29 03:32:16 -07:00
log_failure ( " gen:: " stringize ( __func__ ) " : def was null " ) ; \
2023-07-31 21:42:08 -07:00
Parser : : Context . pop ( ) ; \
2023-07-29 22:21:04 -07:00
return CodeInvalid ; \
2023-07-24 14:45:27 -07:00
}
2023-08-22 21:05:58 -07:00
# define currtok_noskip Context.Tokens.current( dont_skip_formatting )
2023-08-04 13:12:13 -07:00
# define currtok Context.Tokens.current()
# define prevtok Context.Tokens.previous()
2023-08-07 00:10:45 -07:00
# define nexttok Context.Tokens.next()
2023-08-04 13:12:13 -07:00
# define eat( Type_ ) Context.Tokens.__eat( Type_ )
# define left ( Context.Tokens.Arr.num() - Context.Tokens.Idx )
2023-07-24 14:45:27 -07:00
2023-08-04 13:12:13 -07:00
# define check_noskip( Type_ ) ( left && currtok_noskip.Type == Type_ )
# define check( Type_ ) ( left && currtok.Type == Type_ )
2023-07-28 18:44:31 -07:00
2023-08-23 15:16:45 -07:00
# define push_scope() \
2023-09-07 19:51:15 -07:00
StackNode scope { nullptr , currtok_noskip , NullToken , txt ( __func__ ) } ; \
2023-07-29 02:52:06 -07:00
Context . push ( & scope )
2023-07-28 18:44:31 -07:00
2023-07-24 14:45:27 -07:00
# pragma endregion Helper Macros
2023-09-04 22:44:04 -07:00
// Procedure Forwards ( Entire parser internal parser interface )
internal Code parse_array_decl ( ) ;
internal CodeAttributes parse_attributes ( ) ;
internal CodeComment parse_comment ( ) ;
internal Code parse_compilcated_definition ( ) ;
internal CodeBody parse_class_struct_body ( Parser : : TokType which , Parser : : Token name = Parser : : NullToken ) ;
internal Code parse_class_struct ( Parser : : TokType which , bool inplace_def ) ;
internal CodeDefine parse_define ( ) ;
internal Code parse_foward_or_definition ( Parser : : TokType which , bool is_inplace ) ;
internal CodeFn parse_function_after_name ( ModuleFlag mflags , CodeAttributes attributes , CodeSpecifiers specifiers , CodeType ret_type , Parser : : Token name ) ;
internal Code parse_function_body ( ) ;
internal Code parse_global_nspace ( ) ;
internal Parser : : Token parse_identifier ( bool * possible_member_function = nullptr ) ;
internal CodeInclude parse_include ( ) ;
internal CodeOperator parse_operator_after_ret_type ( ModuleFlag mflags , CodeAttributes attributes , CodeSpecifiers specifiers , CodeType ret_type ) ;
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 ( ) ;
internal Code parse_simple_preprocess ( Parser : : TokType which ) ;
internal Code parse_static_assert ( ) ;
internal void parse_template_args ( Parser : : Token & token ) ;
internal CodeVar parse_variable_after_name ( ModuleFlag mflags , CodeAttributes attributes , CodeSpecifiers specifiers , CodeType type , StrC name ) ;
2023-07-28 18:44:31 -07:00
2023-08-07 00:10:45 -07:00
internal CodeClass parse_class ( bool inplace_def = false ) ;
internal CodeConstructor parse_constructor ( ) ;
internal CodeDestructor parse_destructor ( CodeSpecifiers specifiers = NoCode ) ;
internal CodeEnum parse_enum ( bool inplace_def = false ) ;
internal CodeBody parse_export_body ( ) ;
internal CodeBody parse_extern_link_body ( ) ;
internal CodeExtern parse_exten_link ( ) ;
internal CodeFriend parse_friend ( ) ;
internal CodeFn parse_function ( ) ;
internal CodeNS parse_namespace ( ) ;
2023-08-21 17:30:13 -07:00
internal CodeOpCast parse_operator_cast ( CodeSpecifiers specifiers = NoCode ) ;
2023-08-07 00:10:45 -07:00
internal CodeStruct parse_struct ( bool inplace_def = false ) ;
internal CodeVar parse_variable ( ) ;
internal CodeTemplate parse_template ( ) ;
2023-08-07 17:16:04 -07:00
internal CodeType parse_type ( bool * is_function = nullptr ) ;
2023-08-07 00:10:45 -07:00
internal CodeTypedef parse_typedef ( ) ;
internal CodeUnion parse_union ( bool inplace_def = false ) ;
internal CodeUsing parse_using ( ) ;
2023-07-24 14:45:27 -07:00
2023-08-01 02:17:24 -07:00
constexpr bool inplace_def = true ;
2023-09-04 22:44:04 -07:00
// Internal parsing functions
2023-08-06 10:28:19 -07:00
2023-09-05 21:30:34 -07:00
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 .
*/
String strip_formatting ( StrC raw_text , bool preserve_newlines = true )
{
String content = String : : make_reserve ( GlobalAllocator , raw_text . Len ) ;
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 ( ) ;
content . append ( cut_ptr , cut_length ) ;
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 ( ) ;
content . append ( cut_ptr , cut_length ) ;
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 ;
content . append ( cut_ptr , cut_length ) ;
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 ( ) ;
content . append ( cut_ptr , cut_length ) ;
last_cut = sptr ( scanner ) - sptr ( raw_text . Ptr ) ;
continue ;
}
// Tabs
if ( scanner [ 0 ] = = ' \t ' )
{
if ( pos > last_cut )
content . append ( cut_ptr , cut_length ) ;
if ( content . back ( ) ! = ' ' )
content . append ( ' ' ) ;
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 ;
content . append ( cut_ptr , cut_length ) ;
last_cut = sptr ( scanner ) - sptr ( raw_text . Ptr ) ;
continue ;
}
if ( pos > last_cut )
content . append ( cut_ptr , cut_length ) ;
// Replace with a space
if ( content . back ( ) ! = ' ' )
content . append ( ' ' ) ;
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 ( ) ;
content . append ( cut_ptr , cut_length ) ;
last_cut = sptr ( scanner ) - sptr ( raw_text . Ptr ) ;
continue ;
}
if ( pos > last_cut )
content . append ( cut_ptr , cut_length ) ;
// Replace with a space
if ( content . back ( ) ! = ' ' )
content . append ( ' ' ) ;
move_fwd ( ) ;
last_cut = sptr ( scanner ) - sptr ( raw_text . Ptr ) ;
continue ;
}
// Escaped newlines
if ( scanner [ 0 ] = = ' \\ ' )
{
content . append ( cut_ptr , cut_length ) ;
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 ] ) )
{
content . append ( cut_ptr , cut_length ) ;
do
{
move_fwd ( ) ;
}
while ( tokleft & & char_is_space ( scanner [ 0 ] ) ) ;
last_cut = sptr ( scanner ) - sptr ( raw_text . Ptr ) ;
// Preserve only 1 space of formattting
if ( content . back ( ) ! = ' ' )
content . append ( ' ' ) ;
continue ;
}
move_fwd ( ) ;
}
if ( last_cut < raw_text . Len )
{
content . append ( cut_ptr , raw_text . Len - last_cut ) ;
}
# undef cut_ptr
# undef cut_length
# undef pos
# undef move_fwd
return content ;
}
2023-09-04 22:44:04 -07:00
internal
Code parse_array_decl ( )
2023-07-29 22:21:04 -07:00
{
using namespace Parser ;
push_scope ( ) ;
2023-09-04 22:44:04 -07:00
if ( check ( TokType : : Operator ) & & currtok . Text [ 0 ] = = ' [ ' & & currtok . Text [ 1 ] = = ' ] ' )
2023-07-29 22:21:04 -07:00
{
2023-09-04 22:44:04 -07:00
Code array_expr = untyped_str ( currtok ) ;
eat ( TokType : : Operator ) ;
2023-07-29 22:21:04 -07:00
2023-07-31 21:42:08 -07:00
Context . pop ( ) ;
2023-09-04 22:44:04 -07:00
return array_expr ;
2023-07-29 22:21:04 -07:00
}
2023-09-04 22:44:04 -07:00
if ( check ( TokType : : BraceSquare_Open ) )
2023-09-03 17:29:45 -07:00
{
2023-09-04 22:44:04 -07:00
eat ( TokType : : BraceSquare_Open ) ;
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
if ( left = = 0 )
{
log_failure ( " Error, unexpected end of array declaration ( '[]' scope started ) \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok . Type = = TokType : : BraceSquare_Close )
{
2023-09-05 21:30:34 -07:00
log_failure ( " Error, empty array expression in definition \n %s " , Context . to_string ( ) ) ;
2023-09-04 22:44:04 -07:00
Context . pop ( ) ;
return CodeInvalid ;
}
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
Token untyped_tok = currtok ;
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
while ( left & & currtok . Type ! = TokType : : BraceSquare_Close )
2023-09-03 17:29:45 -07:00
{
2023-09-04 22:44:04 -07:00
eat ( currtok . Type ) ;
}
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
untyped_tok . Length = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) untyped_tok . Text ;
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
Code array_expr = untyped_str ( untyped_tok ) ;
if ( left = = 0 )
{
log_failure ( " Error, unexpected end of array declaration, expected ] \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
2023-09-03 17:29:45 -07:00
}
2023-09-04 22:44:04 -07:00
if ( currtok . Type ! = TokType : : BraceSquare_Close )
2023-09-03 17:29:45 -07:00
{
2023-09-04 22:44:04 -07:00
log_failure ( " %s: Error, expected ] in array declaration, not %s \n %s " , ETokType : : to_str ( currtok . Type ) , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
eat ( TokType : : BraceSquare_Close ) ;
2023-09-05 21:30:34 -07:00
// Its a multi-dimensional array
if ( check ( TokType : : BraceSquare_Open ) )
{
Code adjacent_arr_expr = parse_array_decl ( ) ;
array_expr - > Next = adjacent_arr_expr . ast ;
}
2023-09-04 22:44:04 -07:00
Context . pop ( ) ;
return array_expr ;
}
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
Context . pop ( ) ;
return { nullptr } ;
}
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
internal inline
CodeAttributes parse_attributes ( )
{
using namespace Parser ;
push_scope ( ) ;
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
Token start = NullToken ;
s32 len = 0 ;
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
if ( check ( TokType : : Attribute_Open ) )
{
eat ( TokType : : Attribute_Open ) ;
2023-09-03 17:29:45 -07:00
2023-09-25 09:12:11 -07:00
start = currtok ;
2023-09-04 22:44:04 -07:00
while ( left & & currtok . Type ! = TokType : : Attribute_Close )
2023-09-03 17:29:45 -07:00
{
2023-09-04 22:44:04 -07:00
eat ( currtok . Type ) ;
}
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
eat ( TokType : : Attribute_Close ) ;
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
s32 len = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) start . Text ;
}
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
else if ( check ( TokType : : Decl_GNU_Attribute ) )
{
eat ( TokType : : Capture_Start ) ;
eat ( TokType : : Capture_Start ) ;
2023-09-25 09:12:11 -07:00
start = currtok ;
2023-09-04 22:44:04 -07:00
while ( left & & currtok . Type ! = TokType : : Capture_End )
2023-09-03 17:29:45 -07:00
{
2023-09-04 22:44:04 -07:00
eat ( currtok . Type ) ;
}
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
eat ( TokType : : Capture_End ) ;
eat ( TokType : : Capture_End ) ;
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
s32 len = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) start . Text ;
}
2023-09-03 17:29:45 -07:00
2023-09-04 22:44:04 -07:00
else if ( check ( TokType : : Decl_MSVC_Attribute ) )
{
eat ( TokType : : Decl_MSVC_Attribute ) ;
eat ( TokType : : Capture_Start ) ;
2023-09-03 17:29:45 -07:00
2023-09-25 09:12:11 -07:00
start = currtok ;
2023-09-04 22:44:04 -07:00
while ( left & & currtok . Type ! = TokType : : Capture_End )
{
eat ( currtok . Type ) ;
2023-09-03 17:29:45 -07:00
}
2023-09-04 22:44:04 -07:00
eat ( TokType : : Capture_End ) ;
s32 len = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) start . Text ;
2023-09-03 17:29:45 -07:00
}
2023-09-04 22:44:04 -07:00
else if ( currtok . is_attribute ( ) )
2023-09-03 17:29:45 -07:00
{
2023-09-04 22:44:04 -07:00
eat ( currtok . Type ) ;
s32 len = start . Length ;
2023-09-03 17:29:45 -07:00
}
2023-09-04 22:44:04 -07:00
if ( len > 0 )
{
StrC attribute_txt = { len , start . Text } ;
Context . pop ( ) ;
2023-09-05 21:30:34 -07:00
String name_stripped = strip_formatting ( attribute_txt , strip_formatting_dont_preserve_newlines ) ;
2023-09-04 22:44:04 -07:00
Code
result = make_code ( ) ;
result - > Type = ECode : : PlatformAttributes ;
result - > Name = get_cached_string ( name_stripped ) ;
result - > Content = result - > Name ;
2023-09-25 09:12:11 -07:00
// result->Token =
2023-09-04 22:44:04 -07:00
return ( CodeAttributes ) result ;
}
2023-07-29 22:21:04 -07:00
Context . pop ( ) ;
2023-09-04 22:44:04 -07:00
return { nullptr } ;
2023-07-29 22:21:04 -07:00
}
2023-08-21 20:49:23 -07:00
internal
2023-09-04 22:44:04 -07:00
CodeComment parse_comment ( )
2023-07-29 22:21:04 -07:00
{
using namespace Parser ;
2023-09-04 22:44:04 -07:00
StackNode scope { nullptr , currtok_noskip , NullToken , txt ( __func__ ) } ;
Context . push ( & scope ) ;
2023-08-26 08:55:05 -07:00
2023-09-04 22:44:04 -07:00
CodeComment
result = ( CodeComment ) make_code ( ) ;
result - > Type = ECode : : Comment ;
result - > Content = get_cached_string ( currtok_noskip ) ;
result - > Name = result - > Content ;
2023-09-25 09:12:11 -07:00
// result->Token = currtok_noskip;
2023-09-04 22:44:04 -07:00
eat ( TokType : : Comment ) ;
2023-07-29 22:21:04 -07:00
Context . pop ( ) ;
2023-09-04 22:44:04 -07:00
return result ;
2023-07-29 22:21:04 -07:00
}
2023-08-21 20:49:23 -07:00
internal
2023-09-04 22:44:04 -07:00
Code parse_complicated_definition ( Parser : : TokType which )
2023-07-31 21:42:08 -07:00
{
using namespace Parser ;
push_scope ( ) ;
2023-09-04 22:44:04 -07:00
bool is_inplace = false ;
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
TokArray tokens = Context . Tokens ;
2023-07-31 21:42:08 -07:00
2023-09-04 22:44:04 -07:00
s32 idx = tokens . Idx ;
2023-07-31 21:42:08 -07:00
s32 level = 0 ;
2023-09-04 22:44:04 -07:00
for ( ; idx < tokens . Arr . num ( ) ; idx + + )
2023-07-31 21:42:08 -07:00
{
2023-09-04 22:44:04 -07:00
if ( tokens [ idx ] . Type = = TokType : : BraceCurly_Open )
2023-07-31 21:42:08 -07:00
level + + ;
2023-09-04 22:44:04 -07:00
if ( tokens [ idx ] . Type = = TokType : : BraceCurly_Close )
2023-07-31 21:42:08 -07:00
level - - ;
2023-09-04 22:44:04 -07:00
if ( level = = 0 & & tokens [ idx ] . Type = = TokType : : Statement_End )
break ;
2023-07-31 21:42:08 -07:00
}
2023-08-26 08:55:05 -07:00
2023-09-04 22:44:04 -07:00
if ( ( idx - 2 ) = = tokens . Idx )
2023-08-26 08:55:05 -07:00
{
2023-09-04 22:44:04 -07:00
// Its a forward declaration only
return parse_foward_or_definition ( which , is_inplace ) ;
2023-08-26 08:55:05 -07:00
}
2023-08-01 11:02:54 -07:00
2023-09-04 22:44:04 -07:00
Token tok = tokens [ idx - 1 ] ;
if ( tok . Type = = TokType : : Identifier )
2023-08-02 09:39:35 -07:00
{
2023-09-04 22:44:04 -07:00
tok = tokens [ idx - 2 ] ;
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
bool is_indirection = tok . Type = = TokType : : Ampersand
| | tok . Type = = TokType : : Star ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
bool ok_to_parse = false ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( tok . Type = = TokType : : BraceCurly_Close )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
// Its an inplace definition
// <which> <type_identifier> { ... } <identifier>;
ok_to_parse = true ;
is_inplace = true ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
else if ( tok . Type = = TokType : : Identifier & & tokens [ idx - 3 ] . Type = = TokType : : Decl_Struct )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
// Its a variable with type ID using struct namespace.
// <which> <type_identifier> <identifier>;
ok_to_parse = true ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
else if ( is_indirection )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
// Its a indirection type with type ID using struct namespace.
// <which> <type_identifier>* <identifier>;
ok_to_parse = true ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
if ( ! ok_to_parse )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
log_failure ( " Unsupported or bad member definition after struct declaration \n %s " , Context . to_string ( ) ) ;
2023-07-31 21:42:08 -07:00
Context . pop ( ) ;
return CodeInvalid ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
Code result = parse_operator_function_or_variable ( false , { nullptr } , { nullptr } ) ;
2023-07-31 21:42:08 -07:00
Context . pop ( ) ;
2023-09-04 22:44:04 -07:00
return result ;
}
else if ( tok . Type = = TokType : : BraceCurly_Close )
{
// Its a definition
// <which> { ... };
return parse_foward_or_definition ( which , is_inplace ) ;
}
else if ( tok . Type = = TokType : : BraceSquare_Close )
{
// Its an array definition
// <which> <type_identifier> <identifier> [ ... ];
Code result = parse_operator_function_or_variable ( false , { nullptr } , { nullptr } ) ;
Context . pop ( ) ;
return result ;
}
else
{
log_failure ( " Unsupported or bad member definition after struct declaration \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
2023-07-24 14:45:27 -07:00
}
}
2023-09-04 22:44:04 -07:00
internal neverinline
CodeBody parse_class_struct_body ( Parser : : TokType which , Parser : : Token name )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-09-04 22:44:04 -07:00
using namespace ECode ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
eat ( TokType : : BraceCurly_Open ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
CodeBody
result = ( CodeBody ) make_code ( ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( which = = TokType : : Decl_Class )
result - > Type = Class_Body ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
else
result - > Type = Struct_Body ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
while ( left & & currtok_noskip . Type ! = TokType : : BraceCurly_Close )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
Code member = Code : : Invalid ;
CodeAttributes attributes = { nullptr } ;
CodeSpecifiers specifiers = { nullptr } ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
bool expects_function = false ;
Context . Scope - > Start = currtok_noskip ;
if ( currtok_noskip . Type = = TokType : : Preprocess_Hash )
eat ( TokType : : Preprocess_Hash ) ;
switch ( currtok_noskip . Type )
{
case TokType : : NewLine :
member = fmt_newline ;
eat ( TokType : : NewLine ) ;
break ;
case TokType : : Comment :
member = parse_comment ( ) ;
break ;
case TokType : : Access_Public :
member = access_public ;
eat ( TokType : : Access_Public ) ;
eat ( TokType : : Assign_Classifer ) ;
break ;
case TokType : : Access_Protected :
member = access_protected ;
eat ( TokType : : Access_Protected ) ;
eat ( TokType : : Assign_Classifer ) ;
break ;
case TokType : : Access_Private :
member = access_private ;
eat ( TokType : : Access_Private ) ;
eat ( TokType : : Assign_Classifer ) ;
break ;
case TokType : : Decl_Class :
member = parse_complicated_definition ( TokType : : Decl_Class ) ;
break ;
case TokType : : Decl_Enum :
member = parse_complicated_definition ( TokType : : Decl_Enum ) ;
break ;
case TokType : : Decl_Friend :
member = parse_friend ( ) ;
break ;
case TokType : : Decl_Operator :
member = parse_operator_cast ( ) ;
break ;
case TokType : : Decl_Struct :
member = parse_complicated_definition ( TokType : : Decl_Struct ) ;
break ;
case TokType : : Decl_Template :
member = parse_template ( ) ;
break ;
case TokType : : Decl_Typedef :
member = parse_typedef ( ) ;
break ;
case TokType : : Decl_Union :
member = parse_complicated_definition ( TokType : : Decl_Union ) ;
break ;
case TokType : : Decl_Using :
member = parse_using ( ) ;
break ;
case TokType : : Operator :
if ( currtok . Text [ 0 ] ! = ' ~ ' )
{
log_failure ( " Operator token found in global body but not destructor unary negation \n %s " , Context . to_string ( ) ) ;
return CodeInvalid ;
}
member = parse_destructor ( ) ;
break ;
case TokType : : Preprocess_Define :
member = parse_define ( ) ;
break ;
case TokType : : Preprocess_Include :
member = parse_include ( ) ;
break ;
case TokType : : Preprocess_If :
case TokType : : Preprocess_IfDef :
case TokType : : Preprocess_IfNotDef :
case TokType : : Preprocess_ElIf :
member = parse_preprocess_cond ( ) ;
break ;
case TokType : : Preprocess_Macro :
member = parse_simple_preprocess ( TokType : : Preprocess_Macro ) ;
break ;
case TokType : : Preprocess_Pragma :
member = parse_pragma ( ) ;
break ;
case TokType : : Preprocess_Else :
member = preprocess_else ;
eat ( TokType : : Preprocess_Else ) ;
break ;
case TokType : : Preprocess_EndIf :
member = preprocess_endif ;
eat ( TokType : : Preprocess_EndIf ) ;
break ;
case TokType : : Preprocess_Unsupported :
member = parse_simple_preprocess ( TokType : : Preprocess_Unsupported ) ;
break ;
case TokType : : StaticAssert :
member = parse_static_assert ( ) ;
break ;
case TokType : : Attribute_Open :
case TokType : : Decl_GNU_Attribute :
case TokType : : Decl_MSVC_Attribute :
# define Entry( attribute, str ) case TokType::attribute:
GEN_DEFINE_ATTRIBUTE_TOKENS
# undef Entry
{
attributes = parse_attributes ( ) ;
}
//! Fallthrough intended
case TokType : : Spec_Consteval :
case TokType : : Spec_Constexpr :
case TokType : : Spec_Constinit :
case TokType : : Spec_ForceInline :
case TokType : : Spec_Inline :
case TokType : : Spec_Mutable :
case TokType : : Spec_NeverInline :
case TokType : : Spec_Static :
case TokType : : Spec_Volatile :
{
SpecifierT specs_found [ 16 ] { ESpecifier : : NumSpecifiers } ;
s32 NumSpecifiers = 0 ;
while ( left & & currtok . is_specifier ( ) )
{
SpecifierT spec = ESpecifier : : to_type ( currtok ) ;
switch ( spec )
{
case ESpecifier : : Constexpr :
case ESpecifier : : Constinit :
case ESpecifier : : Inline :
case ESpecifier : : ForceInline :
case ESpecifier : : Mutable :
case ESpecifier : : NeverInline :
case ESpecifier : : Static :
case ESpecifier : : Volatile :
break ;
case ESpecifier : : Consteval :
expects_function = true ;
break ;
default :
log_failure ( " Invalid specifier %s for variable \n %s " , ESpecifier : : to_str ( spec ) , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
specs_found [ NumSpecifiers ] = spec ;
NumSpecifiers + + ;
eat ( currtok . Type ) ;
}
if ( NumSpecifiers )
{
specifiers = def_specifiers ( NumSpecifiers , specs_found ) ;
}
if ( currtok . Type = = TokType : : Operator & & currtok . Text [ 0 ] = = ' ~ ' )
{
member = parse_destructor ( specifiers ) ;
break ;
}
if ( currtok . Type = = TokType : : Decl_Operator )
{
member = parse_operator_cast ( specifiers ) ;
break ;
}
}
//! Fallthrough intentional
case TokType : : Identifier :
case TokType : : Spec_Const :
case TokType : : Type_Unsigned :
case TokType : : Type_Signed :
case TokType : : Type_Short :
case TokType : : Type_Long :
case TokType : : Type_char :
case TokType : : Type_int :
case TokType : : Type_double :
{
if ( nexttok . Type = = TokType : : Capture_Start & & name . Length & & currtok . Type = = TokType : : Identifier )
{
if ( str_compare ( name . Text , currtok . Text , name . Length ) = = 0 )
{
member = parse_constructor ( ) ;
break ;
}
}
member = parse_operator_function_or_variable ( expects_function , attributes , specifiers ) ;
}
break ;
default :
Token untyped_tok = currtok ;
while ( left & & currtok . Type ! = TokType : : BraceCurly_Close )
{
untyped_tok . Length = ( ( sptr ) currtok . Text + currtok . Length ) - ( sptr ) untyped_tok . Text ;
eat ( currtok . Type ) ;
}
member = untyped_str ( untyped_tok ) ;
break ;
}
if ( member = = Code : : Invalid )
{
log_failure ( " Failed to parse member \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
result . append ( member ) ;
}
eat ( TokType : : BraceCurly_Close ) ;
Context . pop ( ) ;
return result ;
}
internal
Code parse_class_struct ( Parser : : TokType which , bool inplace_def = false )
{
using namespace Parser ;
if ( which ! = TokType : : Decl_Class & & which ! = TokType : : Decl_Struct )
{
log_failure ( " Error, expected class or struct, not %s \n %s " , ETokType : : to_str ( which ) , Context . to_string ( ) ) ;
return CodeInvalid ;
}
Token name { nullptr , 0 , TokType : : Invalid } ;
AccessSpec access = AccessSpec : : Default ;
CodeType parent = { nullptr } ;
CodeBody body = { nullptr } ;
CodeAttributes attributes = { nullptr } ;
ModuleFlag mflags = ModuleFlag : : None ;
CodeClass result = CodeInvalid ;
if ( check ( TokType : : Module_Export ) )
{
mflags = ModuleFlag : : Export ;
eat ( TokType : : Module_Export ) ;
}
eat ( which ) ;
attributes = parse_attributes ( ) ;
if ( check ( TokType : : Identifier ) )
{
name = parse_identifier ( ) ;
Context . Scope - > Name = name ;
}
local_persist
char interface_arr_mem [ kilobytes ( 4 ) ] { 0 } ;
Array < CodeType > interfaces = Array < CodeType > : : init_reserve ( Arena : : init_from_memory ( interface_arr_mem , kilobytes ( 4 ) ) , 4 ) ;
if ( check ( TokType : : Assign_Classifer ) )
{
eat ( TokType : : Assign_Classifer ) ;
if ( currtok . is_access_specifier ( ) )
{
access = currtok . to_access_specifier ( ) ;
}
Token parent_tok = parse_identifier ( ) ;
parent = def_type ( parent_tok ) ;
while ( check ( TokType : : Comma ) )
{
eat ( TokType : : Access_Public ) ;
if ( currtok . is_access_specifier ( ) )
{
eat ( currtok . Type ) ;
}
Token interface_tok = parse_identifier ( ) ;
interfaces . append ( def_type ( interface_tok ) ) ;
}
}
if ( check ( TokType : : BraceCurly_Open ) )
{
body = parse_class_struct_body ( which , name ) ;
}
CodeComment inline_cmt = NoCode ;
if ( ! inplace_def )
{
Token stmt_end = currtok ;
eat ( TokType : : Statement_End ) ;
if ( currtok_noskip . Type = = TokType : : Comment & & currtok_noskip . Line = = stmt_end . Line )
inline_cmt = parse_comment ( ) ;
}
if ( which = = TokType : : Decl_Class )
result = def_class ( name , body , parent , access , attributes , mflags ) ;
else
result = def_struct ( name , body , ( CodeType ) parent , access , attributes , mflags ) ;
if ( inline_cmt )
result - > InlineCmt = inline_cmt ;
interfaces . free ( ) ;
return result ;
}
internal inline
CodeDefine parse_define ( )
{
using namespace Parser ;
push_scope ( ) ;
eat ( TokType : : Preprocess_Define ) ;
CodeDefine
define = ( CodeDefine ) make_code ( ) ;
define - > Type = ECode : : Preprocess_Define ;
if ( ! check ( TokType : : Identifier ) )
{
log_failure ( " Error, expected identifier after #define \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
Context . Scope - > Name = currtok ;
define - > Name = get_cached_string ( currtok ) ;
eat ( TokType : : Identifier ) ;
if ( ! check ( TokType : : Preprocess_Content ) )
{
log_failure ( " Error, expected content after #define %s \n %s " , define - > Name , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
if ( currtok . Length = = 0 )
{
define - > Content = get_cached_string ( currtok ) ;
eat ( TokType : : Preprocess_Content ) ;
Context . pop ( ) ;
return define ;
}
2023-09-05 21:30:34 -07:00
define - > Content = get_cached_string ( strip_formatting ( currtok , strip_formatting_dont_preserve_newlines ) ) ;
2023-09-04 22:44:04 -07:00
eat ( TokType : : Preprocess_Content ) ;
Context . pop ( ) ;
return define ;
}
internal inline
Code parse_foward_or_definition ( Parser : : TokType which , bool is_inplace )
{
using namespace Parser ;
Code result = CodeInvalid ;
switch ( which )
{
case TokType : : Decl_Class :
result = parse_class ( is_inplace ) ;
Context . pop ( ) ;
return result ;
case TokType : : Decl_Enum :
result = parse_enum ( is_inplace ) ;
Context . pop ( ) ;
return result ;
case TokType : : Decl_Struct :
result = parse_struct ( is_inplace ) ;
Context . pop ( ) ;
return result ;
case TokType : : Decl_Union :
result = parse_union ( is_inplace ) ;
Context . pop ( ) ;
return result ;
default :
log_failure ( " Error, wrong token type given to parse_complicated_definition "
" (only supports class, enum, struct, union) \n %s "
, Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
return CodeInvalid ;
}
// 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
, CodeType ret_type
, Parser : : Token name
)
{
using namespace Parser ;
push_scope ( ) ;
CodeParam params = parse_params ( ) ;
while ( left & & currtok . is_specifier ( ) )
{
if ( specifiers . ast = = nullptr )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
specifiers = def_specifier ( ESpecifier : : to_type ( currtok ) ) ;
eat ( currtok . Type ) ;
continue ;
}
specifiers . append ( ESpecifier : : to_type ( currtok ) ) ;
eat ( currtok . Type ) ;
}
CodeBody body = NoCode ;
CodeComment inline_cmt = NoCode ;
if ( check ( TokType : : BraceCurly_Open ) )
{
body = parse_function_body ( ) ;
if ( body = = Code : : Invalid )
{
Context . pop ( ) ;
return CodeInvalid ;
}
}
else
{
Token stmt_end = currtok ;
eat ( TokType : : Statement_End ) ;
2023-09-07 19:51:15 -07:00
if ( currtok_noskip . Type = = TokType : : Comment & & currtok_noskip . Line = = stmt_end . Line )
2023-09-04 22:44:04 -07:00
inline_cmt = parse_comment ( ) ;
}
using namespace ECode ;
String
name_stripped = String : : make ( GlobalAllocator , name ) ;
name_stripped . strip_space ( ) ;
CodeFn
result = ( CodeFn ) make_code ( ) ;
result - > Name = get_cached_string ( name_stripped ) ;
result - > ModuleFlags = mflags ;
if ( body )
{
switch ( body - > Type )
{
case Function_Body :
case Untyped :
break ;
default :
{
log_failure ( " Body must be either of Function_Body or Untyped type, %s \n %s " , body . debug_str ( ) , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
result - > Type = Function ;
result - > Body = body ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
else
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
result - > Type = Function_Fwd ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
if ( specifiers )
result - > Specs = specifiers ;
2023-08-26 08:55:05 -07:00
2023-09-04 22:44:04 -07:00
result - > ReturnType = ret_type ;
2023-08-26 08:55:05 -07:00
2023-09-04 22:44:04 -07:00
if ( params )
result - > Params = params ;
2023-08-26 08:55:05 -07:00
2023-09-04 22:44:04 -07:00
if ( inline_cmt )
result - > InlineCmt = inline_cmt ;
2023-07-24 14:45:27 -07:00
2023-07-29 03:32:16 -07:00
Context . pop ( ) ;
2023-09-04 22:44:04 -07:00
return result ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
internal
Code parse_function_body ( )
2023-09-03 20:36:51 -07:00
{
using namespace Parser ;
2023-09-04 22:44:04 -07:00
using namespace ECode ;
push_scope ( ) ;
2023-09-03 20:36:51 -07:00
2023-09-04 22:44:04 -07:00
eat ( TokType : : BraceCurly_Open ) ;
CodeBody
result = ( CodeBody ) make_code ( ) ;
result - > Type = Function_Body ;
2023-09-05 23:09:26 -07:00
// TODO : Support actual parsing of function body
2023-09-04 22:44:04 -07:00
Token start = currtok ;
s32 level = 0 ;
while ( left & & ( currtok . Type ! = TokType : : BraceCurly_Close | | level > 0 ) )
2023-09-03 20:36:51 -07:00
{
2023-09-04 22:44:04 -07:00
if ( currtok . Type = = TokType : : BraceCurly_Open )
level + + ;
2023-09-03 20:36:51 -07:00
2023-09-04 22:44:04 -07:00
else if ( currtok . Type = = TokType : : BraceCurly_Close & & level > 0 )
level - - ;
2023-09-03 20:36:51 -07:00
2023-09-04 22:44:04 -07:00
eat ( currtok . Type ) ;
}
2023-09-03 20:36:51 -07:00
2023-09-04 22:44:04 -07:00
Token previous = prevtok ;
2023-09-03 20:36:51 -07:00
2023-09-04 22:44:04 -07:00
s32 len = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) start . Text ;
2023-09-03 20:36:51 -07:00
2023-09-04 22:44:04 -07:00
if ( len > 0 )
{
result . append ( def_execution ( { len , start . Text } ) ) ;
2023-09-03 20:36:51 -07:00
}
2023-09-04 22:44:04 -07:00
eat ( TokType : : BraceCurly_Close ) ;
Context . pop ( ) ;
return result ;
2023-09-03 20:36:51 -07:00
}
2023-09-04 22:44:04 -07:00
internal neverinline
CodeBody parse_global_nspace ( CodeT which )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-09-04 22:44:04 -07:00
using namespace ECode ;
2023-07-29 02:52:06 -07:00
2023-09-04 22:44:04 -07:00
if ( which ! = Namespace_Body & & which ! = Global_Body & & which ! = Export_Body & & which ! = Extern_Linkage_Body )
return CodeInvalid ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( which ! = Global_Body )
eat ( TokType : : BraceCurly_Open ) ;
2023-09-03 20:36:51 -07:00
2023-09-04 22:44:04 -07:00
CodeBody
result = ( CodeBody ) make_code ( ) ;
result - > Type = which ;
while ( left & & currtok_noskip . Type ! = TokType : : BraceCurly_Close )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
Code member = Code : : Invalid ;
CodeAttributes attributes = { nullptr } ;
CodeSpecifiers specifiers = { nullptr } ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
bool expects_function = false ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Context . Scope - > Start = currtok_noskip ;
if ( currtok_noskip . Type = = TokType : : Preprocess_Hash )
eat ( TokType : : Preprocess_Hash ) ;
switch ( currtok_noskip . Type )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
case TokType : : NewLine :
// Empty lines are auto skipped by Tokens.current()
member = fmt_newline ;
eat ( TokType : : NewLine ) ;
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
case TokType : : Comment :
member = parse_comment ( ) ;
break ;
2023-07-29 10:15:53 -07:00
2023-09-04 22:44:04 -07:00
case TokType : : Decl_Class :
member = parse_complicated_definition ( TokType : : Decl_Class ) ;
break ;
2023-07-29 02:52:06 -07:00
2023-09-04 22:44:04 -07:00
case TokType : : Decl_Enum :
member = parse_complicated_definition ( TokType : : Decl_Enum ) ;
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
case TokType : : Decl_Extern_Linkage :
if ( which = = Extern_Linkage_Body )
log_failure ( " Nested extern linkage \n %s " , Context . to_string ( ) ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
member = parse_extern_link_body ( ) ;
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
case TokType : : Decl_Namespace :
member = parse_namespace ( ) ;
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
case TokType : : Decl_Struct :
member = parse_complicated_definition ( TokType : : Decl_Struct ) ;
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
case TokType : : Decl_Template :
member = parse_template ( ) ;
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
case TokType : : Decl_Typedef :
member = parse_typedef ( ) ;
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
case TokType : : Decl_Union :
member = parse_complicated_definition ( TokType : : Decl_Union ) ;
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
case TokType : : Decl_Using :
member = parse_using ( ) ;
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
case TokType : : Preprocess_Define :
member = parse_define ( ) ;
break ;
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
case TokType : : Preprocess_Include :
member = parse_include ( ) ;
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
case TokType : : Preprocess_If :
case TokType : : Preprocess_IfDef :
case TokType : : Preprocess_IfNotDef :
case TokType : : Preprocess_ElIf :
member = parse_preprocess_cond ( ) ;
break ;
case TokType : : Preprocess_Macro :
member = parse_simple_preprocess ( TokType : : Preprocess_Macro ) ;
break ;
case TokType : : Preprocess_Pragma :
member = parse_pragma ( ) ;
break ;
case TokType : : Preprocess_Else :
member = preprocess_else ;
eat ( TokType : : Preprocess_Else ) ;
break ;
case TokType : : Preprocess_EndIf :
member = preprocess_endif ;
eat ( TokType : : Preprocess_EndIf ) ;
break ;
case TokType : : Preprocess_Unsupported :
member = parse_simple_preprocess ( TokType : : Preprocess_Unsupported ) ;
break ;
case TokType : : StaticAssert :
member = parse_static_assert ( ) ;
break ;
case TokType : : Module_Export :
if ( which = = Export_Body )
log_failure ( " Nested export declaration \n %s " , Context . to_string ( ) ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
member = parse_export_body ( ) ;
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
case TokType : : Module_Import :
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
not_implemented ( context ) ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
//! Fallthrough intentional
case TokType : : Decl_GNU_Attribute :
case TokType : : Decl_MSVC_Attribute :
# define Entry( attribute, str ) case TokType::attribute:
GEN_DEFINE_ATTRIBUTE_TOKENS
# undef Entry
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
attributes = parse_attributes ( ) ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
//! Fallthrough intentional
case TokType : : Spec_Consteval :
case TokType : : Spec_Constexpr :
case TokType : : Spec_Constinit :
case TokType : : Spec_Extern :
case TokType : : Spec_ForceInline :
case TokType : : Spec_Global :
case TokType : : Spec_Inline :
case TokType : : Spec_Internal_Linkage :
case TokType : : Spec_NeverInline :
case TokType : : Spec_Static :
{
SpecifierT specs_found [ 16 ] { ESpecifier : : NumSpecifiers } ;
s32 NumSpecifiers = 0 ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
while ( left & & currtok . is_specifier ( ) )
{
SpecifierT spec = ESpecifier : : to_type ( currtok ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
bool ignore_spec = false ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
switch ( spec )
{
case ESpecifier : : Constexpr :
case ESpecifier : : Constinit :
case ESpecifier : : ForceInline :
case ESpecifier : : Global :
case ESpecifier : : External_Linkage :
case ESpecifier : : Internal_Linkage :
case ESpecifier : : Inline :
case ESpecifier : : Mutable :
case ESpecifier : : NeverInline :
case ESpecifier : : Static :
case ESpecifier : : Volatile :
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
case ESpecifier : : Consteval :
expects_function = true ;
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
case ESpecifier : : Const :
ignore_spec = true ;
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
default :
StrC spec_str = ESpecifier : : to_str ( spec ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
log_failure ( " Invalid specifier %.*s for variable \n %s " , spec_str . Len , spec_str , Context . to_string ( ) ) ;
return CodeInvalid ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( ignore_spec )
break ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
specs_found [ NumSpecifiers ] = spec ;
NumSpecifiers + + ;
eat ( currtok . Type ) ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( NumSpecifiers )
{
specifiers = def_specifiers ( NumSpecifiers , specs_found ) ;
}
}
//! Fallthrough intentional
case TokType : : Identifier :
case TokType : : Spec_Const :
case TokType : : Type_Long :
case TokType : : Type_Short :
case TokType : : Type_Signed :
case TokType : : Type_Unsigned :
case TokType : : Type_char :
case TokType : : Type_double :
case TokType : : Type_int :
{
bool found_operator_cast = false ;
s32 idx = Context . Tokens . Idx ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
for ( ; idx < Context . Tokens . Arr . num ( ) ; idx + + )
{
Token tok = Context . Tokens [ idx ] ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( tok . Type = = TokType : : Identifier )
{
idx + + ;
tok = Context . Tokens [ idx ] ;
if ( tok . Type = = TokType : : Access_StaticSymbol )
continue ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
break ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( tok . Type = = TokType : : Decl_Operator )
found_operator_cast = true ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
break ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
if ( found_operator_cast )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
member = parse_operator_cast ( ) ;
break ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
member = parse_operator_function_or_variable ( expects_function , attributes , specifiers ) ;
2023-07-24 14:45:27 -07:00
}
}
2023-09-04 22:44:04 -07:00
if ( member = = Code : : Invalid )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
log_failure ( " Failed to parse member \n %s " , Context . to_string ( ) ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
}
2023-09-04 22:44:04 -07:00
// log_fmt("Global Body Member: %s", member->debug_str());
result . append ( member ) ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
if ( which ! = Global_Body )
eat ( TokType : : BraceCurly_Close ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
2023-09-04 22:44:04 -07:00
internal
Parser : : Token parse_identifier ( bool * possible_member_function )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Token name = currtok ;
Context . Scope - > Name = name ;
eat ( TokType : : Identifier ) ;
2023-08-26 08:55:05 -07:00
2023-09-04 22:44:04 -07:00
parse_template_args ( name ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
while ( check ( TokType : : Access_StaticSymbol ) )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
eat ( TokType : : Access_StaticSymbol ) ;
if ( left = = 0 )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
log_failure ( " Error, unexpected end of static symbol identifier \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return { nullptr , 0 , TokType : : Invalid } ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok . Type = = TokType : : Operator & & currtok . Text [ 0 ] = = ' * ' & & currtok . Length = = 1 )
{
if ( possible_member_function )
* possible_member_function = true ;
else
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
log_failure ( " Found a member function pointer identifier but the parsing context did not expect it \n %s " , Context . to_string ( ) ) ;
2023-07-31 21:42:08 -07:00
Context . pop ( ) ;
2023-09-04 22:44:04 -07:00
return { nullptr , 0 , TokType : : Invalid } ;
2023-07-24 14:45:27 -07:00
}
}
2023-09-04 22:44:04 -07:00
if ( currtok . Type ! = TokType : : Identifier )
{
log_failure ( " Error, expected static symbol identifier, not %s \n %s " , ETokType : : to_str ( currtok . Type ) , Context . to_string ( ) ) ;
Context . pop ( ) ;
return { nullptr , 0 , TokType : : Invalid } ;
}
name . Length = ( ( sptr ) currtok . Text + currtok . Length ) - ( sptr ) name . Text ;
eat ( TokType : : Identifier ) ;
parse_template_args ( name ) ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
Context . pop ( ) ;
return name ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
internal
CodeInclude parse_include ( )
{
using namespace Parser ;
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
CodeInclude
include = ( CodeInclude ) make_code ( ) ;
include - > Type = ECode : : Preprocess_Include ;
eat ( TokType : : Preprocess_Include ) ;
2023-08-22 23:17:47 -07:00
2023-09-04 22:44:04 -07:00
if ( ! check ( TokType : : String ) )
{
log_failure ( " Error, expected include string after #include \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
Context . Scope - > Name = currtok ;
include - > Content = get_cached_string ( currtok ) ;
eat ( TokType : : String ) ;
2023-07-24 14:45:27 -07:00
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-09-04 22:44:04 -07:00
return include ;
2023-07-24 14:45:27 -07:00
}
2023-08-21 20:49:23 -07:00
internal
2023-07-29 02:52:06 -07:00
CodeOperator parse_operator_after_ret_type (
ModuleFlag mflags
2023-07-24 14:45:27 -07:00
, CodeAttributes attributes
2023-07-29 02:52:06 -07:00
, CodeSpecifiers specifiers
2023-07-24 14:45:27 -07:00
, CodeType ret_type
2023-07-28 18:44:31 -07:00
)
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
using namespace EOperator ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-08-02 09:39:35 -07:00
Token nspace = NullToken ;
if ( check ( TokType : : Identifier ) )
{
nspace = currtok ;
while ( left & & currtok . Type = = TokType : : Identifier )
{
eat ( TokType : : Identifier ) ;
if ( currtok . Type = = TokType : : Access_StaticSymbol )
eat ( TokType : : Access_StaticSymbol ) ;
}
nspace . Length = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) nspace . Text ;
}
2023-07-24 14:45:27 -07:00
eat ( TokType : : Decl_Operator ) ;
2023-08-01 11:02:54 -07:00
if ( ! left & & currtok . Type ! = TokType : : Operator
& & currtok . Type ! = TokType : : Star
& & currtok . Type ! = TokType : : Ampersand
& & currtok . Type ! = TokType : : Ampersand_DBL )
2023-07-24 14:45:27 -07:00
{
2023-07-29 02:52:06 -07:00
log_failure ( " Expected operator after 'operator' keyword \n %s " , Context . to_string ( ) ) ;
2023-07-31 21:42:08 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
}
2023-08-02 09:39:35 -07:00
Context . Scope - > Name = currtok ;
2023-07-24 14:45:27 -07:00
OperatorT op = Invalid ;
switch ( currtok . Text [ 0 ] )
{
case ' + ' :
{
if ( currtok . Text [ 1 ] = = ' = ' )
op = Assign_Add ;
2023-08-01 11:02:54 -07:00
if ( currtok . Text [ 1 ] = = ' + ' )
op = Increment ;
2023-07-24 14:45:27 -07:00
else
op = Add ;
}
break ;
case ' - ' :
{
2023-08-01 11:02:54 -07:00
if ( currtok . Text [ 1 ] = = ' > ' )
{
if ( currtok . Text [ 2 ] = = ' * ' )
op = MemberOfPointer ;
else
op = MemberOfPointer ;
break ;
}
2023-07-24 14:45:27 -07:00
if ( currtok . Text [ 1 ] = = ' = ' )
op = Assign_Subtract ;
else
op = Subtract ;
}
break ;
case ' * ' :
{
if ( currtok . Text [ 1 ] = = ' = ' )
op = Assign_Multiply ;
else
{
Token & finder = prevtok ;
while ( finder . Type ! = TokType : : Decl_Operator )
{
if ( finder . Type = = TokType : : Identifier )
{
op = Indirection ;
break ;
}
}
if ( op = = Invalid )
op = Multiply ;
}
}
break ;
case ' / ' :
{
if ( currtok . Text [ 1 ] = = ' = ' )
op = Assign_Divide ;
else
op = Divide ;
}
break ;
case ' % ' :
{
if ( currtok . Text [ 1 ] = = ' = ' )
op = Assign_Modulo ;
else
op = Modulo ;
}
break ;
case ' & ' :
{
if ( currtok . Text [ 1 ] = = ' = ' )
op = Assign_BAnd ;
else if ( currtok . Text [ 1 ] = = ' & ' )
op = LAnd ;
else
{
if ( op = = Invalid )
op = BAnd ;
}
}
break ;
case ' | ' :
{
if ( currtok . Text [ 1 ] = = ' = ' )
op = Assign_BOr ;
else if ( currtok . Text [ 1 ] = = ' | ' )
op = LOr ;
else
op = BOr ;
}
break ;
case ' ^ ' :
{
if ( currtok . Text [ 1 ] = = ' = ' )
op = Assign_BXOr ;
else
op = BXOr ;
}
break ;
case ' ~ ' :
{
op = BNot ;
}
break ;
case ' ! ' :
{
if ( currtok . Text [ 1 ] = = ' = ' )
op = LNot ;
else
op = UnaryNot ;
}
break ;
case ' = ' :
{
if ( currtok . Text [ 1 ] = = ' = ' )
op = LEqual ;
else
op = Assign ;
}
break ;
case ' < ' :
{
if ( currtok . Text [ 1 ] = = ' = ' )
op = LEqual ;
else if ( currtok . Text [ 1 ] = = ' < ' )
{
if ( currtok . Text [ 2 ] = = ' = ' )
op = Assign_LShift ;
else
op = LShift ;
}
else
op = Lesser ;
}
break ;
case ' > ' :
{
if ( currtok . Text [ 1 ] = = ' = ' )
op = GreaterEqual ;
else if ( currtok . Text [ 1 ] = = ' > ' )
{
if ( currtok . Text [ 2 ] = = ' = ' )
op = Assign_RShift ;
else
op = RShift ;
}
else
op = Greater ;
}
break ;
case ' ( ' :
{
if ( currtok . Text [ 1 ] = = ' ) ' )
op = FunctionCall ;
else
op = Invalid ;
}
break ;
case ' [ ' :
{
if ( currtok . Text [ 1 ] = = ' ] ' )
op = Subscript ;
2023-09-04 22:44:04 -07:00
else
op = Invalid ;
}
break ;
default :
{
break ;
}
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( op = = Invalid )
{
log_failure ( " Invalid operator '%s' \n %s " , currtok . Text , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
eat ( currtok . Type ) ;
2023-08-01 13:07:47 -07:00
2023-09-04 22:44:04 -07:00
// Parse Params
CodeParam params = parse_params ( ) ;
2023-08-01 13:07:47 -07:00
2023-09-04 22:44:04 -07:00
if ( params . ast = = nullptr & & op = = EOperator : : Multiply )
op = MemberOfPointer ;
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
while ( left & & currtok . is_specifier ( ) )
{
if ( specifiers . ast = = nullptr )
2023-08-02 09:39:35 -07:00
{
2023-09-04 22:44:04 -07:00
specifiers = def_specifier ( ESpecifier : : to_type ( currtok ) ) ;
2023-08-02 09:39:35 -07:00
eat ( currtok . Type ) ;
2023-09-04 22:44:04 -07:00
continue ;
2023-08-02 09:39:35 -07:00
}
2023-09-04 22:44:04 -07:00
specifiers . append ( ESpecifier : : to_type ( currtok ) ) ;
eat ( currtok . Type ) ;
}
2023-08-22 23:17:47 -07:00
2023-09-04 22:44:04 -07:00
// Parse Body
CodeBody body = { nullptr } ;
CodeComment inline_cmt = NoCode ;
if ( check ( TokType : : BraceCurly_Open ) )
{
body = parse_function_body ( ) ;
if ( body = = Code : : Invalid )
{
Context . pop ( ) ;
return CodeInvalid ;
2023-08-21 17:30:13 -07:00
}
}
else
{
2023-09-04 22:44:04 -07:00
Token stmt_end = currtok ;
eat ( TokType : : Statement_End ) ;
2023-08-21 17:30:13 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok_noskip . Type = = TokType : : Comment & & currtok_noskip . Line = = stmt_end . Line )
inline_cmt = parse_comment ( ) ;
2023-08-02 09:39:35 -07:00
}
2023-09-04 22:44:04 -07:00
// OpValidateResult check_result = operator__validate( op, params, ret_type, specifiers );
CodeOperator result = def_operator ( op , nspace , params , ret_type , body , specifiers , attributes , mflags ) ;
2023-08-08 19:14:58 -07:00
2023-09-04 22:44:04 -07:00
if ( inline_cmt )
result - > InlineCmt = inline_cmt ;
2023-08-02 09:39:35 -07:00
2023-08-01 13:07:47 -07:00
Context . pop ( ) ;
return result ;
}
2023-08-21 20:49:23 -07:00
internal
2023-07-28 18:44:31 -07:00
Code parse_operator_function_or_variable ( bool expects_function , CodeAttributes attributes , CodeSpecifiers specifiers )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-07-31 21:42:08 -07:00
Code result = CodeInvalid ;
2023-07-24 14:45:27 -07:00
2023-08-22 23:17:47 -07:00
# ifndef GEN_PARSER_DISABLE_MACRO_FUNCTION_SIGNATURES
2023-08-02 09:39:35 -07:00
if ( currtok . Type = = TokType : : Preprocess_Macro )
{
// Were dealing with a macro after attributes/specifiers.
result = parse_simple_preprocess ( TokType : : Preprocess_Macro ) ;
Context . pop ( ) ;
return result ;
}
2023-08-22 23:17:47 -07:00
# endif
2023-08-02 09:39:35 -07:00
2023-07-29 03:32:16 -07:00
CodeType type = parse_type ( ) ;
2023-07-24 14:45:27 -07:00
2023-07-31 21:42:08 -07:00
if ( type = = CodeInvalid )
{
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
2023-07-31 21:42:08 -07:00
}
2023-07-24 14:45:27 -07:00
2023-08-02 09:39:35 -07:00
bool found_operator = false ;
s32 idx = Context . Tokens . Idx ;
for ( ; idx < Context . Tokens . Arr . num ( ) ; idx + + )
{
Token tok = Context . Tokens [ idx ] ;
if ( tok . Type = = TokType : : Identifier )
{
idx + + ;
tok = Context . Tokens [ idx ] ;
if ( tok . Type = = TokType : : Access_StaticSymbol )
continue ;
break ;
}
if ( tok . Type = = TokType : : Decl_Operator )
found_operator = true ;
break ;
}
if ( found_operator )
2023-07-24 14:45:27 -07:00
{
// Dealing with an operator overload
2023-07-29 02:52:06 -07:00
result = parse_operator_after_ret_type ( ModuleFlag : : None , attributes , specifiers , type ) ;
2023-07-24 14:45:27 -07:00
}
else
2023-09-04 22:44:04 -07:00
{
Token name = parse_identifier ( ) ;
Context . Scope - > Name = name ;
if ( check ( TokType : : Capture_Start ) )
{
// Dealing with a function
result = parse_function_after_name ( ModuleFlag : : None , attributes , specifiers , type , name ) ;
}
else
{
if ( expects_function )
{
log_failure ( " Expected function declaration (consteval was used) \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
// Dealing with a variable
result = parse_variable_after_name ( ModuleFlag : : None , attributes , specifiers , type , name ) ;
}
2023-08-01 02:17:24 -07:00
}
2023-09-04 22:44:04 -07:00
Context . pop ( ) ;
return result ;
2023-08-01 02:17:24 -07:00
}
2023-09-04 22:44:04 -07:00
internal
CodePragma parse_pragma ( )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
CodePragma
pragma = ( CodePragma ) make_code ( ) ;
pragma - > Type = ECode : : Preprocess_Pragma ;
eat ( TokType : : Preprocess_Pragma ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( ! check ( TokType : : Preprocess_Content ) )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
log_failure ( " Error, expected content after #pragma \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
2023-08-04 13:12:13 -07:00
2023-09-04 22:44:04 -07:00
Context . Scope - > Name = currtok ;
2023-08-06 10:28:19 -07:00
2023-09-05 21:30:34 -07:00
pragma - > Content = get_cached_string ( currtok ) ;
2023-09-04 22:44:04 -07:00
eat ( TokType : : Preprocess_Content ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Context . pop ( ) ;
return pragma ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
internal inline
CodeParam parse_params ( bool use_template_capture )
{
using namespace Parser ;
using namespace ECode ;
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( ! use_template_capture )
eat ( TokType : : Capture_Start ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
else
{
if ( check ( TokType : : Operator ) & & currtok . Text [ 0 ] = = ' < ' )
eat ( TokType : : Operator ) ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( ! use_template_capture & & check ( TokType : : Capture_End ) )
{
eat ( TokType : : Capture_End ) ;
Context . pop ( ) ;
return { nullptr } ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
CodeType type = { nullptr } ;
Code value = { nullptr } ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( check ( TokType : : Varadic_Argument ) )
{
eat ( TokType : : Varadic_Argument ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Context . pop ( ) ;
return param_varadic ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
type = parse_type ( ) ;
if ( type = = Code : : Invalid )
{
Context . pop ( ) ;
return CodeInvalid ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Token name = NullToken ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( check ( TokType : : Identifier ) )
{
name = currtok ;
eat ( TokType : : Identifier ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok . IsAssign )
{
eat ( TokType : : Operator ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Token value_tok = currtok ;
2023-08-07 00:10:45 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok . Type = = TokType : : Comma )
{
log_failure ( " Expected value after assignment operator \n %s. " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
2023-08-07 00:10:45 -07:00
2023-09-04 22:44:04 -07:00
while ( left
& & currtok . Type ! = TokType : : Comma
& & currtok . Type ! = TokType : : Capture_End
)
{
value_tok . Length = ( ( sptr ) currtok . Text + currtok . Length ) - ( sptr ) value_tok . Text ;
eat ( currtok . Type ) ;
}
2023-07-29 22:21:04 -07:00
2023-09-05 21:30:34 -07:00
value = untyped_str ( strip_formatting ( value_tok , strip_formatting_dont_preserve_newlines ) ) ;
2023-09-04 22:44:04 -07:00
}
}
2023-07-29 22:21:04 -07:00
2023-09-04 22:44:04 -07:00
CodeParam
result = ( CodeParam ) make_code ( ) ;
result - > Type = Parameters ;
2023-07-29 22:21:04 -07:00
2023-09-04 22:44:04 -07:00
if ( name . Length > 0 )
result - > Name = get_cached_string ( name ) ;
2023-07-30 15:55:57 -07:00
2023-09-04 22:44:04 -07:00
result - > ValueType = type ;
2023-07-29 22:21:04 -07:00
2023-09-04 22:44:04 -07:00
if ( value )
result - > Value = value ;
2023-07-29 22:21:04 -07:00
2023-09-04 22:44:04 -07:00
result - > NumEntries + + ;
2023-07-29 22:21:04 -07:00
2023-09-04 22:44:04 -07:00
while ( left
& & use_template_capture ?
currtok . Type ! = TokType : : Operator & & currtok . Text [ 0 ] ! = ' > '
: currtok . Type ! = TokType : : Capture_End )
{
eat ( TokType : : Comma ) ;
2023-07-31 21:42:08 -07:00
2023-09-04 22:44:04 -07:00
Code type = { nullptr } ;
Code value = { nullptr } ;
2023-07-31 21:42:08 -07:00
2023-09-04 22:44:04 -07:00
if ( check ( TokType : : Varadic_Argument ) )
{
eat ( TokType : : Varadic_Argument ) ;
result . append ( param_varadic ) ;
continue ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
type = parse_type ( ) ;
if ( type = = Code : : Invalid )
{
Context . pop ( ) ;
return CodeInvalid ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
name = { nullptr , 0 , TokType : : Invalid , false } ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( check ( TokType : : Identifier ) )
{
name = currtok ;
eat ( TokType : : Identifier ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok . IsAssign )
{
eat ( TokType : : Operator ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Token value_tok = currtok ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok . Type = = TokType : : Comma )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
log_failure ( " Expected value after assignment operator \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
2023-07-24 14:45:27 -07:00
}
2023-08-07 00:10:45 -07:00
2023-09-04 22:44:04 -07:00
while ( left
& & currtok . Type ! = TokType : : Comma & & currtok . Type ! = TokType : : Capture_End
)
2023-08-07 00:10:45 -07:00
{
2023-09-04 22:44:04 -07:00
value_tok . Length = ( ( sptr ) currtok . Text + currtok . Length ) - ( sptr ) value_tok . Text ;
eat ( currtok . Type ) ;
2023-08-07 00:10:45 -07:00
}
2023-08-21 17:30:13 -07:00
2023-09-05 21:30:34 -07:00
value = untyped_str ( strip_formatting ( value_tok , strip_formatting_dont_preserve_newlines ) ) ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
}
2023-08-07 00:10:45 -07:00
2023-09-04 22:44:04 -07:00
CodeParam
param = ( CodeParam ) make_code ( ) ;
param - > Type = Parameters ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( name . Length > 0 )
param - > Name = get_cached_string ( name ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
param - > ValueType = type ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( value )
param - > Value = value ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
result . append ( param ) ;
}
if ( ! use_template_capture )
eat ( TokType : : Capture_End ) ;
else
{
if ( ! check ( TokType : : Operator ) | | currtok . Text [ 0 ] ! = ' > ' )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
log_failure ( " Expected '<' after 'template' keyword \n %s " , Context . to_string ( ) ) ;
2023-07-31 21:42:08 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
}
2023-09-04 22:44:04 -07:00
eat ( TokType : : Operator ) ;
2023-07-24 14:45:27 -07:00
}
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
2023-09-04 22:44:04 -07:00
# undef context
2023-07-24 14:45:27 -07:00
}
internal
2023-09-04 22:44:04 -07:00
CodePreprocessCond parse_preprocess_cond ( )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-09-04 22:44:04 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( ! currtok . is_preprocess_cond ( ) )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
log_failure ( " Error, expected preprocess conditional \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
}
2023-09-04 22:44:04 -07:00
CodePreprocessCond
cond = ( CodePreprocessCond ) make_code ( ) ;
cond - > Type = scast ( CodeT , currtok . Type - ( ETokType : : Preprocess_If - ECode : : Preprocess_If ) ) ;
eat ( currtok . Type ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( ! check ( TokType : : Preprocess_Content ) )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
log_failure ( " Error, expected content after #define \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
Context . Scope - > Name = currtok ;
cond - > Content = get_cached_string ( currtok ) ;
eat ( TokType : : Preprocess_Content ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Context . pop ( ) ;
return cond ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
internal inline
Code parse_simple_preprocess ( Parser : : TokType which )
{
using namespace Parser ;
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Token tok = currtok ;
eat ( which ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok . Type = = TokType : : BraceCurly_Open )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
// Eat the block scope right after the macro. Were assuming the macro defines a function definition's signature
eat ( TokType : : BraceCurly_Open ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
s32 level = 0 ;
while ( left & & ( currtok . Type ! = TokType : : BraceCurly_Close | | level > 0 ) )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
if ( currtok . Type = = TokType : : BraceCurly_Open )
level + + ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
else if ( currtok . Type = = TokType : : BraceCurly_Close & & level > 0 )
level - - ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
eat ( currtok . Type ) ;
}
eat ( TokType : : BraceCurly_Close ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
StrC prev_proc = Context . Scope - > Prev - > ProcName ;
if ( str_compare ( prev_proc . Ptr , " parse_typedef " , prev_proc . Len ) ! = 0 )
{
if ( check ( TokType : : Statement_End ) )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
Token stmt_end = currtok ;
eat ( TokType : : Statement_End ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok_noskip . Type = = TokType : : Comment & & currtok_noskip . Line = = stmt_end . Line )
eat ( TokType : : Comment ) ;
}
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
tok . Length = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) tok . Text ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
else
2023-08-22 21:05:58 -07:00
{
2023-09-04 22:44:04 -07:00
if ( str_compare ( Context . Scope - > Prev - > ProcName . Ptr , " parse_typedef " , Context . Scope - > Prev - > ProcName . Len ) ! = 0 )
{
if ( check ( TokType : : Statement_End ) )
{
Token stmt_end = currtok ;
eat ( TokType : : Statement_End ) ;
2023-08-23 15:16:45 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok_noskip . Type = = TokType : : Comment & & currtok_noskip . Line = = stmt_end . Line )
eat ( TokType : : Comment ) ;
}
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
tok . Length = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) tok . Text ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
char const * content = str_fmt_buf ( " %.*s " , tok . Length , tok . Text ) ;
2023-08-23 15:16:45 -07:00
2023-09-04 22:44:04 -07:00
Code result = untyped_str ( to_str ( content ) ) ;
Context . Scope - > Name = tok ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
internal
2023-09-04 22:44:04 -07:00
Code parse_static_assert ( )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Code
assert = make_code ( ) ;
assert - > Type = ECode : : Untyped ;
Token content = currtok ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Context . Scope - > Name = content ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
eat ( TokType : : StaticAssert ) ;
eat ( TokType : : Capture_Start ) ;
2023-07-24 14:45:27 -07:00
s32 level = 0 ;
2023-09-04 22:44:04 -07:00
while ( left & & ( currtok . Type ! = TokType : : Capture_End | | level > 0 ) )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
if ( currtok . Type = = TokType : : Capture_Start )
2023-07-24 14:45:27 -07:00
level + + ;
2023-09-04 22:44:04 -07:00
else if ( currtok . Type = = TokType : : Capture_End )
2023-07-24 14:45:27 -07:00
level - - ;
eat ( currtok . Type ) ;
}
2023-09-04 22:44:04 -07:00
eat ( TokType : : Capture_End ) ;
eat ( TokType : : Statement_End ) ;
2023-07-24 14:45:27 -07:00
2023-09-07 19:51:15 -07: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 } ) ;
2023-09-04 22:44:04 -07:00
assert - > Name = assert - > Content ;
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-09-04 22:44:04 -07:00
return assert ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
/*
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 ( Parser : : Token & token )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-09-04 22:44:04 -07:00
if ( currtok . Type = = TokType : : Operator & & currtok . Text [ 0 ] = = ' < ' & & currtok . Length = = 1 )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
eat ( TokType : : Operator ) ;
2023-08-06 10:28:19 -07:00
2023-09-04 22:44:04 -07:00
s32 level = 0 ;
while ( left & & ( currtok . Text [ 0 ] ! = ' > ' | | level > 0 ) )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
if ( currtok . Text [ 0 ] = = ' < ' )
level + + ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok . Text [ 0 ] = = ' > ' )
level - - ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
eat ( currtok . Type ) ;
}
2023-07-29 22:21:04 -07:00
2023-09-04 22:44:04 -07:00
eat ( TokType : : Operator ) ;
2023-07-29 22:21:04 -07:00
2023-09-04 22:44:04 -07:00
// Extend length of name to last token
token . Length = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) token . Text ;
}
}
2023-07-29 22:21:04 -07:00
2023-09-04 22:44:04 -07: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
, CodeType type
, StrC name
)
{
using namespace Parser ;
push_scope ( ) ;
2023-07-30 15:55:57 -07:00
2023-09-04 22:44:04 -07:00
Code array_expr = parse_array_decl ( ) ;
Code expr = { nullptr } ;
Code bitfield_expr = { nullptr } ;
2023-07-29 22:21:04 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok . IsAssign )
{
eat ( TokType : : Operator ) ;
2023-07-29 22:21:04 -07:00
2023-09-04 22:44:04 -07:00
Token expr_tok = currtok ;
2023-07-29 22:21:04 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok . Type = = TokType : : Statement_End )
{
log_failure ( " Expected expression after assignment operator \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
2023-07-31 21:42:08 -07:00
2023-09-04 22:44:04 -07:00
while ( left & & currtok . Type ! = TokType : : Statement_End )
{
eat ( currtok . Type ) ;
}
2023-07-31 21:42:08 -07:00
2023-09-04 22:44:04 -07:00
expr_tok . Length = ( ( sptr ) currtok . Text + currtok . Length ) - ( sptr ) expr_tok . Text - 1 ;
expr = untyped_str ( expr_tok ) ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok . Type = = TokType : : BraceCurly_Open )
{
Token expr_tok = currtok ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
eat ( TokType : : BraceCurly_Open ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
s32 level = 0 ;
while ( left & & ( currtok . Type ! = TokType : : BraceCurly_Close | | level > 0 ) )
{
if ( currtok . Type = = TokType : : BraceCurly_Open )
level + + ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
else if ( currtok . Type = = TokType : : BraceCurly_Close & & level > 0 )
level - - ;
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
eat ( currtok . Type ) ;
}
eat ( TokType : : BraceCurly_Close ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
expr_tok . Length = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) expr_tok . Text ;
expr = untyped_str ( expr_tok ) ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok . Type = = TokType : : Assign_Classifer )
{
eat ( TokType : : Assign_Classifer ) ;
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
Token expr_tok = currtok ;
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
if ( currtok . Type = = TokType : : Statement_End )
{
log_failure ( " Expected expression after bitfield \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
while ( left & & currtok . Type ! = TokType : : Statement_End )
{
eat ( currtok . Type ) ;
}
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
expr_tok . Length = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) expr_tok . Text ;
bitfield_expr = untyped_str ( expr_tok ) ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Token stmt_end = currtok ;
eat ( TokType : : Statement_End ) ;
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
// Check for inline comment : <type> <identifier> = <expression>; // <inline comment>
CodeComment inline_cmt = NoCode ;
if ( left
& & ( currtok_noskip . Type = = TokType : : Comment )
& & currtok_noskip . Line = = stmt_end . Line )
{
inline_cmt = parse_comment ( ) ;
}
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
using namespace ECode ;
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
CodeVar
result = ( CodeVar ) make_code ( ) ;
result - > Type = Variable ;
result - > Name = get_cached_string ( name ) ;
result - > ModuleFlags = mflags ;
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
result - > ValueType = type ;
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
if ( array_expr )
type - > ArrExpr = array_expr ;
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
if ( bitfield_expr )
result - > BitfieldSize = bitfield_expr ;
2023-08-02 09:39:35 -07:00
2023-09-04 22:44:04 -07:00
if ( attributes )
result - > Attributes = attributes ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( specifiers )
result - > Specs = specifiers ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( expr )
result - > Value = expr ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
if ( inline_cmt )
result - > InlineCmt = inline_cmt ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
2023-09-04 22:44:04 -07:00
// Publically Exposed Interface
2023-07-24 14:45:27 -07:00
internal
2023-08-01 02:17:24 -07:00
CodeClass parse_class ( bool inplace_def )
2023-07-24 14:45:27 -07:00
{
2023-07-29 03:32:16 -07:00
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-08-01 02:17:24 -07:00
CodeClass result = ( CodeClass ) parse_class_struct ( Parser : : TokType : : Decl_Class , inplace_def ) ;
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
return result ;
2023-07-24 14:45:27 -07:00
}
CodeClass parse_class ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
CodeClass result = ( CodeClass ) parse_class_struct ( TokType : : Decl_Class ) ;
Context . pop ( ) ;
return result ;
2023-07-24 14:45:27 -07:00
}
2023-08-07 00:10:45 -07:00
internal
CodeConstructor parse_constructor ( )
{
using namespace Parser ;
push_scope ( ) ;
2023-08-22 21:05:58 -07:00
Token identifier = parse_identifier ( ) ;
CodeParam params = parse_params ( ) ;
Code initializer_list = NoCode ;
CodeBody body = NoCode ;
CodeComment inline_cmt = NoCode ;
2023-08-07 00:10:45 -07:00
if ( check ( TokType : : Assign_Classifer ) )
{
eat ( TokType : : Assign_Classifer ) ;
2023-08-19 05:21:28 -07:00
Token initializer_list_tok = NullToken ;
2023-08-07 00:10:45 -07:00
s32 level = 0 ;
while ( left & & ( currtok . Type ! = TokType : : BraceCurly_Open | | level > 0 ) )
{
if ( currtok . Type = = TokType : : BraceCurly_Open )
level + + ;
else if ( currtok . Type = = TokType : : BraceCurly_Close )
level - - ;
eat ( currtok . Type ) ;
}
initializer_list_tok . Length = ( ( sptr ) currtok . Text + currtok . Length ) - ( sptr ) initializer_list_tok . Text ;
initializer_list = untyped_str ( initializer_list_tok ) ;
body = parse_function_body ( ) ;
}
else if ( check ( TokType : : BraceCurly_Open ) )
{
body = parse_function_body ( ) ;
}
2023-08-22 21:05:58 -07:00
else
{
Token stmt_end = currtok ;
eat ( TokType : : Statement_End ) ;
2023-08-23 15:16:45 -07:00
2023-08-22 21:05:58 -07:00
if ( currtok_noskip . Type = = TokType : : Comment & & currtok_noskip . Line = = stmt_end . Line )
inline_cmt = parse_comment ( ) ;
}
2023-08-07 00:10:45 -07:00
CodeConstructor result = ( CodeConstructor ) make_code ( ) ;
if ( params )
result - > Params = params ;
if ( initializer_list )
result - > InitializerList = initializer_list ;
if ( body )
{
result - > Body = body ;
result - > Type = ECode : : Constructor ;
}
else
result - > Type = ECode : : Constructor_Fwd ;
2023-08-23 15:16:45 -07:00
2023-08-22 21:05:58 -07:00
if ( inline_cmt )
result - > InlineCmt = inline_cmt ;
2023-08-07 00:10:45 -07:00
Context . pop ( ) ;
return result ;
}
CodeConstructor parse_constructor ( StrC def )
{
check_parse_args ( def ) ;
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
Context . Tokens = toks ;
CodeConstructor result = parse_constructor ( ) ;
return result ;
}
internal
CodeDestructor parse_destructor ( CodeSpecifiers specifiers )
{
using namespace Parser ;
push_scope ( ) ;
if ( check ( TokType : : Spec_Virtual ) )
{
if ( specifiers )
specifiers . append ( ESpecifier : : Virtual ) ;
else
specifiers = def_specifier ( ESpecifier : : Virtual ) ;
eat ( TokType : : Spec_Virtual ) ;
}
if ( left & & currtok . Text [ 0 ] = = ' ~ ' )
eat ( TokType : : Operator ) ;
else
{
log_failure ( " Expected destructor '~' token \n %s " , Context . to_string ( ) ) ;
return CodeInvalid ;
}
2023-08-22 21:05:58 -07:00
Token identifier = parse_identifier ( ) ;
CodeBody body = { nullptr } ;
2023-08-07 00:10:45 -07:00
eat ( TokType : : Capture_Start ) ;
eat ( TokType : : Capture_End ) ;
if ( check ( TokType : : Operator ) & & currtok . Text [ 0 ] = = ' = ' )
{
eat ( TokType : : Operator ) ;
if ( left & & currtok . Text [ 0 ] = = ' 0 ' )
{
eat ( TokType : : Number ) ;
specifiers . append ( ESpecifier : : Pure ) ;
}
else
{
log_failure ( " Pure specifier expected due to '=' token \n %s " , Context . to_string ( ) ) ;
return CodeInvalid ;
}
}
2023-08-26 08:55:05 -07:00
2023-08-22 21:05:58 -07:00
CodeComment inline_cmt = NoCode ;
2023-08-07 00:10:45 -07:00
if ( check ( TokType : : BraceCurly_Open ) )
body = parse_function_body ( ) ;
2023-08-22 21:05:58 -07:00
else
{
Token stmt_end = currtok ;
eat ( TokType : : Statement_End ) ;
2023-08-26 08:55:05 -07:00
2023-08-22 21:05:58 -07:00
if ( currtok_noskip . Type = = TokType : : Comment & & currtok_noskip . Line = = stmt_end . Line )
inline_cmt = parse_comment ( ) ;
}
2023-08-07 00:10:45 -07:00
CodeDestructor result = ( CodeDestructor ) make_code ( ) ;
if ( specifiers )
result - > Specs = specifiers ;
if ( body )
{
result - > Body = body ;
result - > Type = ECode : : Destructor ;
}
else
result - > Type = ECode : : Destructor_Fwd ;
2023-08-26 08:55:05 -07:00
2023-08-22 21:05:58 -07:00
if ( inline_cmt )
result - > InlineCmt = inline_cmt ;
2023-08-07 00:10:45 -07:00
Context . pop ( ) ;
return result ;
}
CodeDestructor parse_destructor ( StrC def )
{
check_parse_args ( def ) ;
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
Context . Tokens = toks ;
CodeDestructor result = parse_destructor ( ) ;
return result ;
}
2023-07-24 14:45:27 -07:00
internal
2023-08-01 02:17:24 -07:00
CodeEnum parse_enum ( bool inplace_def )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
using namespace ECode ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-07-27 14:12:58 -07:00
SpecifierT specs_found [ 16 ] { ESpecifier : : NumSpecifiers } ;
s32 NumSpecifiers = 0 ;
2023-07-24 14:45:27 -07:00
2023-08-01 02:17:24 -07:00
CodeAttributes attributes = { nullptr } ;
2023-07-24 14:45:27 -07:00
Token name = { nullptr , 0 , TokType : : Invalid } ;
Code array_expr = { nullptr } ;
CodeType type = { nullptr } ;
char entries_code [ kilobytes ( 128 ) ] { 0 } ;
s32 entries_length = 0 ;
bool is_enum_class = false ;
eat ( TokType : : Decl_Enum ) ;
if ( currtok . Type = = TokType : : Decl_Class )
{
eat ( TokType : : Decl_Class ) ;
is_enum_class = true ;
}
2023-08-01 02:17:24 -07:00
attributes = parse_attributes ( ) ;
2023-07-24 14:45:27 -07:00
2023-08-01 11:02:54 -07:00
if ( check ( TokType : : Identifier ) )
2023-07-24 14:45:27 -07:00
{
2023-08-01 11:02:54 -07:00
name = currtok ;
2023-08-02 09:39:35 -07:00
Context . Scope - > Name = currtok ;
2023-08-01 11:02:54 -07:00
eat ( TokType : : Identifier ) ;
2023-07-24 14:45:27 -07:00
}
if ( currtok . Type = = TokType : : Assign_Classifer )
{
eat ( TokType : : Assign_Classifer ) ;
2023-07-29 03:32:16 -07:00
type = parse_type ( ) ;
2023-07-24 14:45:27 -07:00
if ( type = = Code : : Invalid )
2023-07-31 21:42:08 -07:00
{
log_failure ( " Failed to parse enum classifier \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
2023-07-31 21:42:08 -07:00
}
2023-07-24 14:45:27 -07:00
}
2023-08-01 11:02:54 -07:00
CodeBody body = { nullptr } ;
2023-07-24 14:45:27 -07:00
if ( currtok . Type = = TokType : : BraceCurly_Open )
{
2023-08-01 13:07:47 -07:00
body = ( CodeBody ) make_code ( ) ;
body - > Type = ECode : : Enum_Body ;
2023-08-01 11:02:54 -07:00
2023-07-24 14:45:27 -07:00
eat ( TokType : : BraceCurly_Open ) ;
2023-08-01 11:02:54 -07:00
Code member = CodeInvalid ;
2023-07-24 14:45:27 -07:00
2023-08-04 13:12:13 -07:00
while ( left & & currtok_noskip . Type ! = TokType : : BraceCurly_Close )
2023-07-24 14:45:27 -07:00
{
2023-09-25 13:42:29 -07:00
if ( currtok_noskip . Type = = TokType : : Preprocess_Hash )
2023-08-06 10:28:19 -07:00
eat ( TokType : : Preprocess_Hash ) ;
2023-08-04 13:12:13 -07:00
switch ( currtok_noskip . Type )
2023-08-01 02:17:24 -07:00
{
2023-08-04 13:12:13 -07:00
case TokType : : NewLine :
member = untyped_str ( currtok_noskip ) ;
eat ( TokType : : NewLine ) ;
2023-08-03 20:18:33 -07:00
break ;
2023-08-22 21:05:58 -07:00
case TokType : : Comment :
2023-08-06 10:28:19 -07:00
member = parse_comment ( ) ;
2023-08-01 11:02:54 -07:00
break ;
2023-08-01 02:17:24 -07:00
2023-08-01 11:02:54 -07:00
case TokType : : Preprocess_Define :
member = parse_define ( ) ;
break ;
2023-07-24 14:45:27 -07:00
2023-08-01 11:02:54 -07:00
case TokType : : Preprocess_If :
case TokType : : Preprocess_IfDef :
case TokType : : Preprocess_IfNotDef :
case TokType : : Preprocess_ElIf :
member = parse_preprocess_cond ( ) ;
break ;
2023-07-24 14:45:27 -07:00
2023-08-01 11:02:54 -07:00
case TokType : : Preprocess_Else :
member = preprocess_else ;
eat ( TokType : : Preprocess_Else ) ;
break ;
case TokType : : Preprocess_EndIf :
member = preprocess_endif ;
eat ( TokType : : Preprocess_EndIf ) ;
break ;
case TokType : : Preprocess_Macro :
2023-08-01 13:07:47 -07:00
member = parse_simple_preprocess ( TokType : : Preprocess_Macro ) ;
2023-08-01 11:02:54 -07:00
break ;
case TokType : : Preprocess_Pragma :
member = parse_pragma ( ) ;
break ;
2023-08-01 13:07:47 -07:00
case TokType : : Preprocess_Unsupported :
member = parse_simple_preprocess ( TokType : : Preprocess_Unsupported ) ;
break ;
2023-08-01 11:02:54 -07:00
default :
Token entry = currtok ;
eat ( TokType : : Identifier ) ;
if ( currtok . Type = = TokType : : Operator & & currtok . Text [ 0 ] = = ' = ' )
{
eat ( TokType : : Operator ) ;
2023-08-04 13:12:13 -07:00
while ( currtok_noskip . Type ! = TokType : : Comma & & currtok_noskip . Type ! = TokType : : BraceCurly_Close )
2023-08-01 11:02:54 -07:00
{
2023-08-04 13:12:13 -07:00
eat ( currtok_noskip . Type ) ;
2023-08-01 11:02:54 -07:00
}
}
if ( currtok . Type = = TokType : : Comma )
{
eat ( TokType : : Comma ) ;
}
entry . Length = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) entry . Text ;
member = untyped_str ( entry ) ;
break ;
2023-07-24 14:45:27 -07:00
}
2023-08-01 11:02:54 -07:00
if ( member = = Code : : Invalid )
2023-07-24 14:45:27 -07:00
{
2023-08-01 11:02:54 -07:00
log_failure ( " Failed to parse member \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
2023-07-24 14:45:27 -07:00
}
2023-08-01 11:02:54 -07:00
body . append ( member ) ;
}
2023-07-24 14:45:27 -07:00
eat ( TokType : : BraceCurly_Close ) ;
}
2023-08-22 21:05:58 -07:00
CodeComment inline_cmt = NoCode ;
2023-08-22 23:17:47 -07:00
2023-08-01 02:17:24 -07:00
if ( ! inplace_def )
2023-08-22 21:05:58 -07:00
{
Token stmt_end = currtok ;
2023-07-31 21:42:08 -07:00
eat ( TokType : : Statement_End ) ;
2023-08-22 23:17:47 -07:00
2023-08-22 21:05:58 -07:00
if ( currtok_noskip . Type = = TokType : : Comment & & currtok_noskip . Line = = stmt_end . Line )
inline_cmt = parse_comment ( ) ;
}
2023-07-24 14:45:27 -07:00
using namespace ECode ;
CodeEnum
result = ( CodeEnum ) make_code ( ) ;
2023-08-01 11:02:54 -07:00
if ( body . ast )
2023-07-24 14:45:27 -07:00
{
result - > Type = is_enum_class ? Enum_Class : Enum ;
2023-08-01 11:02:54 -07:00
result - > Body = body ;
2023-07-24 14:45:27 -07:00
}
else
{
result - > Type = is_enum_class ? Enum_Class_Fwd : Enum_Fwd ;
}
result - > Name = get_cached_string ( name ) ;
2023-08-01 02:17:24 -07:00
if ( attributes )
result - > Attributes = attributes ;
2023-07-24 14:45:27 -07:00
if ( type )
result - > UnderlyingType = type ;
2023-08-22 23:17:47 -07:00
2023-08-22 21:05:58 -07:00
if ( inline_cmt )
result - > InlineCmt = inline_cmt ;
2023-07-24 14:45:27 -07:00
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
CodeEnum parse_enum ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
2023-07-31 21:42:08 -07:00
{
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
2023-07-31 21:42:08 -07:00
}
2023-07-24 14:45:27 -07:00
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
return parse_enum ( ) ;
2023-07-24 14:45:27 -07:00
}
internal inline
2023-07-28 18:44:31 -07:00
CodeBody parse_export_body ( )
2023-07-24 14:45:27 -07:00
{
2023-07-29 03:32:16 -07:00
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
CodeBody result = parse_global_nspace ( ECode : : Export_Body ) ;
Context . pop ( ) ;
return result ;
2023-07-24 14:45:27 -07:00
}
CodeBody parse_export_body ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
return parse_export_body ( ) ;
2023-07-24 14:45:27 -07:00
}
internal inline
2023-07-29 02:52:06 -07:00
CodeBody parse_extern_link_body ( )
2023-07-24 14:45:27 -07:00
{
2023-07-29 03:32:16 -07:00
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
CodeBody result = parse_global_nspace ( ECode : : Extern_Linkage_Body ) ;
Context . pop ( ) ;
return result ;
2023-07-24 14:45:27 -07:00
}
internal
2023-07-29 02:52:06 -07:00
CodeExtern parse_extern_link ( )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
eat ( TokType : : Decl_Extern_Linkage ) ;
Token name = currtok ;
eat ( TokType : : String ) ;
name . Text + = 1 ;
name . Length - = 1 ;
CodeExtern
result = ( CodeExtern ) make_code ( ) ;
result - > Type = ECode : : Extern_Linkage ;
result - > Name = get_cached_string ( name ) ;
2023-07-29 03:32:16 -07:00
Code entry = parse_extern_link_body ( ) ;
2023-07-24 14:45:27 -07:00
if ( entry = = Code : : Invalid )
{
2023-07-29 02:52:06 -07:00
log_failure ( " Failed to parse body \n %s " , Context . to_string ( ) ) ;
2023-07-31 21:42:08 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
result - > Body = entry ;
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
CodeExtern parse_extern_link ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
return parse_extern_link ( ) ;
2023-07-24 14:45:27 -07:00
}
internal
2023-07-29 02:52:06 -07:00
CodeFriend parse_friend ( )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
using namespace ECode ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
eat ( TokType : : Decl_Friend ) ;
CodeFn function = { nullptr } ;
// Type declaration or return type
2023-07-29 03:32:16 -07:00
CodeType type = parse_type ( ) ;
2023-07-24 14:45:27 -07:00
if ( type = = Code : : Invalid )
2023-07-31 21:42:08 -07:00
{
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
2023-07-31 21:42:08 -07:00
}
2023-07-24 14:45:27 -07:00
// Funciton declaration
if ( currtok . Type = = TokType : : Identifier )
{
// Name
2023-07-29 03:32:16 -07:00
Token name = parse_identifier ( ) ;
2023-08-02 09:39:35 -07:00
Context . Scope - > Name = name ;
2023-07-24 14:45:27 -07:00
// Parameter list
2023-07-29 03:32:16 -07:00
CodeParam params = parse_params ( ) ;
2023-07-24 14:45:27 -07:00
function = make_code ( ) ;
function - > Type = Function_Fwd ;
function - > Name = get_cached_string ( name ) ;
function - > ReturnType = type ;
if ( params )
function - > Params = params ;
}
2023-08-23 15:16:45 -07:00
2023-08-22 21:05:58 -07:00
Token stmt_end = currtok ;
2023-07-24 14:45:27 -07:00
eat ( TokType : : Statement_End ) ;
2023-08-23 15:16:45 -07:00
2023-08-22 21:05:58 -07:00
CodeComment inline_cmt = NoCode ;
if ( currtok_noskip . Type = = TokType : : Comment & & currtok_noskip . Line = = stmt_end . Line )
inline_cmt = parse_comment ( ) ;
2023-07-24 14:45:27 -07:00
CodeFriend
result = ( CodeFriend ) make_code ( ) ;
result - > Type = Friend ;
if ( function )
result - > Declaration = function ;
else
result - > Declaration = type ;
2023-08-23 15:16:45 -07:00
2023-08-22 21:05:58 -07:00
if ( inline_cmt )
result - > InlineCmt = inline_cmt ;
2023-07-24 14:45:27 -07:00
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
CodeFriend parse_friend ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
return parse_friend ( ) ;
2023-07-24 14:45:27 -07:00
}
internal
2023-07-29 02:52:06 -07:00
CodeFn parse_functon ( )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-07-27 14:12:58 -07:00
SpecifierT specs_found [ 16 ] { ESpecifier : : NumSpecifiers } ;
s32 NumSpecifiers = 0 ;
2023-07-24 14:45:27 -07:00
CodeAttributes attributes = { nullptr } ;
2023-08-07 00:10:45 -07:00
CodeSpecifiers specifiers = { nullptr } ;
2023-07-24 14:45:27 -07:00
ModuleFlag mflags = ModuleFlag : : None ;
if ( check ( TokType : : Module_Export ) )
{
mflags = ModuleFlag : : Export ;
eat ( TokType : : Module_Export ) ;
}
2023-07-28 18:44:31 -07:00
attributes = parse_attributes ( ) ;
2023-07-24 14:45:27 -07:00
2023-07-28 18:44:31 -07:00
while ( left & & currtok . is_specifier ( ) )
2023-07-24 14:45:27 -07:00
{
SpecifierT spec = ESpecifier : : to_type ( currtok ) ;
switch ( spec )
{
case ESpecifier : : Const :
case ESpecifier : : Consteval :
case ESpecifier : : Constexpr :
case ESpecifier : : External_Linkage :
2023-08-21 17:30:13 -07:00
case ESpecifier : : ForceInline :
2023-07-24 14:45:27 -07:00
case ESpecifier : : Inline :
2023-08-21 17:30:13 -07:00
case ESpecifier : : NeverInline :
2023-07-24 14:45:27 -07:00
case ESpecifier : : Static :
break ;
default :
2023-07-29 02:52:06 -07:00
log_failure ( " Invalid specifier %s for functon \n %s " , ESpecifier : : to_str ( spec ) , Context . to_string ( ) ) ;
2023-07-31 21:42:08 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
}
if ( spec = = ESpecifier : : Const )
continue ;
2023-07-27 14:12:58 -07:00
specs_found [ NumSpecifiers ] = spec ;
NumSpecifiers + + ;
2023-07-24 14:45:27 -07:00
eat ( currtok . Type ) ;
}
2023-07-27 14:12:58 -07:00
if ( NumSpecifiers )
2023-07-24 14:45:27 -07:00
{
2023-07-27 14:12:58 -07:00
specifiers = def_specifiers ( NumSpecifiers , specs_found ) ;
2023-07-24 14:45:27 -07:00
}
2023-07-29 03:32:16 -07:00
CodeType ret_type = parse_type ( ) ;
2023-07-24 14:45:27 -07:00
if ( ret_type = = Code : : Invalid )
2023-07-31 21:42:08 -07:00
{
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
2023-07-31 21:42:08 -07:00
}
2023-07-24 14:45:27 -07:00
2023-07-29 03:32:16 -07:00
Token name = parse_identifier ( ) ;
2023-08-02 09:39:35 -07:00
Context . Scope - > Name = name ;
2023-07-24 14:45:27 -07:00
if ( ! name )
2023-07-31 21:42:08 -07:00
{
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
2023-07-31 21:42:08 -07:00
}
2023-07-24 14:45:27 -07:00
2023-07-29 02:52:06 -07:00
CodeFn result = parse_function_after_name ( mflags , attributes , specifiers , ret_type , name ) ;
2023-07-24 14:45:27 -07:00
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
CodeFn parse_function ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-29 02:52:06 -07:00
using namespace Parser ;
2023-07-24 14:45:27 -07:00
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
return ( CodeFn ) parse_functon ( ) ;
2023-07-24 14:45:27 -07:00
}
CodeBody parse_global_body ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
CodeBody result = parse_global_nspace ( ECode : : Global_Body ) ;
Context . pop ( ) ;
return result ;
2023-07-24 14:45:27 -07:00
}
internal
2023-08-06 11:58:43 -07:00
CodeNS parse_namespace ( )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
eat ( TokType : : Decl_Namespace ) ;
2023-07-29 03:32:16 -07:00
Token name = parse_identifier ( ) ;
2023-08-02 09:39:35 -07:00
Context . Scope - > Name = name ;
2023-07-24 14:45:27 -07:00
2023-07-29 03:32:16 -07:00
CodeBody body = parse_global_nspace ( ECode : : Namespace_Body ) ;
2023-07-24 14:45:27 -07:00
if ( body = = Code : : Invalid )
2023-07-31 21:42:08 -07:00
{
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
2023-07-31 21:42:08 -07:00
}
2023-07-24 14:45:27 -07:00
2023-08-06 11:58:43 -07:00
CodeNS
result = ( CodeNS ) make_code ( ) ;
2023-07-24 14:45:27 -07:00
result - > Type = ECode : : Namespace ;
result - > Name = get_cached_string ( name ) ;
result - > Body = body ;
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
2023-08-06 11:58:43 -07:00
CodeNS parse_namespace ( StrC def )
2023-07-24 14:45:27 -07:00
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
return parse_namespace ( ) ;
2023-07-24 14:45:27 -07:00
}
internal
2023-07-29 02:52:06 -07:00
CodeOperator parse_operator ( )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
CodeAttributes attributes = { nullptr } ;
CodeSpecifiers specifiers = { nullptr } ;
ModuleFlag mflags = ModuleFlag : : None ;
2023-07-27 14:12:58 -07:00
SpecifierT specs_found [ 16 ] { ESpecifier : : NumSpecifiers } ;
s32 NumSpecifiers = 0 ;
2023-07-24 14:45:27 -07:00
if ( check ( TokType : : Module_Export ) )
{
mflags = ModuleFlag : : Export ;
eat ( TokType : : Module_Export ) ;
}
2023-07-28 18:44:31 -07:00
attributes = parse_attributes ( ) ;
2023-07-24 14:45:27 -07:00
2023-07-28 18:44:31 -07:00
while ( left & & currtok . is_specifier ( ) )
2023-07-24 14:45:27 -07:00
{
SpecifierT spec = ESpecifier : : to_type ( currtok ) ;
switch ( spec )
{
case ESpecifier : : Const :
case ESpecifier : : Constexpr :
2023-08-21 17:30:13 -07:00
case ESpecifier : : ForceInline :
2023-07-24 14:45:27 -07:00
case ESpecifier : : Inline :
2023-08-21 17:30:13 -07:00
case ESpecifier : : NeverInline :
2023-07-24 14:45:27 -07:00
case ESpecifier : : Static :
break ;
default :
2023-07-29 02:52:06 -07:00
log_failure ( " Invalid specifier " " %s " " for operator \n %s " , ESpecifier : : to_str ( spec ) , Context . to_string ( ) ) ;
2023-07-31 21:42:08 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
}
if ( spec = = ESpecifier : : Const )
continue ;
2023-07-27 14:12:58 -07:00
specs_found [ NumSpecifiers ] = spec ;
NumSpecifiers + + ;
2023-07-24 14:45:27 -07:00
eat ( currtok . Type ) ;
}
2023-07-27 14:12:58 -07:00
if ( NumSpecifiers )
2023-07-24 14:45:27 -07:00
{
2023-07-27 14:12:58 -07:00
specifiers = def_specifiers ( NumSpecifiers , specs_found ) ;
2023-07-24 14:45:27 -07:00
}
// Parse Return Type
2023-07-29 03:32:16 -07:00
CodeType ret_type = parse_type ( ) ;
2023-07-24 14:45:27 -07:00
2023-07-29 02:52:06 -07:00
CodeOperator result = parse_operator_after_ret_type ( mflags , attributes , specifiers , ret_type ) ;
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
CodeOperator parse_operator ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
return ( CodeOperator ) parse_operator ( ) ;
2023-07-24 14:45:27 -07:00
}
2023-08-21 17:30:13 -07:00
CodeOpCast parse_operator_cast ( CodeSpecifiers specifiers )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-08-22 21:05:58 -07:00
// TODO : Specifiers attributed to the cast
2023-08-21 17:30:13 -07:00
// Operator's namespace if not within same class.
2023-08-02 09:39:35 -07:00
Token name = NullToken ;
if ( check ( TokType : : Identifier ) )
{
name = currtok ;
while ( left & & currtok . Type = = TokType : : Identifier )
{
eat ( TokType : : Identifier ) ;
if ( currtok . Type = = TokType : : Access_StaticSymbol )
eat ( TokType : : Access_StaticSymbol ) ;
}
name . Length = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) name . Text ;
}
2023-07-24 14:45:27 -07:00
eat ( TokType : : Decl_Operator ) ;
2023-07-29 03:32:16 -07:00
Code type = parse_type ( ) ;
2023-07-24 14:45:27 -07:00
2023-08-02 09:39:35 -07:00
Context . Scope - > Name = { type - > Name . Data , type - > Name . length ( ) } ;
2023-07-24 14:45:27 -07:00
eat ( TokType : : Capture_Start ) ;
eat ( TokType : : Capture_End ) ;
if ( check ( TokType : : Spec_Const ) )
2023-07-31 21:42:08 -07:00
{
2023-08-21 17:30:13 -07:00
if ( specifiers . ast = = nullptr )
specifiers = def_specifier ( ESpecifier : : Const ) ;
else
specifiers . append ( ESpecifier : : Const ) ;
2023-07-31 21:42:08 -07:00
eat ( TokType : : Spec_Const ) ;
}
2023-07-24 14:45:27 -07:00
2023-08-22 21:05:58 -07:00
Code body = NoCode ;
CodeComment inline_cmt = NoCode ;
2023-07-24 14:45:27 -07:00
if ( check ( TokType : : BraceCurly_Open ) )
{
eat ( TokType : : BraceCurly_Open ) ;
Token body_str = currtok ;
s32 level = 0 ;
while ( left & & ( currtok . Type ! = TokType : : BraceCurly_Close | | level > 0 ) )
{
if ( currtok . Type = = TokType : : BraceCurly_Open )
level + + ;
2023-08-04 13:12:13 -07:00
else if ( currtok . Type = = TokType : : BraceCurly_Close )
2023-07-24 14:45:27 -07:00
level - - ;
eat ( currtok . Type ) ;
}
body_str . Length = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) body_str . Text ;
2023-08-04 13:12:13 -07:00
eat ( TokType : : BraceCurly_Close ) ;
2023-07-24 14:45:27 -07:00
body = untyped_str ( body_str ) ;
2023-08-02 09:39:35 -07:00
}
else
{
2023-08-22 21:05:58 -07:00
Token stmt_end = currtok ;
2023-08-02 09:39:35 -07:00
eat ( TokType : : Statement_End ) ;
2023-08-26 08:55:05 -07:00
2023-08-22 21:05:58 -07:00
if ( currtok_noskip . Type = = TokType : : Comment & & currtok_noskip . Line = = stmt_end . Line )
inline_cmt = parse_comment ( ) ;
2023-07-24 14:45:27 -07:00
}
CodeOpCast result = ( CodeOpCast ) make_code ( ) ;
2023-08-02 09:39:35 -07:00
if ( name )
result - > Name = get_cached_string ( name ) ;
2023-07-24 14:45:27 -07:00
if ( body )
{
result - > Type = ECode : : Operator_Cast ;
result - > Body = body ;
}
else
{
result - > Type = ECode : : Operator_Cast_Fwd ;
}
if ( specifiers )
result - > Specs = specifiers ;
result - > ValueType = type ;
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
CodeOpCast parse_operator_cast ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
return parse_operator_cast ( ) ;
2023-07-24 14:45:27 -07:00
}
internal inline
2023-08-01 02:17:24 -07:00
CodeStruct parse_struct ( bool inplace_def )
2023-07-24 14:45:27 -07:00
{
2023-07-29 03:32:16 -07:00
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-08-01 02:17:24 -07:00
CodeStruct result = ( CodeStruct ) parse_class_struct ( TokType : : Decl_Struct , inplace_def ) ;
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
return result ;
2023-07-24 14:45:27 -07:00
}
CodeStruct parse_struct ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 14:14:02 -07:00
push_scope ( ) ;
CodeStruct result = ( CodeStruct ) parse_class_struct ( TokType : : Decl_Struct ) ;
Context . pop ( ) ;
return result ;
2023-07-24 14:45:27 -07:00
}
internal
2023-07-29 02:52:06 -07:00
CodeTemplate parse_template ( )
2023-07-24 14:45:27 -07:00
{
# define UseTemplateCapture true
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
ModuleFlag mflags = ModuleFlag : : None ;
if ( check ( TokType : : Module_Export ) )
{
mflags = ModuleFlag : : Export ;
eat ( TokType : : Module_Export ) ;
}
eat ( TokType : : Decl_Template ) ;
2023-07-29 03:32:16 -07:00
Code params = parse_params ( UseTemplateCapture ) ;
2023-07-24 14:45:27 -07:00
if ( params = = Code : : Invalid )
2023-07-31 21:42:08 -07:00
{
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
2023-07-31 21:42:08 -07:00
}
2023-07-24 14:45:27 -07:00
Code definition = { nullptr } ;
while ( left )
{
if ( check ( TokType : : Decl_Class ) )
{
2023-07-29 03:32:16 -07:00
definition = parse_class ( ) ;
2023-07-24 14:45:27 -07:00
break ;
}
if ( check ( TokType : : Decl_Struct ) )
{
2023-07-31 21:42:08 -07:00
definition = parse_struct ( ) ;
2023-07-24 14:45:27 -07:00
break ;
}
if ( check ( TokType : : Decl_Using ) )
{
2023-07-29 03:32:16 -07:00
definition = parse_using ( ) ;
2023-07-24 14:45:27 -07:00
break ;
}
// Its either a function or a variable
Token name = { nullptr , 0 , TokType : : Invalid } ;
CodeAttributes attributes = { nullptr } ;
CodeSpecifiers specifiers = { nullptr } ;
bool expects_function = false ;
2023-07-27 14:12:58 -07:00
SpecifierT specs_found [ 16 ] { ESpecifier : : NumSpecifiers } ;
s32 NumSpecifiers = 0 ;
2023-07-24 14:45:27 -07:00
2023-07-28 18:44:31 -07:00
attributes = parse_attributes ( ) ;
2023-07-24 14:45:27 -07:00
2023-07-28 18:44:31 -07:00
while ( left & & currtok . is_specifier ( ) )
2023-07-24 14:45:27 -07:00
{
SpecifierT spec = ESpecifier : : to_type ( currtok ) ;
switch ( spec )
{
case ESpecifier : : Const :
case ESpecifier : : Constexpr :
case ESpecifier : : Constinit :
case ESpecifier : : External_Linkage :
case ESpecifier : : Global :
case ESpecifier : : Inline :
case ESpecifier : : Local_Persist :
case ESpecifier : : Mutable :
case ESpecifier : : Static :
case ESpecifier : : Thread_Local :
case ESpecifier : : Volatile :
break ;
case ESpecifier : : Consteval :
expects_function = true ;
break ;
default :
2023-07-29 02:52:06 -07:00
log_failure ( " Invalid specifier %s for variable or function \n %s " , ESpecifier : : to_str ( spec ) , Context . to_string ( ) ) ;
2023-07-31 21:42:08 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
}
// Ignore const it will be handled by the type
if ( spec = = ESpecifier : : Const )
continue ;
2023-07-27 14:12:58 -07:00
specs_found [ NumSpecifiers ] = spec ;
NumSpecifiers + + ;
2023-07-24 14:45:27 -07:00
eat ( currtok . Type ) ;
}
2023-07-27 14:12:58 -07:00
if ( NumSpecifiers )
2023-07-24 14:45:27 -07:00
{
2023-07-27 14:12:58 -07:00
specifiers = def_specifiers ( NumSpecifiers , specs_found ) ;
2023-07-24 14:45:27 -07:00
}
2023-07-29 03:32:16 -07:00
definition = parse_operator_function_or_variable ( expects_function , attributes , specifiers ) ;
2023-07-24 14:45:27 -07:00
break ;
}
CodeTemplate
result = ( CodeTemplate ) make_code ( ) ;
result - > Type = ECode : : Template ;
result - > Params = params ;
result - > Declaration = definition ;
result - > ModuleFlags = mflags ;
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
# undef UseTemplateCapture
}
CodeTemplate parse_template ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
return parse_template ( ) ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07: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 ) ) )
2023-09-05 10:36:59 -07:00
The excess whitespace cannot be stripped however , because there is no semantic awareness within the first capture group .
2023-09-04 22:44:04 -07:00
*/
2023-07-24 14:45:27 -07:00
internal
2023-09-04 22:44:04 -07:00
CodeType parse_type ( bool * typedef_is_function )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
Token context_tok = prevtok ;
2023-07-27 14:12:58 -07:00
SpecifierT specs_found [ 16 ] { ESpecifier : : NumSpecifiers } ;
s32 NumSpecifiers = 0 ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
Token name = { nullptr , 0 , TokType : : Invalid } ;
2023-07-24 14:45:27 -07:00
2023-09-03 20:36:51 -07:00
// Attributes are assumed to be before the type signature
2023-07-28 18:44:31 -07:00
CodeAttributes attributes = parse_attributes ( ) ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
// Prefix specifiers
2023-07-28 18:44:31 -07:00
while ( left & & currtok . is_specifier ( ) )
2023-07-24 14:45:27 -07:00
{
SpecifierT spec = ESpecifier : : to_type ( currtok ) ;
if ( spec ! = ESpecifier : : Const )
{
2023-07-29 02:52:06 -07:00
log_failure ( " Error, invalid specifier used in type definition: %s \n %s " , currtok . Text , Context . to_string ( ) ) ;
2023-07-31 21:42:08 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
}
2023-07-27 14:12:58 -07:00
specs_found [ NumSpecifiers ] = spec ;
NumSpecifiers + + ;
2023-07-24 14:45:27 -07:00
eat ( currtok . Type ) ;
}
if ( left = = 0 )
{
2023-07-29 02:52:06 -07:00
log_failure ( " Error, unexpected end of type definition \n %s " , Context . to_string ( ) ) ;
2023-07-31 21:42:08 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
}
2023-09-03 20:36:51 -07:00
// All kinds of nonsense can makeup a type signature, first we check for a in-place definition of a class, enum, or struct
2023-07-24 14:45:27 -07:00
if ( currtok . Type = = TokType : : Decl_Class
| | currtok . Type = = TokType : : Decl_Enum
2023-09-03 20:36:51 -07:00
| | currtok . Type = = TokType : : Decl_Struct
| | currtok . Type = = TokType : : Decl_Union )
2023-07-24 14:45:27 -07:00
{
name = currtok ;
eat ( currtok . Type ) ;
name . Length = ( ( sptr ) currtok . Text + currtok . Length ) - ( sptr ) name . Text ;
eat ( TokType : : Identifier ) ;
2023-08-02 09:39:35 -07:00
Context . Scope - > Name = name ;
2023-07-24 14:45:27 -07:00
}
2023-09-03 20:36:51 -07:00
2023-09-04 22:44:04 -07:00
#if 0
else if ( currtok . Type = = TokType : : DeclType )
{
// Will have a capture and its own parsing rules, were going to just shove everything in a string.
name = currtok ;
eat ( TokType : : DeclType ) ;
eat ( TokType : : Capture_Start ) ;
while ( left & & currtok . Type ! = TokType : : Capture_End )
{
if ( currtok . Type = = TokType : : Capture_Start )
level + + ;
if ( currtok . Type = = TokType : : Capture_End )
level - - ;
eat ( currtok . Type ) ;
}
eat ( TokType : : Capture_End ) ;
name . Length = ( ( sptr ) currtok . Text + currtok . Length ) - ( sptr ) name . Text ;
Context . Scope - > Name = name ;
}
# endif
2023-09-03 20:36:51 -07:00
// Check if native type keywords are used, eat them for the signature.
2023-07-31 21:42:08 -07:00
else if ( currtok . Type > = TokType : : Type_Unsigned & & currtok . Type < = TokType : : Type_MS_W64 )
2023-07-24 14:45:27 -07:00
{
name = currtok ;
eat ( currtok . Type ) ;
2023-07-31 21:42:08 -07:00
while ( currtok . Type > = TokType : : Type_Unsigned & & currtok . Type < = TokType : : Type_MS_W64 )
2023-07-24 14:45:27 -07:00
{
eat ( currtok . Type ) ;
}
name . Length = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) name . Text ;
2023-08-02 09:39:35 -07:00
Context . Scope - > Name = name ;
2023-07-24 14:45:27 -07:00
}
2023-09-03 20:36:51 -07:00
// The usual Identifier type signature that may have namespace qualifiers
2023-07-24 14:45:27 -07:00
else
{
2023-07-29 03:32:16 -07:00
name = parse_identifier ( ) ;
2023-08-02 09:39:35 -07:00
Context . Scope - > Name = name ;
2023-07-24 14:45:27 -07:00
if ( ! name )
2023-07-31 21:42:08 -07:00
{
log_failure ( " Error, failed to type signature \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
2023-07-31 21:42:08 -07:00
}
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
// Suffix specifiers for typename.
2023-07-28 18:44:31 -07:00
while ( left & & currtok . is_specifier ( ) )
2023-07-24 14:45:27 -07:00
{
SpecifierT spec = ESpecifier : : to_type ( currtok ) ;
if ( spec ! = ESpecifier : : Const
& & spec ! = ESpecifier : : Ptr
& & spec ! = ESpecifier : : Ref
& & spec ! = ESpecifier : : RValue )
{
2023-07-29 02:52:06 -07:00
log_failure ( " Error, invalid specifier used in type definition: %s \n %s " , currtok . Text , Context . to_string ( ) ) ;
2023-07-31 21:42:08 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
}
2023-07-27 14:12:58 -07:00
specs_found [ NumSpecifiers ] = spec ;
NumSpecifiers + + ;
2023-07-24 14:45:27 -07:00
eat ( currtok . Type ) ;
}
2023-09-04 22:44:04 -07:00
# ifdef GEN_USE_NEW_TYPENAME_PARSING
if ( NumSpecifiers )
{
specifiers = def_specifiers ( NumSpecifiers , specs_found ) ;
NumSpecifiers = 0 ;
}
# endif
2023-09-03 20:36:51 -07:00
// For function type signatures
CodeType return_type = NoCode ;
CodeParam params = NoCode ;
2023-09-04 22:44:04 -07:00
# ifdef GEN_USE_NEW_TYPENAME_PARSING
CodeParam params_nested = NoCode ;
# endif
bool is_function_typename = false ;
Token * last_capture = nullptr ;
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07: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.
if ( typedef_is_function & & scanner - > Type = = TokType : : Identifier )
{
is_function_typename = true ;
+ + scanner ;
}
is_function_typename = scanner - > Type = = TokType : : Capture_Start ;
Token * first_capture = scanner ;
if ( is_function_typename )
{
// Go to the end of the signature
2023-09-07 18:11:57 -07:00
while ( scanner - > Type ! = TokType : : Statement_End & & scanner - > Type ! = TokType : : BraceCurly_Open )
2023-09-04 22:44:04 -07:00
+ + scanner ;
// Go back to the first capture start found
while ( scanner - > Type ! = TokType : : Capture_Start )
- - scanner ;
last_capture = scanner ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
bool is_for_opcast = str_compare ( Context . Scope - > Prev - > ProcName , " parse_operator_cast " ) = = 0 ;
if ( is_for_opcast & & is_function_typename & & last_capture )
2023-08-07 17:16:04 -07:00
{
2023-09-04 22:44:04 -07:00
// 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 )
2023-08-07 17:16:04 -07:00
{
2023-09-04 22:44:04 -07:00
// The capture start in question is the first capture start, this is not a function typename.
is_function_typename = false ;
2023-08-07 17:16:04 -07:00
}
2023-09-04 22:44:04 -07:00
}
}
2023-08-07 17:16:04 -07:00
2023-09-04 22:44:04 -07:00
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.
return_type = ( CodeType ) make_code ( ) ;
return_type - > Type = ECode : : Typename ;
// String
// name_stripped = String::make( GlobalAllocator, name );
// name_stripped.strip_space();
return_type - > Name = get_cached_string ( name ) ;
# ifdef GEN_USE_NEW_TYPENAME_PARSING
if ( specifiers )
{
return_type - > Specs = specifiers ;
specifiers = nullptr ;
2023-08-07 17:16:04 -07:00
}
2023-09-04 22:44:04 -07:00
# else
if ( NumSpecifiers )
return_type - > Specs = def_specifiers ( NumSpecifiers , ( SpecifierT * ) specs_found ) ;
// Reset specifiers, the function itself will have its own suffix specifiers possibly.
NumSpecifiers = 0 ;
# endif
name = { nullptr , 0 , TokType : : Invalid } ;
// The next token can either be a capture for the identifier or it could be the identifier exposed.
if ( ! check ( TokType : : Capture_Start ) )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
// Started with an identifier immeidately, which means its of the format: <ReturnType> <identifier> <capture>;
name = parse_identifier ( ) ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -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.
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,
// we can shove these specific specifiers into a specs, and then leave the suffix ones for a separate member of the AST.
// Parse immeidate capture which would be with parse_params()
// Eat Capture End
# ifdef GEN_USE_NEW_TYPENAME_PARSING
eat ( TokType : : Capture_Start ) ;
// Binding specifiers
while ( left & & currtok . is_specifier ( ) )
{
SpecifierT spec = ESpecifier : : to_type ( currtok ) ;
if ( spec ! = ESpecifier : : Ptr
& & spec ! = ESpecifier : : Ref
& & spec ! = ESpecifier : : RValue )
{
log_failure ( " Error, invalid specifier used in type definition: %s \n %s " , currtok . Text , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
specs_found [ NumSpecifiers ] = spec ;
NumSpecifiers + + ;
eat ( currtok . Type ) ;
}
if ( NumSpecifiers )
{
specifiers = def_specifiers ( NumSpecifiers , specs_found ) ;
}
NumSpecifiers = 0 ;
if ( check ( TokType : : Identifier ) )
name = parse_identifier ( ) ;
// Immeidate parameters
if ( check ( TokType : : Capture_Start ) )
params_nested = parse_params ( ) ;
# else
// 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 ;
eat ( TokType : : Capture_Start ) ;
s32 level = 0 ;
while ( left & & ( currtok . Type ! = TokType : : Capture_End | | level > 0 ) )
{
if ( currtok . Type = = TokType : : Capture_Start )
level + + ;
if ( currtok . Type = = TokType : : Capture_End )
level - - ;
eat ( currtok . Type ) ;
}
eat ( TokType : : Capture_End ) ;
name . Length = ( ( sptr ) prevtok . Text + prevtok . Length ) - ( sptr ) name . Text ;
# endif
}
// Were now dealing with the parameters of the function
params = parse_params ( ) ;
// Look for suffix specifiers for the function
while ( left & & currtok . is_specifier ( ) )
{
SpecifierT spec = ESpecifier : : to_type ( currtok ) ;
if ( spec ! = ESpecifier : : Const
2023-09-06 00:06:30 -07:00
// TODO : Add support for NoExcept
2023-09-04 22:44:04 -07:00
// && spec != ESpecifier::NoExcept
& & spec ! = ESpecifier : : RValue )
{
log_failure ( " Error, invalid specifier used in type definition: %s \n %s " , currtok . Text , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
specs_found [ NumSpecifiers ] = spec ;
NumSpecifiers + + ;
2023-07-24 14:45:27 -07:00
eat ( currtok . Type ) ;
}
2023-09-04 22:44:04 -07:00
# ifdef GEN_USE_NEW_TYPENAME_PARSING
if ( NumSpecifiers )
{
func_suffix_specs = def_specifiers ( NumSpecifiers , specs_found ) ;
NumSpecifiers = 0 ;
}
# endif
2023-07-24 14:45:27 -07:00
}
2023-08-25 15:57:53 -07:00
2023-08-23 08:05:49 -07:00
bool is_param_pack = false ;
if ( check ( TokType : : Varadic_Argument ) )
{
is_param_pack = true ;
eat ( TokType : : Varadic_Argument ) ;
}
2023-07-24 14:45:27 -07:00
using namespace ECode ;
CodeType
2023-09-11 20:22:53 -07:00
result = ( CodeType ) make_code ( ) ;
result - > Type = Typename ;
2023-09-25 09:12:11 -07:00
// result->Token = Context.Scope->Start;
2023-07-24 14:45:27 -07:00
2023-09-05 10:36:59 -07:00
// Need to wait until were using the new parsing method to do this.
2023-09-05 21:30:34 -07:00
String name_stripped = strip_formatting ( name , strip_formatting_dont_preserve_newlines ) ;
2023-09-05 10:36:59 -07:00
// name_stripped.strip_space();
2023-09-04 22:44:04 -07:00
# ifdef GEN_USE_NEW_TYPENAME_PARSING
if ( params_nested )
2023-07-24 14:45:27 -07:00
{
2023-09-04 22:44:04 -07:00
name_stripped . append ( params_nested - > to_string ( ) ) ;
2023-07-24 14:45:27 -07:00
}
2023-09-04 22:44:04 -07:00
# endif
2023-08-26 08:55:05 -07:00
result - > Name = get_cached_string ( name_stripped ) ;
2023-07-24 14:45:27 -07:00
if ( attributes )
result - > Attributes = attributes ;
2023-08-25 15:57:53 -07:00
2023-09-04 22:44:04 -07:00
# ifdef GEN_USE_NEW_TYPENAME_PARSING
if ( specifiers )
{
result - > Specs = specifiers ;
}
if ( func_suffix_specs )
{
result - > FuncSuffixSpecs = func_suffix_specs ;
}
# else
if ( NumSpecifiers )
{
Code specifiers = def_specifiers ( NumSpecifiers , ( SpecifierT * ) specs_found ) ;
result - > Specs = specifiers ;
}
# endif
2023-08-23 08:05:49 -07:00
if ( is_param_pack )
result - > IsParamPack = true ;
2023-07-24 14:45:27 -07:00
2023-09-04 22:44:04 -07:00
// These following are only populated if its a function typename
2023-09-03 20:36:51 -07:00
if ( return_type )
2023-09-04 22:44:04 -07:00
{
2023-09-03 20:36:51 -07:00
result - > ReturnType = return_type ;
2023-09-04 22:44:04 -07:00
if ( typedef_is_function )
* typedef_is_function = true ;
}
2023-09-03 20:36:51 -07:00
if ( params )
result - > Params = params ;
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
CodeType parse_type ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
return parse_type ( ) ;
2023-07-24 14:45:27 -07:00
}
internal
2023-07-29 02:52:06 -07:00
CodeTypedef parse_typedef ( )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-08-07 17:16:04 -07:00
bool is_function = false ;
Token name = { nullptr , 0 , TokType : : Invalid } ;
Code array_expr = { nullptr } ;
Code type = { nullptr } ;
2023-07-24 14:45:27 -07:00
ModuleFlag mflags = ModuleFlag : : None ;
if ( check ( TokType : : Module_Export ) )
{
mflags = ModuleFlag : : Export ;
eat ( TokType : : Module_Export ) ;
}
eat ( TokType : : Decl_Typedef ) ;
2023-07-31 21:42:08 -07:00
constexpr bool from_typedef = true ;
2023-08-22 23:17:47 -07:00
# if GEN_PARSER_DISABLE_MACRO_TYPEDEF
if ( false )
# else
2023-07-31 21:42:08 -07:00
if ( check ( TokType : : Preprocess_Macro ) )
2023-08-22 23:17:47 -07:00
# endif
2023-07-31 21:42:08 -07:00
{
type = t_empty ;
name = currtok ;
2023-08-02 09:39:35 -07:00
Context . Scope - > Name = name ;
2023-07-31 21:42:08 -07:00
eat ( TokType : : Preprocess_Macro ) ;
}
else
{
2023-08-07 17:16:04 -07:00
bool is_complicated =
currtok . Type = = TokType : : Decl_Enum
| | currtok . Type = = TokType : : Decl_Class
| | currtok . Type = = TokType : : Decl_Struct
| | currtok . Type = = TokType : : Decl_Union ;
2023-07-24 14:45:27 -07:00
2023-08-07 17:16:04 -07:00
if ( is_complicated )
{
TokArray tokens = Context . Tokens ;
2023-07-24 14:45:27 -07:00
2023-08-07 17:16:04 -07:00
s32 idx = tokens . Idx ;
s32 level = 0 ;
for ( ; idx < tokens . Arr . num ( ) ; idx + + )
{
if ( tokens [ idx ] . Type = = TokType : : BraceCurly_Open )
level + + ;
2023-07-24 14:45:27 -07:00
2023-08-07 17:16:04 -07:00
if ( tokens [ idx ] . Type = = TokType : : BraceCurly_Close )
level - - ;
if ( level = = 0 & & tokens [ idx ] . Type = = TokType : : Statement_End )
break ;
}
if ( ( idx - 2 ) = = tokens . Idx )
{
// Its a forward declaration only
type = parse_foward_or_definition ( currtok . Type , from_typedef ) ;
}
Token tok = tokens [ idx - 1 ] ;
if ( tok . Type = = TokType : : Identifier )
{
tok = tokens [ idx - 2 ] ;
bool is_indirection = tok . Type = = TokType : : Ampersand
| | tok . Type = = TokType : : Star ;
bool ok_to_parse = false ;
if ( tok . Type = = TokType : : BraceCurly_Close )
{
// Its an inplace definition
// typdef <which> <type_identifier> { ... } <identifier>;
ok_to_parse = true ;
}
else if ( tok . Type = = TokType : : Identifier & & tokens [ idx - 3 ] . Type = = TokType : : Decl_Struct )
{
// Its a variable with type ID using struct namespace.
// <which> <type_identifier> <identifier>;
ok_to_parse = true ;
}
else if ( is_indirection )
{
// Its a indirection type with type ID using struct namespace.
// <which> <type_identifier>* <identifier>;
ok_to_parse = true ;
}
2023-07-24 14:45:27 -07:00
2023-08-07 17:16:04 -07:00
if ( ! ok_to_parse )
{
log_failure ( " Unsupported or bad member definition after struct declaration \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
type = parse_type ( ) ;
}
else if ( tok . Type = = TokType : : BraceCurly_Close )
{
// Its a definition
// <which> { ... };
type = parse_foward_or_definition ( currtok . Type , from_typedef ) ;
}
else if ( tok . Type = = TokType : : BraceSquare_Close )
{
// Its an array definition
// <which> <type_identifier> <identifier> [ ... ];
type = parse_type ( ) ;
}
else
{
log_failure ( " Unsupported or bad member definition after struct declaration \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
}
2023-07-31 21:42:08 -07:00
else
2023-08-07 17:16:04 -07:00
type = parse_type ( & is_function ) ;
2023-07-24 14:45:27 -07:00
2023-07-31 21:42:08 -07:00
if ( check ( TokType : : Identifier ) )
{
name = currtok ;
eat ( TokType : : Identifier ) ;
}
2023-08-07 17:16:04 -07:00
else if ( ! is_function )
2023-07-31 21:42:08 -07:00
{
log_failure ( " Error, expected identifier for typedef \n %s " , Context . to_string ( ) ) ;
Context . pop ( ) ;
return CodeInvalid ;
}
2023-07-24 14:45:27 -07:00
}
2023-07-29 03:32:16 -07:00
array_expr = parse_array_decl ( ) ;
2023-08-22 23:17:47 -07:00
2023-08-22 21:05:58 -07:00
Token stmt_end = currtok ;
2023-07-24 14:45:27 -07:00
eat ( TokType : : Statement_End ) ;
2023-08-22 23:17:47 -07:00
2023-08-22 21:05:58 -07:00
CodeComment inline_cmt = NoCode ;
if ( currtok_noskip . Type = = TokType : : Comment & & currtok_noskip . Line = = stmt_end . Line )
inline_cmt = parse_comment ( ) ;
2023-07-24 14:45:27 -07:00
using namespace ECode ;
CodeTypedef
result = ( CodeTypedef ) make_code ( ) ;
result - > Type = Typedef ;
result - > ModuleFlags = mflags ;
2023-08-07 17:16:04 -07:00
if ( is_function )
{
result - > Name = type - > Name ;
result - > IsFunction = true ;
}
else
{
result - > Name = get_cached_string ( name ) ;
result - > IsFunction = false ;
}
2023-07-24 14:45:27 -07:00
result - > UnderlyingType = type ;
if ( type - > Type = = Typename & & array_expr & & array_expr - > Type ! = Invalid )
type . cast < CodeType > ( ) - > ArrExpr = array_expr ;
2023-08-22 23:17:47 -07:00
2023-08-22 21:05:58 -07:00
if ( inline_cmt )
result - > InlineCmt = inline_cmt ;
2023-07-24 14:45:27 -07:00
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
CodeTypedef parse_typedef ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
return parse_typedef ( ) ;
2023-07-24 14:45:27 -07:00
}
2023-08-21 20:49:23 -07:00
internal neverinline
2023-08-01 02:17:24 -07:00
CodeUnion parse_union ( bool inplace_def )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
ModuleFlag mflags = ModuleFlag : : None ;
if ( check ( TokType : : Module_Export ) )
{
mflags = ModuleFlag : : Export ;
eat ( TokType : : Module_Export ) ;
}
eat ( TokType : : Decl_Union ) ;
2023-07-28 18:44:31 -07:00
CodeAttributes attributes = parse_attributes ( ) ;
2023-07-24 14:45:27 -07:00
StrC name = { 0 , nullptr } ;
if ( check ( TokType : : Identifier ) )
{
name = currtok ;
2023-08-02 09:39:35 -07:00
Context . Scope - > Name = currtok ;
2023-07-24 14:45:27 -07:00
eat ( TokType : : Identifier ) ;
}
CodeBody body = { nullptr } ;
eat ( TokType : : BraceCurly_Open ) ;
body = make_code ( ) ;
body - > Type = ECode : : Union_Body ;
2023-08-04 13:12:13 -07:00
while ( ! check_noskip ( TokType : : BraceCurly_Close ) )
2023-07-24 14:45:27 -07:00
{
2023-08-23 15:16:45 -07:00
if ( currtok_noskip . Type = = TokType : : Preprocess_Hash )
2023-08-06 10:28:19 -07:00
eat ( TokType : : Preprocess_Hash ) ;
2023-08-01 11:02:54 -07:00
Code member = { nullptr } ;
2023-08-04 13:12:13 -07:00
switch ( currtok_noskip . Type )
2023-08-01 11:02:54 -07:00
{
2023-08-04 13:12:13 -07:00
case TokType : : NewLine :
2023-08-03 20:18:33 -07:00
// Empty lines are auto skipped by Tokens.current()
2023-08-04 13:12:13 -07:00
member = fmt_newline ;
eat ( TokType : : NewLine ) ;
2023-08-03 20:18:33 -07:00
break ;
2023-08-22 21:05:58 -07:00
case TokType : : Comment :
2023-08-06 10:28:19 -07:00
member = parse_comment ( ) ;
2023-08-01 11:02:54 -07:00
break ;
case TokType : : Decl_Class :
member = parse_complicated_definition ( TokType : : Decl_Class ) ;
break ;
case TokType : : Decl_Enum :
member = parse_complicated_definition ( TokType : : Decl_Enum ) ;
break ;
case TokType : : Decl_Struct :
member = parse_complicated_definition ( TokType : : Decl_Struct ) ;
break ;
case TokType : : Decl_Union :
member = parse_complicated_definition ( TokType : : Decl_Union ) ;
break ;
case TokType : : Preprocess_Define :
member = parse_define ( ) ;
break ;
case TokType : : Preprocess_If :
case TokType : : Preprocess_IfDef :
case TokType : : Preprocess_IfNotDef :
case TokType : : Preprocess_ElIf :
member = parse_preprocess_cond ( ) ;
break ;
case TokType : : Preprocess_Else :
member = preprocess_else ;
eat ( TokType : : Preprocess_Else ) ;
break ;
case TokType : : Preprocess_EndIf :
member = preprocess_endif ;
eat ( TokType : : Preprocess_EndIf ) ;
break ;
case TokType : : Preprocess_Macro :
2023-08-01 13:07:47 -07:00
member = parse_simple_preprocess ( TokType : : Preprocess_Macro ) ;
2023-08-01 11:02:54 -07:00
break ;
case TokType : : Preprocess_Pragma :
member = parse_pragma ( ) ;
break ;
2023-08-01 13:07:47 -07:00
case TokType : : Preprocess_Unsupported :
member = parse_simple_preprocess ( TokType : : Preprocess_Unsupported ) ;
break ;
2023-08-01 11:02:54 -07:00
default :
member = parse_variable ( ) ;
break ;
}
2023-07-24 14:45:27 -07:00
2023-08-01 11:02:54 -07:00
if ( member )
body . append ( member ) ;
2023-07-24 14:45:27 -07:00
}
eat ( TokType : : BraceCurly_Close ) ;
2023-07-31 21:42:08 -07:00
2023-08-01 02:17:24 -07:00
if ( ! inplace_def )
2023-07-31 21:42:08 -07:00
eat ( TokType : : Statement_End ) ;
2023-07-24 14:45:27 -07:00
CodeUnion
result = ( CodeUnion ) make_code ( ) ;
result - > Type = ECode : : Union ;
result - > ModuleFlags = mflags ;
if ( name )
result - > Name = get_cached_string ( name ) ;
if ( body )
result - > Body = body ;
if ( attributes )
result - > Attributes = attributes ;
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
CodeUnion parse_union ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
return parse_union ( ) ;
2023-07-24 14:45:27 -07:00
}
internal
2023-07-29 02:52:06 -07:00
CodeUsing parse_using ( )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
SpecifierT specs_found [ 16 ] { ESpecifier : : Invalid } ;
2023-07-27 14:12:58 -07:00
s32 NumSpecifiers = 0 ;
2023-07-24 14:45:27 -07:00
Token name = { nullptr , 0 , TokType : : Invalid } ;
Code array_expr = { nullptr } ;
CodeType type = { nullptr } ;
bool is_namespace = false ;
ModuleFlag mflags = ModuleFlag : : None ;
CodeAttributes attributes = { nullptr } ;
if ( check ( TokType : : Module_Export ) )
{
mflags = ModuleFlag : : Export ;
eat ( TokType : : Module_Export ) ;
}
eat ( TokType : : Decl_Using ) ;
if ( currtok . Type = = TokType : : Decl_Namespace )
{
is_namespace = true ;
eat ( TokType : : Decl_Namespace ) ;
}
name = currtok ;
2023-08-02 09:39:35 -07:00
Context . Scope - > Name = name ;
2023-07-24 14:45:27 -07:00
eat ( TokType : : Identifier ) ;
if ( currtok . IsAssign )
{
2023-07-29 03:32:16 -07:00
attributes = parse_attributes ( ) ;
2023-07-24 14:45:27 -07:00
eat ( TokType : : Operator ) ;
2023-07-29 03:32:16 -07:00
type = parse_type ( ) ;
2023-07-24 14:45:27 -07:00
}
2023-07-29 03:32:16 -07:00
array_expr = parse_array_decl ( ) ;
2023-07-24 14:45:27 -07:00
2023-08-22 21:05:58 -07:00
Token stmt_end = currtok ;
2023-07-24 14:45:27 -07:00
eat ( TokType : : Statement_End ) ;
2023-08-26 08:55:05 -07:00
2023-08-22 21:05:58 -07:00
CodeComment inline_cmt = NoCode ;
if ( currtok_noskip . Type = = TokType : : Comment & & currtok_noskip . Line = = stmt_end . Line )
{
inline_cmt = parse_comment ( ) ;
}
2023-07-24 14:45:27 -07:00
using namespace ECode ;
CodeUsing
result = ( CodeUsing ) make_code ( ) ;
result - > Name = get_cached_string ( name ) ;
result - > ModuleFlags = mflags ;
if ( is_namespace )
{
result - > Type = Using_Namespace ;
}
else
{
result - > Type = Using ;
if ( type )
result - > UnderlyingType = type ;
if ( array_expr )
type - > ArrExpr = array_expr ;
if ( attributes )
result - > Attributes = attributes ;
2023-08-26 08:55:05 -07:00
2023-08-22 21:05:58 -07:00
if ( inline_cmt )
result - > InlineCmt = inline_cmt ;
2023-07-24 14:45:27 -07:00
}
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
CodeUsing parse_using ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-24 14:45:27 -07:00
using namespace Parser ;
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-29 02:52:06 -07:00
return parse_using ( ) ;
2023-07-24 14:45:27 -07:00
}
internal
2023-07-28 18:44:31 -07:00
CodeVar parse_variable ( )
2023-07-24 14:45:27 -07:00
{
using namespace Parser ;
2023-07-29 02:52:06 -07:00
push_scope ( ) ;
2023-07-24 14:45:27 -07:00
2023-07-27 14:12:58 -07:00
SpecifierT specs_found [ 16 ] { ESpecifier : : NumSpecifiers } ;
s32 NumSpecifiers = 0 ;
2023-07-24 14:45:27 -07:00
ModuleFlag mflags = ModuleFlag : : None ;
CodeAttributes attributes = { nullptr } ;
CodeSpecifiers specifiers = { nullptr } ;
if ( check ( TokType : : Module_Export ) )
{
mflags = ModuleFlag : : Export ;
eat ( TokType : : Module_Export ) ;
}
2023-07-28 18:44:31 -07:00
attributes = parse_attributes ( ) ;
2023-07-24 14:45:27 -07:00
2023-07-29 03:32:16 -07:00
while ( left & & currtok . is_specifier ( ) )
2023-07-24 14:45:27 -07:00
{
SpecifierT spec = ESpecifier : : to_type ( currtok ) ;
switch ( spec )
{
case ESpecifier : : Const :
case ESpecifier : : Constexpr :
case ESpecifier : : Constinit :
case ESpecifier : : External_Linkage :
case ESpecifier : : Global :
case ESpecifier : : Inline :
case ESpecifier : : Local_Persist :
case ESpecifier : : Mutable :
case ESpecifier : : Static :
case ESpecifier : : Thread_Local :
case ESpecifier : : Volatile :
break ;
default :
2023-07-29 02:52:06 -07:00
log_failure ( " Invalid specifier %s for variable \n %s " , ESpecifier : : to_str ( spec ) , Context . to_string ( ) ) ;
2023-07-31 21:42:08 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return CodeInvalid ;
}
// Ignore const specifiers, they're handled by the type
if ( spec = = ESpecifier : : Const )
continue ;
2023-07-27 14:12:58 -07:00
specs_found [ NumSpecifiers ] = spec ;
NumSpecifiers + + ;
2023-07-24 14:45:27 -07:00
eat ( currtok . Type ) ;
}
2023-07-27 14:12:58 -07:00
if ( NumSpecifiers )
2023-07-24 14:45:27 -07:00
{
2023-07-27 14:12:58 -07:00
specifiers = def_specifiers ( NumSpecifiers , specs_found ) ;
2023-07-24 14:45:27 -07:00
}
2023-07-29 03:32:16 -07:00
CodeType type = parse_type ( ) ;
2023-07-24 14:45:27 -07:00
if ( type = = Code : : Invalid )
return CodeInvalid ;
2023-08-02 09:39:35 -07:00
Context . Scope - > Name = parse_identifier ( ) ;
2023-07-24 14:45:27 -07:00
2023-07-29 02:52:06 -07:00
CodeVar result = parse_variable_after_name ( mflags , attributes , specifiers , type , Context . Scope - > Name ) ;
2023-07-24 14:45:27 -07:00
2023-07-29 02:52:06 -07:00
Context . pop ( ) ;
2023-07-24 14:45:27 -07:00
return result ;
}
CodeVar parse_variable ( StrC def )
{
2023-07-29 03:32:16 -07:00
check_parse_args ( def ) ;
2023-07-29 02:52:06 -07:00
using namespace Parser ;
2023-07-24 14:45:27 -07:00
TokArray toks = lex ( def ) ;
if ( toks . Arr = = nullptr )
return CodeInvalid ;
2023-07-29 09:25:38 -07:00
Context . Tokens = toks ;
2023-07-28 18:44:31 -07:00
return parse_variable ( ) ;
2023-07-24 14:45:27 -07:00
}
// Undef helper macros
# undef check_parse_args
2023-07-29 02:52:06 -07:00
# undef currtok
# undef prevtok
2023-08-07 00:10:45 -07:00
# undef nexttok
2023-07-24 14:45:27 -07:00
# undef eat
# undef left
2023-07-29 02:52:06 -07:00
# undef check
# undef push_scope