Finished fleshing out incrementals, started to flesh out parsing

This commit is contained in:
Edward R. Gonzalez 2023-04-12 01:24:43 -04:00
parent d167f74243
commit eec93cee78
3 changed files with 488 additions and 46 deletions

View File

@ -63,15 +63,18 @@ using zpl::arena_init_from_memory;
using zpl::arena_free; using zpl::arena_free;
using zpl::bprintf; using zpl::bprintf;
using zpl::char_is_alpha; using zpl::char_is_alpha;
using zpl::char_is_alphanumeric;
using zpl::char_is_space; using zpl::char_is_space;
using zpl::crc32; using zpl::crc32;
using zpl::free_all; using zpl::free_all;
using zpl::memcopy;
using zpl::memset; using zpl::memset;
using zpl::pool_allocator; using zpl::pool_allocator;
using zpl::pool_init; using zpl::pool_init;
using zpl::pool_free; using zpl::pool_free;
using zpl::printf_va; using zpl::printf_va;
using zpl::printf_err_va; using zpl::printf_err_va;
using zpl::str_compare;
using zpl::snprintf_va; using zpl::snprintf_va;
using zpl::string_appendc; using zpl::string_appendc;
using zpl::string_append_fmt; using zpl::string_append_fmt;

View File

@ -769,7 +769,7 @@ namespace gen
}; };
inline inline
OpValidateResult operator_validate( OperatorT op, Code params_code, Code ret_type, Code specifier ) OpValidateResult operator__validate( OperatorT op, Code params_code, Code ret_type, Code specifier )
{ {
using namespace EOperator; using namespace EOperator;
@ -1123,13 +1123,13 @@ namespace gen
{ \ { \
if ( Length_ <= 0 ) \ if ( Length_ <= 0 ) \
{ \ { \
log_failure( "gen::%s: Invalid name length provided - %d", txt(Context_), length ); \ log_failure( "gen::" txt(Context_) ": Invalid name length provided - %d", length ); \
return Code::Invalid; \ return Code::Invalid; \
} \ } \
\ \
if ( Name_ == nullptr ) \ if ( Name_ == nullptr ) \
{ \ { \
log_failure( "gen::%s: name is null", txt(Context_) ); \ log_failure( "gen::" txt(Context_) ": name is null" ); \
return Code::Invalid; \ return Code::Invalid; \
} \ } \
} }
@ -1137,7 +1137,7 @@ namespace gen
# define null_check( Context_, Code_ ) \ # define null_check( Context_, Code_ ) \
if ( ! Code_ ) \ if ( ! Code_ ) \
{ \ { \
log_failure( "gen::%s: %s provided is null", txt(Context_), txt(Code_) ); \ log_failure( "gen::" txt(Context_) ": " txt(Code_) " provided is null" ); \
return Code::Invalid; \ return Code::Invalid; \
} }
@ -1145,13 +1145,13 @@ namespace gen
{ \ { \
if ( ! Code_ ) \ if ( ! Code_ ) \
{ \ { \
log_failure( "gen::%s: %s provided is null", txt(Context_) ); \ log_failure( "gen::" txt(Context_) ": " txt(Code_) " provided is null" ); \
return Code::Invalid; \ return Code::Invalid; \
} \ } \
\ \
if ( Code_->is_invalid() ) \ if ( Code_->is_invalid() ) \
{ \ { \
log_failure("gen::%s: %s provided is invalid", txt(Context_), txt(Code_) ); \ log_failure("gen::" txt(Context_) ": " txt(Code_) " provided is invalid" ); \
return Code::Invalid; \ return Code::Invalid; \
} \ } \
} }
@ -1435,7 +1435,7 @@ namespace gen
return Code::Invalid; return Code::Invalid;
} }
OpValidateResult check_result = operator_validate( op, params_code, ret_type, specifiers ); OpValidateResult check_result = operator__validate( op, params_code, ret_type, specifiers );
if ( check_result == OpValidateResult::Fail ) if ( check_result == OpValidateResult::Fail )
{ {
@ -2386,7 +2386,7 @@ namespace gen
{ {
using namespace ECode; using namespace ECode;
OpValidateResult check_result = operator_validate( op, params_code, ret_type, specifiers ); OpValidateResult check_result = operator__validate( op, params_code, ret_type, specifiers );
if ( check_result == OpValidateResult::Fail ) if ( check_result == OpValidateResult::Fail )
{ {
@ -2468,6 +2468,73 @@ namespace gen
# pragma endregion Incremetnal Constructions # pragma endregion Incremetnal Constructions
# pragma region Parsing Constructors # pragma region Parsing Constructors
# pragma region Helper Macros
# define check_parse_args( func, length, def ) \
if ( length <= 0 ) \
{ \
log_failure( "gen::" txt(func) ": length must greater than 0" ); \
return Code::Invalid; \
} \
if ( def == nullptr ) \
{ \
log_failure( "gen::" txt(func) ": def was null" ); \
return Code::Invalid; \
}
/*
These macros are used to make the parsing code more readable.
They expect the following variables to be defined withing the scope of parsing constructor:
SpecifierT specs_found[16] { ESpecifier::Num_Specifiers };
s32 num_specifiers = 0;
char const* name = nullptr;
s32 name_length = 0;
s32 left = length;
char const* scanner = def;
Code array_expr = Code::Invalid;
Code type = Code::Invalid;
char const* word = scanner;
s32 word_length = 0;
*/
# define current ( * scanner )
# define move_forward() \
left--; \
scanner++
# define SkipWhitespace() \
while ( left && char_is_space( current ) ) \
{ \
move_forward(); \
}
# define GetWord() \
while ( left && char_is_alphanumeric( current ) || current == '_' ) \
{ \
move_forward(); \
word_length++; \
}
# define CheckForSpecifiers() \
GetWord(); \
for ( s32 index = 0; index < ESpecifier::Num_Specifiers; index++ ) \
{ \
char const* specifier_str = ESpecifier::to_str( scast(SpecifierT, index) ); \
\
if ( str_compare( word, specifier_str, word_length ) == 0 ) \
{ \
specs_found[num_specifiers] = (SpecifierT) index; \
num_specifiers++; \
continue; \
} \
}
# pragma endregion Helper Macros
Code parse_class( s32 length, char const* def ) Code parse_class( s32 length, char const* def )
{ {
not_implemented( parse_class ); not_implemented( parse_class );
@ -2475,7 +2542,148 @@ namespace gen
Code parse_enum( s32 length, char const* def ) Code parse_enum( s32 length, char const* def )
{ {
not_implemented( parse_enum ); check_parse_args( parse_enum, length, def );
// Just in case someone gets a vulkan-level enum in here...
char entries_code[ kilobytes(128) ] { 0 };
s32 entries_length = 0;
char const* name = nullptr;
s32 name_length = 0;
s32 left = length;
char const* scanner = def;
char const* word = scanner;
s32 word_length = 0;
Code type = { nullptr };
bool is_enum_class = false;
SkipWhitespace();
if ( left <= 0 )
{
log_failure( "gen::parse_enum: enum definition was empty" );
return Code::Invalid;
}
GetWord();
if ( word_length != 4 || str_compare( word, "enum", word_length ) != 0 )
{
log_failure( "gen::parse_enum: enum definition did not start with `enum`" );
return Code::Invalid;
}
SkipWhitespace();
if ( left <= 0 )
{
log_failure( "gen::parse_enum: enum definition did not have a name" );
return Code::Invalid;
}
GetWord();
if ( word_length == 5 && str_compare( word, "class", word_length ) == 0 )
{
is_enum_class = true;
}
SkipWhitespace();
if ( left <= 0 )
{
log_failure( "gen::parse_enum: enum definition did not have a name" );
return Code::Invalid;
}
GetWord();
name = word;
name_length = word_length;
SkipWhitespace();
if ( current == ':' )
{
move_forward();
SkipWhitespace();
GetWord();
def_type( word_length, word, type );
}
SkipWhitespace();
if ( current == ';' )
{
goto Finished;
}
if ( current != '{' )
{
log_failure( "gen::parse_enum: enum definition did not have a body" );
return Code::Invalid;
}
move_forward();
char const* body_start = scanner;
do
{
if ( current == '}' )
{
move_forward();
break;
}
SkipWhitespace();
if ( left <= 0 )
{
log_failure( "gen::parse_enum: enum definition did not have a body" );
return Code::Invalid;
}
GetWord();
if ( word_length == 0 )
{
log_failure( "gen::parse_enum: enum definition did not have a body" );
return Code::Invalid;
}
entries_length += word_length;
if ( entries_length >= kilobytes(128) )
{
log_failure( "gen::parse_enum: enum definition had too many entries" );
return Code::Invalid;
}
}
while(1);
Finished:
using namespace ECode;
Code
result = make_code();
if ( entries_length )
{
memcopy( entries_code, body_start, entries_length );
Code body = untyped_str( entries_length, entries_code );
result->Type = is_enum_class ? Enum_Class : Enum;
result->add_entry( body );
}
else
{
result->Type = is_enum_class ? Enum_Class_Fwd : Enum_Fwd;
}
result->Name = get_cached_string( name, name_length );
if ( type )
result->add_entry( type );
result.lock();
return result;
} }
Code parse_execution( s32 length, char const* exec_def ) Code parse_execution( s32 length, char const* exec_def )
@ -2495,11 +2703,7 @@ namespace gen
Code parse_function( s32 length, char const* def ) Code parse_function( s32 length, char const* def )
{ {
if ( def == nullptr ) check_parse_args( parse_function, length, def );
{
log_failure("gen::parse_proc: def is null!");
return Code::Invalid;
}
Arena mem; Arena mem;
do_once_start do_once_start
@ -2523,9 +2727,6 @@ namespace gen
static static
Param Params[ 64 ] { 0 }; Param Params[ 64 ] { 0 };
// Zero out params before a run of this func.
memset( Params, 0, sizeof( Params ));
char const* name; char const* name;
s32 name_length = 0; s32 name_length = 0;
@ -2540,15 +2741,6 @@ namespace gen
while ( left -- ) while ( left -- )
{ {
#define SkipWhitespace() \
while ( left && char_is_space( * scanner ) ) \
{ \
left--; \
scanner++ ; \
}
#define Get
// Find all specifiers (if any) and the return type // Find all specifiers (if any) and the return type
do do
{ {
@ -2684,14 +2876,263 @@ namespace gen
not_implemented( parse_variable ); not_implemented( parse_variable );
} }
Code parse_type( s32 length, char const* def ) inline
bool parse__type_helper( char const* func_name
, s32 length, char const* def
, s32 name_length, char const* name
, u8 num_specifiers, SpecifierT* specs_found
, Code& array_expr)
{ {
not_implemented( parse_type ); s32 left = length;
char const* scanner = def;
char const* word = scanner;
s32 word_length = 0;
// Find all left-hand specifiers and the typename.
do
{
// Clearing any whitespace
SkipWhitespace();
if ( left <= 0 )
{
log_failure( "gen::%s: Error, reached end of string before finding typename", func_name );
return false;
} }
Code parse_typdef( s32 length, char const* def ) CheckForSpecifiers();
break;
}
while (1);
name = scanner;
name_length = word_length;
// Find all right-hand specifiers.
do
{ {
not_implemented( parse_typedef ); SkipWhitespace();
if ( left <= 0 )
break;
if ( current == '*')
{
specs_found[num_specifiers] = ESpecifier::Ptr;
num_specifiers++;
move_forward();
continue;
}
if ( current == '&')
{
move_forward();
if ( current == '&')
{
specs_found[num_specifiers] = ESpecifier::RValue;
num_specifiers++;
move_forward();
continue;
}
specs_found[num_specifiers] = ESpecifier::Ref;
num_specifiers++;
continue;
}
if ( current == '[')
{
move_forward();
SkipWhitespace();
if ( left <= 0 )
{
log_failure( "gen::%s: Error, reached end of string before finding array expression", func_name );
return false;
}
word = scanner;
word_length = 0;
GetWord();
array_expr = untyped_str( word_length, word );
if ( left <= 0 )
{
log_failure( "gen::%s: Error, reached end of string before finding ']' for array expression", func_name );
return false;
}
if ( current == ']')
{
move_forward();
}
num_specifiers++;
continue;
}
word = scanner;
word_length = 0;
CheckForSpecifiers();
break;
}
while (1);
}
Code parse_type( s32 length, char const* def )
{
check_parse_args( parse_type, length, def );
SpecifierT specs_found[16] { ESpecifier::Num_Specifiers };
u8 num_specifiers = 0;
char const* name = nullptr;
s32 name_length = 0;
Code array_expr = { nullptr };
bool helper_result = parse__type_helper( txt(parse_type)
, length, def
, name_length, name
, num_specifiers, specs_found
, array_expr
);
if ( ! helper_result )
return Code::Invalid;
using namespace ECode;
Code
result = make_code();
result->Type = Typename;
result->Name = get_cached_string( name, name_length );
Code specifiers = def_specifiers( num_specifiers, specs_found );
result->add_entry( specifiers );
if ( array_expr )
result->add_entry( array_expr );
result.lock();
return result;
}
Code parse_typedef( s32 length, char const* def )
{
check_parse_args( parse_typedef, length, def );
using namespace ECode;
SpecifierT specs_found[16] { ESpecifier::Num_Specifiers };
s32 num_specifiers = 0;
char const* name = nullptr;
s32 name_length = 0;
s32 left = length;
char const* scanner = def;
Code array_expr = { nullptr };
Code type = { nullptr };
char const* word = scanner;
s32 word_length = 0;
do
{
SkipWhitespace();
if ( left <= 0 )
{
log_failure( "gen::parse_typedef: Error, reached end of string before finding typename" );
return Code::Invalid;
}
GetWord();
if ( str_compare( word, "typedef", word_length ) != 0 )
{
log_failure( "gen::parse_typedef: Error, expected 'typedef' but found '%.*s'", word_length, word );
return Code::Invalid;
}
// Determining the typename inline
bool helper_result = parse__type_helper( txt(parse_typedef)
, left, scanner
, name_length, name
, num_specifiers, specs_found
, array_expr
);
if ( ! helper_result )
return Code::Invalid;
type = make_code();
type->Type = Typename;
type->Name = get_cached_string( name, name_length );
Code specifiers = def_specifiers( num_specifiers, specs_found );
type->add_entry( specifiers );
if ( array_expr )
type->add_entry( array_expr );
type.lock();
// End typename
SkipWhitespace();
if ( left <= 0 )
{
log_failure( "gen::parse_typedef: Error, reached end of string before finding name" );
return Code::Invalid;
}
word = scanner;
word_length = 0;
GetWord();
name = word;
name_length = word_length;
SkipWhitespace();
if ( left <= 0 )
{
log_failure( "gen::parse_typedef: Error, reached end of string before finding ';' for typedef" );
return Code::Invalid;
}
if ( current == ';')
{
move_forward();
break;
}
log_failure( "gen::parse_typedef: Error, expected ';' for typedef" );
return Code::Invalid;
}
while (1);
using namespace ECode;
Code
result = make_code();
result->Type = Typedef;
result->Name = get_cached_string( name, name_length );
result->add_entry( type );
result.lock();
return result;
} }
Code parse_using( s32 length, char const* def ) Code parse_using( s32 length, char const* def )
@ -2742,9 +3183,6 @@ namespace gen
s32 parse_typedefs( s32 length, char const* typedef_def, Code* out_typedef_codes ) s32 parse_typedefs( s32 length, char const* typedef_def, Code* out_typedef_codes )
{ {
not_implemented( parse_typedefs ); not_implemented( parse_typedefs );
Code
result = make_code();
} }
s32 parse_usings( s32 length, char const* usings_def, Code* out_using_codes ) s32 parse_usings( s32 length, char const* usings_def, Code* out_using_codes )

View File

@ -584,8 +584,9 @@ namespace gen
# define Define_Specifiers \ # define Define_Specifiers \
Entry( API_Import, API_Export_Code ) \ Entry( API_Import, API_Export_Code ) \
Entry( API_Export, API_Import_Code ) \ Entry( API_Export, API_Import_Code ) \
Entry( Attribute, " You cannot stringize an attribute this way" ) \ Entry( Attribute, "You cannot stringize an attribute this way" ) \
Entry( Alignas, alignas ) \ Entry( Alignas, alignas ) \
Entry( Array_Decl, "You cannot stringize an array declare this way" ) \
Entry( Const, const ) \ Entry( Const, const ) \
Entry( C_Linkage, extern "C" ) \ Entry( C_Linkage, extern "C" ) \
Entry( Consteval, consteval ) \ Entry( Consteval, consteval ) \