#ifdef GEN_INTELLISENSE_DIRECTIVES #pragma once #include "code_serialization.cpp" #endif namespace parser { internal void init(); internal void deinit(); } internal void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) { Arena* last = & Global_AllocatorBuckets.back(); switch ( type ) { case EAllocation_ALLOC: { if ( ( last->TotalUsed + size ) > last->TotalSize ) { Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize ); if ( bucket.PhysicalStart == nullptr ) GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets"); if ( ! Global_AllocatorBuckets.append( bucket ) ) GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets"); last = & Global_AllocatorBuckets.back(); } return alloc_align( allocator_info(* last), size, alignment ); } case EAllocation_FREE: { // Doesn't recycle. } break; case EAllocation_FREE_ALL: { // Memory::cleanup instead. } break; case EAllocation_RESIZE: { if ( last->TotalUsed + size > last->TotalSize ) { Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize ); if ( bucket.PhysicalStart == nullptr ) GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets"); if ( ! Global_AllocatorBuckets.append( bucket ) ) GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets"); last = & Global_AllocatorBuckets.back(); } void* result = alloc_align( last->Backing, size, alignment ); if ( result != nullptr && old_memory != nullptr ) { mem_copy( result, old_memory, old_size ); } return result; } } return nullptr; } internal void define_constants() { Code::Global = make_code(); Code::Global->Name = get_cached_string( txt("Global Code") ); Code::Global->Content = Code::Global->Name; Code::Invalid = make_code(); Code::Invalid.set_global(); t_empty = (CodeType) make_code(); t_empty->Type = ECode::Typename; t_empty->Name = get_cached_string( txt("") ); t_empty.set_global(); access_private = make_code(); access_private->Type = ECode::Access_Private; access_private->Name = get_cached_string( txt("private:\n") ); access_private.set_global(); access_protected = make_code(); access_protected->Type = ECode::Access_Protected; access_protected->Name = get_cached_string( txt("protected:\n") ); access_protected.set_global(); access_public = make_code(); access_public->Type = ECode::Access_Public; access_public->Name = get_cached_string( txt("public:\n") ); access_public.set_global(); attrib_api_export = def_attributes( code(GEN_API_Export_Code)); attrib_api_export.set_global(); attrib_api_import = def_attributes( code(GEN_API_Import_Code)); attrib_api_import.set_global(); module_global_fragment = make_code(); module_global_fragment->Type = ECode::Untyped; module_global_fragment->Name = get_cached_string( txt("module;") ); module_global_fragment->Content = module_global_fragment->Name; module_global_fragment.set_global(); module_private_fragment = make_code(); module_private_fragment->Type = ECode::Untyped; module_private_fragment->Name = get_cached_string( txt("module : private;") ); module_private_fragment->Content = module_private_fragment->Name; module_private_fragment.set_global(); fmt_newline = make_code(); fmt_newline->Type = ECode::NewLine; fmt_newline.set_global(); pragma_once = (CodePragma) make_code(); pragma_once->Type = ECode::Preprocess_Pragma; pragma_once->Name = get_cached_string( txt("once") ); pragma_once->Content = pragma_once->Name; pragma_once.set_global(); param_varadic = (CodeType) make_code(); param_varadic->Type = ECode::Parameters; param_varadic->Name = get_cached_string( txt("...") ); param_varadic->ValueType = t_empty; param_varadic.set_global(); preprocess_else = (CodePreprocessCond) make_code(); preprocess_else->Type = ECode::Preprocess_Else; preprocess_else.set_global(); preprocess_endif = (CodePreprocessCond) make_code(); preprocess_endif->Type = ECode::Preprocess_EndIf; preprocess_endif.set_global(); # define def_constant_code_type( Type_ ) \ t_##Type_ = def_type( name(Type_) ); \ t_##Type_.set_global(); def_constant_code_type( auto ); def_constant_code_type( void ); def_constant_code_type( int ); def_constant_code_type( bool ); def_constant_code_type( char ); def_constant_code_type( wchar_t ); def_constant_code_type( class ); def_constant_code_type( typename ); #ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS t_b32 = def_type( name(b32) ); def_constant_code_type( s8 ); def_constant_code_type( s16 ); def_constant_code_type( s32 ); def_constant_code_type( s64 ); def_constant_code_type( u8 ); def_constant_code_type( u16 ); def_constant_code_type( u32 ); def_constant_code_type( u64 ); def_constant_code_type( ssize ); def_constant_code_type( usize ); def_constant_code_type( f32 ); def_constant_code_type( f64 ); #endif # undef def_constant_code_type # define def_constant_spec( Type_, ... ) \ spec_##Type_ = def_specifiers( num_args(__VA_ARGS__), __VA_ARGS__); \ spec_##Type_.set_global(); # pragma push_macro("forceinline") # pragma push_macro("global") # pragma push_macro("internal") # pragma push_macro("local_persist") # pragma push_macro("neverinline") # undef forceinline # undef global # undef internal # undef local_persist # undef neverinline def_constant_spec( const, ESpecifier::Const ); def_constant_spec( consteval, ESpecifier::Consteval ); def_constant_spec( constexpr, ESpecifier::Constexpr ); def_constant_spec( constinit, ESpecifier::Constinit ); def_constant_spec( extern_linkage, ESpecifier::External_Linkage ); def_constant_spec( final, ESpecifier::Final ); def_constant_spec( forceinline, ESpecifier::ForceInline ); def_constant_spec( global, ESpecifier::Global ); def_constant_spec( inline, ESpecifier::Inline ); def_constant_spec( internal_linkage, ESpecifier::Internal_Linkage ); def_constant_spec( local_persist, ESpecifier::Local_Persist ); def_constant_spec( mutable, ESpecifier::Mutable ); def_constant_spec( neverinline, ESpecifier::NeverInline ); def_constant_spec( noexcept, ESpecifier::NoExceptions ); def_constant_spec( override, ESpecifier::Override ); def_constant_spec( ptr, ESpecifier::Ptr ); def_constant_spec( pure, ESpecifier::Pure ) def_constant_spec( ref, ESpecifier::Ref ); def_constant_spec( register, ESpecifier::Register ); def_constant_spec( rvalue, ESpecifier::RValue ); def_constant_spec( static_member, ESpecifier::Static ); def_constant_spec( thread_local, ESpecifier::Thread_Local ); def_constant_spec( virtual, ESpecifier::Virtual ); def_constant_spec( volatile, ESpecifier::Volatile) spec_local_persist = def_specifiers( 1, ESpecifier::Local_Persist ); spec_local_persist.set_global(); # pragma pop_macro("forceinline") # pragma pop_macro("global") # pragma pop_macro("internal") # pragma pop_macro("local_persist") # pragma pop_macro("neverinline") # undef def_constant_spec } void init() { // Setup global allocator { GlobalAllocator = AllocatorInfo { & Global_Allocator_Proc, nullptr }; Global_AllocatorBuckets = Array::init_reserve( heap(), 128 ); if ( Global_AllocatorBuckets == nullptr ) GEN_FATAL( "Failed to reserve memory for Global_AllocatorBuckets"); Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize ); if ( bucket.PhysicalStart == nullptr ) GEN_FATAL( "Failed to create first bucket for Global_AllocatorBuckets"); Global_AllocatorBuckets.append( bucket ); } // Setup the arrays { CodePools = Array::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); if ( CodePools == nullptr ) GEN_FATAL( "gen::init: Failed to initialize the CodePools array" ); StringArenas = Array::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); if ( StringArenas == nullptr ) GEN_FATAL( "gen::init: Failed to initialize the StringArenas array" ); } // Setup the code pool and code entries arena. { Pool code_pool = pool_init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); if ( code_pool.PhysicalStart == nullptr ) GEN_FATAL( "gen::init: Failed to initialize the code pool" ); CodePools.append( code_pool ); LexArena = arena_init_from_allocator( Allocator_Lexer, LexAllocator_Size ); Arena string_arena = arena_init_from_allocator( Allocator_StringArena, SizePer_StringArena ); if ( string_arena.PhysicalStart == nullptr ) GEN_FATAL( "gen::init: Failed to initialize the string arena" ); StringArenas.append( string_arena ); } // Setup the hash tables { StringCache = StringTable::init( Allocator_StringTable ); if ( StringCache.Entries == nullptr ) GEN_FATAL( "gen::init: Failed to initialize the StringCache"); } // Preprocessor Defines PreprocessorDefines = Array::init_reserve( GlobalAllocator, kilobytes(1) ); define_constants(); parser::init(); } void deinit() { usize index = 0; usize left = CodePools.num(); do { Pool* code_pool = & CodePools[index]; free(* code_pool); index++; } while ( left--, left ); index = 0; left = StringArenas.num(); do { Arena* string_arena = & StringArenas[index]; free(* string_arena); index++; } while ( left--, left ); StringCache.destroy(); CodePools.free(); StringArenas.free(); free(LexArena); PreprocessorDefines.free(); index = 0; left = Global_AllocatorBuckets.num(); do { Arena* bucket = & Global_AllocatorBuckets[ index ]; free(* bucket); index++; } while ( left--, left ); Global_AllocatorBuckets.free(); parser::deinit(); } void reset() { s32 index = 0; s32 left = CodePools.num(); do { Pool* code_pool = & CodePools[index]; clear(* code_pool); index++; } while ( left--, left ); index = 0; left = StringArenas.num(); do { Arena* string_arena = & StringArenas[index]; string_arena->TotalUsed = 0;; index++; } while ( left--, left ); StringCache.clear(); define_constants(); } AllocatorInfo get_string_allocator( s32 str_length ) { Arena* last = & StringArenas.back(); usize size_req = str_length + sizeof(StringHeader) + sizeof(char*); if ( last->TotalUsed + ssize(size_req) > last->TotalSize ) { Arena new_arena = arena_init_from_allocator( Allocator_StringArena, SizePer_StringArena ); if ( ! StringArenas.append( new_arena ) ) GEN_FATAL( "gen::get_string_allocator: Failed to allocate a new string arena" ); last = & StringArenas.back(); } return allocator_info(* last); } // Will either make or retrive a code string. StringCached get_cached_string( StrC str ) { s32 hash_length = str.Len > kilobytes(1) ? kilobytes(1) : str.Len; u64 key = crc32( str.Ptr, hash_length ); { StringCached* result = StringCache.get( key ); if ( result ) return * result; } String result = String::make( get_string_allocator( str.Len ), str ); StringCache.set( key, result ); return result; } // Used internally to retireve a Code object form the CodePool. Code make_code() { Pool* allocator = & CodePools.back(); if ( allocator->FreeList == nullptr ) { Pool code_pool = pool_init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); if ( code_pool.PhysicalStart == nullptr ) GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePool allcoator returned nullptr." ); if ( ! CodePools.append( code_pool ) ) GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePools failed to append new pool." ); allocator = & CodePools.back(); } Code result { rcast( AST*, alloc( allocator_info(* allocator), sizeof(AST) )) }; mem_set( result.ast, 0, sizeof(AST) ); // result->Type = ECode::Invalid; // result->Content = { nullptr }; // result->Prev = { nullptr }; // result->Next = { nullptr }; // result->Token = nullptr; // result->Parent = { nullptr }; // result->Name = { nullptr }; // result->Type = ECode::Invalid; // result->ModuleFlags = ModuleFlag::Invalid; // result->NumEntries = 0; return result; } void set_allocator_data_arrays( AllocatorInfo allocator ) { Allocator_DataArrays = allocator; } void set_allocator_code_pool( AllocatorInfo allocator ) { Allocator_CodePool = allocator; } void set_allocator_lexer( AllocatorInfo allocator ) { Allocator_Lexer = allocator; } void set_allocator_string_arena( AllocatorInfo allocator ) { Allocator_StringArena = allocator; } void set_allocator_string_table( AllocatorInfo allocator ) { Allocator_StringArena = allocator; }