Parser constructor passes all current tests...

Pretty much have a working library now... Albiet with problably quite a few hidden bugs in parsing.

Next steps are to start converting library to use its own Arena, Pool, Array, HashTable types. And either work on zpl dependency gutting or making a more robust set of tests.
This commit is contained in:
2023-07-11 03:10:20 -04:00
parent ddb3244467
commit f9085d4b6f
12 changed files with 787 additions and 50 deletions

View File

@ -22,7 +22,7 @@ Code gen__array_base()
));
}
Code gen__array( StrC type, sw type_size )
Code gen__array( StrC type )
{
StrC name;
{
@ -184,7 +184,7 @@ Code gen__array( StrC type, sw type_size )
header.Num = new_capacity;
sw size = sizeof( Header ) + sizeof( Type ) * new_capacity;
Header* new_header = reinterpret_cast< Header* >( alloc( header.Allocator, size ) );
Header* new_header = rcast( Header*, alloc( header.Allocator, size ) );
if ( new_header == nullptr )
return false;
@ -223,7 +223,6 @@ struct GenArrayRequest
{
StrC Dependency;
StrC Type;
sw Size;
};
Array(GenArrayRequest) GenArrayRequests;
@ -245,7 +244,7 @@ void gen__array_request( StrC type, sw size, StrC dep = {} )
return;
}
GenArrayRequest request = { dep, type, size };
GenArrayRequest request = { dep, type };
array_append( GenArrayRequests, request );
}
#define gen_array( type ) gen__array_request( { txt_to_StrC(type) }, sizeof(type) )
@ -268,7 +267,7 @@ u32 gen_array_file()
{
GenArrayRequest const& request = * current;
Code generated_array = gen__array( request.Type, request.Size );
Code generated_array = gen__array( request.Type );
if ( request.Dependency )
{

View File

@ -0,0 +1,202 @@
#pragma once
#if gen_time
#include "gen.hpp"
using namespace gen;
Code gen__buffer_base()
{
return parse_global_body( code(
struct BufferHeader
{
AllocatorInfo Backing;
uw Capacity;
uw Num;
};
));
}
Code gen__buffer( StrC type )
{
StrC name;
{
char const* name_str = str_fmt_buf( "Buffer_%s\0", type.Ptr );
s32 name_len = str_len( name_str );
name = { name_len, name_str };
};
Code buffer = parse_struct( token_fmt(
txt(
struct <BufferName>
{
using Header = BufferHeader;
using Type = <type>;
static <BufferName> init( AllocatorInfo allocator, sw capacity )
{
Header* header = rcast( Header*, alloc( allocator, sizeof( Header ) + capacity * sizeof( Type ) ) );
if ( header == nullptr )
return { nullptr };
header->Backing = allocator;
header->Capacity = capacity;
header->Num = 0;
return { rcast( Type*, header + 1 ) };
}
<BufferName> init( AllocatorInfo allocator, <BufferName> other )
{
Header& other_header = other.get_header();
Header* header = rcast( Header*, alloc( allocator, sizeof( Header ) + other_header.Capacity * sizeof( Type ) ) );
if ( header == nullptr )
return { nullptr };
header->Backing = allocator;
header->Capacity = other_header.Capacity;
header->Num = other_header.Num;
mem_copy( header + 1, other.Data, other_header.Num * sizeof( Type ) );
return { rcast( Type*, header + 1 ) };
}
void append( Type value )
{
Header& header = get_header();
Data[ header.Num ] = value;
header.Num++;
}
void append( Type* values, sw num )
{
Header& header = get_header();
ZPL_ASSERT( header.Num + num <= header.Capacity);
mem_copy( Data + header.Num, values, num * sizeof( Type ) );
header.Num += num;
}
void clear( void )
{
Header& header = get_header();
header.Num = 0;
}
Type& end( void )
{
Header& header = get_header();
return Data[ header.Num - 1 ];
}
void free( void )
{
Header& header = get_header();
zpl::free( header.Backing, &header );
}
Header& get_header( void )
{
return *( rcast( Header*, Data ) - 1 );
}
sw num( void )
{
return get_header().Num;
}
void wipe( void )
{
Header& header = get_header();
header.Num = 0;
mem_set( Data, 0, header.Capacity * sizeof( Type ) );
}
operator Type*()
{
return Data;
}
Type* Data;
};
),
2
, "BufferName", (char const*) name
, "type", (char const*) type
));
return buffer;
}
struct GenBufferRequest
{
StrC Dependency;
StrC Type;
};
Array(GenBufferRequest) GenBufferRequests;
void gen__buffer_request( StrC type, StrC dep = {} )
{
do_once_start
array_init( GenBufferRequests, Memory::GlobalAllocator );
do_once_end
// Make sure we don't already have a request for the type.
for ( sw idx = 0; idx < array_count( GenBufferRequests ); ++idx )
{
StrC const reqest_type = GenBufferRequests[ idx ].Type;
if ( reqest_type.Len != type.Len )
continue;
if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 )
return;
}
GenBufferRequest request = { dep, type };
array_append( GenBufferRequests, request );
}
#define gen_buffer( type ) gen__buffer_request( { txt_to_StrC(type) } )
u32 gen_buffer_file()
{
Builder
gen_buffer_file;
gen_buffer_file.open( "buffer.Parsed.gen.hpp" );
gen_buffer_file.print( def_include( StrC::from("Bloat.hpp")) );
gen_buffer_file.print( gen__buffer_base() );
GenBufferRequest* current = GenBufferRequests;
s32 left = array_count( GenBufferRequests );
while (left--)
{
GenBufferRequest const& request = * current;
Code generated_buffer = gen__buffer( current->Type );
if ( request.Dependency )
{
char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type );
s32 cmt_len = str_len( cmt_str );
Code cmt = def_comment( { cmt_len, cmt_str } );
Code include = def_include( request.Dependency );
gen_buffer_file.print( cmt );
gen_buffer_file.print( include );
}
gen_buffer_file.print( generated_buffer );
current++;
}
gen_buffer_file.write();
return 0;
}
#endif // gen_time

View File

@ -0,0 +1,359 @@
#pragma once
#if gen_time
#include "gen.hpp"
#include "Array.Parsed.hpp"
using namespace gen;
Code gen__hashtable_base()
{
return parse_global_body( code(
struct HashTable_FindResult
{
sw HashIndex;
sw PrevIndex;
sw EntryIndex;
};
));
}
Code gen__hashtable( StrC type, sw type_size )
{
StringCached name;
{
char const* name_str = str_fmt_buf( "HashTable_%s", type.Ptr );
s32 len = str_len( name_str );
name = get_cached_string({ len, name_str });
}
Code ht_entry = parse_struct( token_fmt(
txt(
struct <HashTableName>_Entry
{
u64 Key;
sw Next;
<type> Value;
};
),
2
, "HashTableName", (char const*) name
, "type", (char const*) type
));
StringCached ht_entry_name = get_cached_string( token_fmt( "<HashTableName>_Entry", 1, "HashTableName", name ) );
Code array_ht_entry = gen__array( ht_entry_name );
Code hashtable = parse_struct( token_fmt(
txt(
struct <HashTableName>
{
using Type = <type>;
using Entry = <HashTableName>_Entry;
using Array_Entry = Array_<HashTableName>_Entry;
using FindResult = HashTable_FindResult;
using MapProc = void ( * )( u64 key, Type value );
using MapMutProc = void ( * )( u64 key, Type* value );
static
<HashTableName> init( AllocatorInfo allocator )
{
<HashTableName>
result = { 0 };
result.Hashes = Array_sw ::init( allocator );
result.Entries = Array_Entry::init( allocator );
return result;
}
void clear( void )
{
for ( s32 idx = 0; idx < Hashes.num(); idx++ )
Hashes[ idx ] = -1;
Entries.clear();
}
void destroy( void )
{
if ( Hashes )
Hashes.free();
if ( Entries )
Entries.free();
}
Type* get( u64 key )
{
sw idx = find( key ).EntryIndex;
if ( idx > 0 )
return &Entries[ idx ].Value;
return nullptr;
}
void grow( void )
{
sw new_num = array_grow_formula( Entries.num() );
rehash( new_num );
}
void map( MapProc map_proc )
{
ZPL_ASSERT_NOT_NULL( map_proc );
for ( sw idx = 0; idx < Entries.num(); idx++ )
{
map_proc( Entries[ idx ].Key, Entries[ idx ].Value );
}
}
void map_mut( MapMutProc map_proc )
{
ZPL_ASSERT_NOT_NULL( map_proc );
for ( sw idx = 0; idx < Entries.num(); idx++ )
{
map_proc( Entries[ idx ].Key, &Entries[ idx ].Value );
}
}
void rehash( sw new_num )
{
sw idx;
sw last_added_index;
HashTable_u32 new_ht = HashTable_u32::init( Hashes.get_header().Allocator );
new_ht.Hashes.resize( new_num );
new_ht.Entries.reserve( new_ht.Hashes.num() );
for ( idx = 0; idx < new_ht.Hashes.num(); ++idx )
new_ht.Hashes[ idx ] = -1;
for ( idx = 0; idx < Entries.num(); ++idx )
{
Entry& entry = Entries[ idx ];
FindResult find_result;
if ( new_ht.Hashes.num() == 0 )
new_ht.grow();
entry = Entries[ idx ];
find_result = new_ht.find( entry.Key );
last_added_index = new_ht.add_entry( entry.Key );
if ( find_result.PrevIndex < 0 )
new_ht.Hashes[ find_result.HashIndex ] = last_added_index;
else
new_ht.Entries[ find_result.PrevIndex ].Next = last_added_index;
new_ht.Entries[ last_added_index ].Next = find_result.EntryIndex;
new_ht.Entries[ last_added_index ].Value = entry.Value;
}
destroy();
Hashes = new_ht.Hashes;
Entries = new_ht.Entries;
}
void rehash_fast( void )
{
sw idx;
for ( idx = 0; idx < Entries.num(); idx++ )
Entries[ idx ].Next = -1;
for ( idx = 0; idx < Hashes.num(); idx++ )
Hashes[ idx ] = -1;
for ( idx = 0; idx < Entries.num(); idx++ )
{
Entry* entry;
FindResult find_result;
}
}
void remove( u64 key )
{
FindResult find_result = find( key );
if ( find_result.EntryIndex >= 0 )
{
Entries.remove_at( find_result.EntryIndex );
rehash_fast();
}
}
void remove_entry( sw idx )
{
Entries.remove_at( idx );
}
void set( u64 key, Type value )
{
sw idx;
FindResult find_result;
if ( Hashes.num() == 0 )
grow();
find_result = find( key );
if ( find_result.EntryIndex >= 0 )
{
idx = find_result.EntryIndex;
}
else
{
idx = add_entry( key );
if ( find_result.PrevIndex >= 0 )
{
Entries[ find_result.PrevIndex ].Next = idx;
}
else
{
Hashes[ find_result.HashIndex ] = idx;
}
}
Entries[ idx ].Value = value;
if ( full() )
grow();
}
sw slot( u64 key )
{
for ( sw idx = 0; idx < Hashes.num(); ++idx )
if ( Hashes[ idx ] == key )
return idx;
return -1;
}
Array_sw Hashes;
Array_Entry Entries;
protected:
sw add_entry( u64 key )
{
sw idx;
Entry entry = { key, -1 };
idx = Entries.num();
Entries.append( entry );
return idx;
}
HashTable_FindResult find( u64 key )
{
FindResult result = { -1, -1, -1 };
if ( Hashes.num() > 0 )
{
result.HashIndex = key % Hashes.num();
result.EntryIndex = Hashes[ result.HashIndex ];
while ( result.EntryIndex >= 0 )
{
if ( Entries[ result.EntryIndex ].Key == key )
break;
result.PrevIndex = result.EntryIndex;
result.EntryIndex = Entries[ result.EntryIndex ].Next;
}
}
return result;
}
b32 full( void )
{
return 0.75f * Hashes.num() < Entries.num();
}
};
),
2
, "HashTableName", (char const*) name
, "type", (char const*) type
));
return def_global_body( 3, ht_entry, array_ht_entry, hashtable );
}
struct GenHashTableRequest
{
StrC Dependency;
StrC Type;
sw TypeSize;
};
Array(GenHashTableRequest) GenHashTableRequests;
void gen__hashtable_request( StrC type, sw size, StrC dep = {} )
{
do_once_start
array_init( GenHashTableRequests, Memory::GlobalAllocator );
gen_array( sw );
do_once_end
// Make sure we don't already have a request for the type.
for ( sw idx = 0; idx < array_count( GenHashTableRequests ); ++idx )
{
StrC const reqest_type = GenHashTableRequests[ idx ].Type;
if ( reqest_type.Len != type.Len )
continue;
if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 )
return;
}
GenHashTableRequest request = { dep, type, size};
array_append( GenHashTableRequests, request );
}
#define gen_hashtable( type ) gen__hashtable_request( { txt_to_StrC(type) }, sizeof( type ))
u32 gen_hashtable_file()
{
Builder
gen_buffer_file;
gen_buffer_file.open( "hashtable.Parsed.gen.hpp" );
gen_buffer_file.print( def_include( StrC::from("Bloat.hpp")) );
gen_buffer_file.print( def_include( StrC::from("Array.Parsed.hpp")) );
gen_buffer_file.print( def_include( StrC::from("array.Parsed.gen.hpp")) );
gen_buffer_file.print( gen__hashtable_base());
GenHashTableRequest* current = GenHashTableRequests;
s32 left = array_count( GenHashTableRequests );
while (left--)
{
GenHashTableRequest const& request = * current;
Code generated_buffer = gen__hashtable( current->Type, current->TypeSize );
if ( request.Dependency )
{
char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type );
s32 cmt_len = str_len( cmt_str );
Code cmt = def_comment( { cmt_len, cmt_str } );
Code include = def_include( request.Dependency );
gen_buffer_file.print( cmt );
gen_buffer_file.print( include );
}
gen_buffer_file.print( generated_buffer );
current++;
}
gen_buffer_file.write();
return 0;
}
#endif // gen_time

171
test/Parsed/Ring.Parsed.hpp Normal file
View File

@ -0,0 +1,171 @@
#pragma once
#if gen_time
#include "gen.hpp"
#include "Buffer.Parsed.hpp"
using namespace gen;
Code gen__ring( StrC type )
{
static Code t_allocator_info = def_type( name(AllocatorInfo) );
String name;
{
char const* name_str = str_fmt_buf( "Ring_%s\0", type.Ptr );
s32 name_len = str_len( name_str );
name = get_cached_string({ name_len, name_str });
};
Code ring = parse_struct( token_fmt(
txt(
struct <RingName>
{
using Type = <type>;
static <RingName> init( AllocatorInfo allocator, uw max_size )
{
<RingName> result = { 0 };
result.Backing = allocator;
result.Buffer = <BufferName>::init( allocator, max_size + 1 );
if ( result.Buffer == nullptr )
return { nullptr };
result.Capacity = max_size + 1;
return result;
}
void append( s16 value )
{
Buffer[ Head ] = value;
Head = ( Head + 1 ) % Capacity;
if ( Head == Tail )
Tail = ( Tail + 1 ) % Capacity;
}
inline void append( Type* values, sw num )
{
for ( sw idx = 0; idx < num; idx++ )
append( values[ idx ] );
}
bool empty( void )
{
return Head == Tail;
}
void free( void )
{
Buffer.free();
}
bool full( void )
{
return ( Head + 1 ) % Capacity == Tail;
}
Type& get( void )
{
Type& data = Buffer[ Tail ];
Tail = ( Tail + 1 ) % Capacity;
return data;
}
void wipe( void )
{
Head = 0;
Tail = 0;
Buffer.wipe();
}
AllocatorInfo Backing;
uw Capacity;
uw Head;
uw Tail;
<BufferName> Buffer;
};
),
3
, "RingName", (char const*) name
, "type", (char const*) type
, "BufferName", str_fmt_buf( "Buffer_%s", type.Ptr )
));
return ring;
}
struct GenRingRequest
{
StrC Dependency;
StrC Type;
};
Array(GenRingRequest) GenRingRequests;
void gen__ring_request( StrC type, sw size, StrC dep = {} )
{
do_once_start
array_init( GenRingRequests, Memory::GlobalAllocator );
do_once_end
// Make sure we don't already have a request for the type.
for ( sw idx = 0; idx < array_count( GenRingRequests ); ++idx )
{
StrC const reqest_type = GenRingRequests[ idx ].Type;
if ( reqest_type.Len != type.Len )
continue;
if ( str_compare( reqest_type.Ptr, type.Ptr, reqest_type.Len ) == 0 )
return;
}
// Ring definition depends on a array and buffer definition.
gen__buffer_request( type, dep );
GenRingRequest request = { dep, type };
array_append( GenRingRequests, request );
}
#define gen_ring( type ) gen__ring_request( { txt_to_StrC(type) }, sizeof( type ))
u32 gen_ring_file()
{
Builder
gen_ring_file;
gen_ring_file.open( "ring.Parsed.gen.hpp" );
gen_ring_file.print( def_include( StrC::from("Bloat.hpp")) );
gen_ring_file.print( def_include( StrC::from("buffer.Parsed.gen.hpp")) );
// gen_ring_file.print( gen__ring_base() );
GenRingRequest* current = GenRingRequests;
s32 left = array_count( GenRingRequests );
while (left--)
{
GenRingRequest const& request = * current;
Code generated_ring = gen__ring( current->Type );
if ( request.Dependency )
{
char const* cmt_str = str_fmt_buf( "// Dependency for %s type", request.Type );
s32 cmt_len = str_len( cmt_str );
Code cmt = def_comment( { cmt_len, cmt_str } );
Code include = def_include( request.Dependency );
gen_ring_file.print( cmt );
gen_ring_file.print( include );
}
gen_ring_file.print( generated_ring );
current++;
}
gen_ring_file.write();
return 0;
}
#endif // gen_time