mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-11-03 23:36:12 -08:00 
			
		
		
		
	
		
			
				
	
	
		
			543 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			543 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#ifdef INTELLISENSE_DIRECTIVES
 | 
						|
#pragma once
 | 
						|
#include "code_serialization.cpp"
 | 
						|
#endif
 | 
						|
 | 
						|
internal void parser_init(Context* ctx);
 | 
						|
internal void parser_deinit(Context* ctx);
 | 
						|
 | 
						|
internal
 | 
						|
void* fallback_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags )
 | 
						|
{
 | 
						|
	GEN_ASSERT(_ctx);
 | 
						|
	GEN_ASSERT(_ctx->Fallback_AllocatorBuckets);
 | 
						|
	Arena* last = array_back(_ctx->Fallback_AllocatorBuckets);
 | 
						|
 | 
						|
	switch ( type )
 | 
						|
	{
 | 
						|
		case EAllocation_ALLOC:
 | 
						|
		{
 | 
						|
			if ( ( last->TotalUsed + size ) > last->TotalSize )
 | 
						|
			{
 | 
						|
				Arena bucket = arena_init_from_allocator( heap(), _ctx->InitSize_Fallback_Allocator_Bucket_Size );
 | 
						|
 | 
						|
				if ( bucket.PhysicalStart == nullptr )
 | 
						|
					GEN_FATAL( "Failed to create bucket for Fallback_AllocatorBuckets");
 | 
						|
 | 
						|
				if ( ! array_append( _ctx->Fallback_AllocatorBuckets, bucket ) )
 | 
						|
					GEN_FATAL( "Failed to append bucket to Fallback_AllocatorBuckets");
 | 
						|
 | 
						|
				last = array_back(_ctx->Fallback_AllocatorBuckets);
 | 
						|
			}
 | 
						|
 | 
						|
			return alloc_align( arena_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(), _ctx->InitSize_Fallback_Allocator_Bucket_Size );
 | 
						|
 | 
						|
				if ( bucket.PhysicalStart == nullptr )
 | 
						|
					GEN_FATAL( "Failed to create bucket for Fallback_AllocatorBuckets");
 | 
						|
 | 
						|
				if ( ! array_append( _ctx->Fallback_AllocatorBuckets, bucket ) )
 | 
						|
					GEN_FATAL( "Failed to append bucket to Fallback_AllocatorBuckets");
 | 
						|
 | 
						|
				last = array_back( _ctx->Fallback_AllocatorBuckets);
 | 
						|
			}
 | 
						|
 | 
						|
			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 fallback_logger(LogEntry entry) 
 | 
						|
{
 | 
						|
	GEN_ASSERT(entry.msg.Len > 0);
 | 
						|
	GEN_ASSERT(entry.msg.Ptr);
 | 
						|
	log_fmt("%S: %S", loglevel_to_str(entry.level), entry.msg);
 | 
						|
}
 | 
						|
 | 
						|
internal
 | 
						|
void define_constants()
 | 
						|
{
 | 
						|
	// We only initalize these if there is no base context.
 | 
						|
	if ( context_counter > 0 )
 | 
						|
		return;
 | 
						|
 | 
						|
	Code_Global          = make_code();
 | 
						|
	Code_Global->Name    = cache_str( txt("Global Code") );
 | 
						|
	Code_Global->Content = Code_Global->Name;
 | 
						|
 | 
						|
	Code_Invalid = make_code();
 | 
						|
	code_set_global(Code_Invalid);
 | 
						|
 | 
						|
	t_empty       = (CodeTypename) make_code();
 | 
						|
	t_empty->Type = CT_Typename;
 | 
						|
	t_empty->Name = cache_str( txt("") );
 | 
						|
	code_set_global(cast(Code, t_empty));
 | 
						|
 | 
						|
	access_private       = make_code();
 | 
						|
	access_private->Type = CT_Access_Private;
 | 
						|
	access_private->Name = cache_str( txt("private:\n") );
 | 
						|
	code_set_global(cast(Code, access_private));
 | 
						|
 | 
						|
	access_protected       = make_code();
 | 
						|
	access_protected->Type = CT_Access_Protected;
 | 
						|
	access_protected->Name = cache_str( txt("protected:\n") );
 | 
						|
	code_set_global(access_protected);
 | 
						|
 | 
						|
	access_public       = make_code();
 | 
						|
	access_public->Type = CT_Access_Public;
 | 
						|
	access_public->Name = cache_str( txt("public:\n") );
 | 
						|
	code_set_global(access_public);
 | 
						|
 | 
						|
	Str api_export_str = code(GEN_API_Export_Code);
 | 
						|
	attrib_api_export = def_attributes( api_export_str );
 | 
						|
	code_set_global(cast(Code, attrib_api_export));
 | 
						|
 | 
						|
	Str api_import_str = code(GEN_API_Import_Code);
 | 
						|
	attrib_api_import = def_attributes( api_import_str );
 | 
						|
	code_set_global(cast(Code, attrib_api_import));
 | 
						|
 | 
						|
	module_global_fragment          = make_code();
 | 
						|
	module_global_fragment->Type    = CT_Untyped;
 | 
						|
	module_global_fragment->Name    = cache_str( txt("module;") );
 | 
						|
	module_global_fragment->Content = module_global_fragment->Name;
 | 
						|
	code_set_global(cast(Code, module_global_fragment));
 | 
						|
 | 
						|
	module_private_fragment          = make_code();
 | 
						|
	module_private_fragment->Type    = CT_Untyped;
 | 
						|
	module_private_fragment->Name    = cache_str( txt("module : private;") );
 | 
						|
	module_private_fragment->Content = module_private_fragment->Name;
 | 
						|
	code_set_global(cast(Code, module_private_fragment));
 | 
						|
 | 
						|
	fmt_newline = make_code();
 | 
						|
	fmt_newline->Type = CT_NewLine;
 | 
						|
	code_set_global((Code)fmt_newline);
 | 
						|
 | 
						|
	pragma_once          = (CodePragma) make_code();
 | 
						|
	pragma_once->Type    = CT_Preprocess_Pragma;
 | 
						|
	pragma_once->Name    = cache_str( txt("once") );
 | 
						|
	pragma_once->Content = pragma_once->Name;
 | 
						|
	code_set_global((Code)pragma_once);
 | 
						|
 | 
						|
	param_varadic            = (CodeParams) make_code();
 | 
						|
	param_varadic->Type      = CT_Parameters;
 | 
						|
	param_varadic->Name      = cache_str( txt("...") );
 | 
						|
	param_varadic->ValueType = t_empty;
 | 
						|
	code_set_global((Code)param_varadic);
 | 
						|
 | 
						|
	preprocess_else = (CodePreprocessCond) make_code();
 | 
						|
	preprocess_else->Type = CT_Preprocess_Else;
 | 
						|
	code_set_global((Code)preprocess_else);
 | 
						|
 | 
						|
	preprocess_endif = (CodePreprocessCond) make_code();
 | 
						|
	preprocess_endif->Type = CT_Preprocess_EndIf;
 | 
						|
	code_set_global((Code)preprocess_endif);
 | 
						|
 | 
						|
	Str auto_str     = txt("auto");     t_auto     = def_type( auto_str );     code_set_global( t_auto );
 | 
						|
	Str void_str     = txt("void");     t_void     = def_type( void_str );     code_set_global( t_void );
 | 
						|
	Str int_str      = txt("int");      t_int      = def_type( int_str );      code_set_global( t_int  );
 | 
						|
	Str bool_str     = txt("bool");     t_bool     = def_type( bool_str );     code_set_global( t_bool );
 | 
						|
	Str char_str     = txt("char");     t_char     = def_type( char_str );     code_set_global( t_char );
 | 
						|
	Str wchar_str    = txt("wchar_t");  t_wchar_t  = def_type( wchar_str );    code_set_global( t_wchar_t );
 | 
						|
	Str class_str    = txt("class");    t_class    = def_type( class_str );    code_set_global( t_class );
 | 
						|
	Str typename_str = txt("typename"); t_typename = def_type( typename_str ); code_set_global( t_typename );
 | 
						|
 | 
						|
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
 | 
						|
	t_b32 = def_type( name(b32) ); code_set_global( t_b32 );
 | 
						|
 | 
						|
	Str s8_str  = txt("s8");  t_s8  = def_type( s8_str ); code_set_global( t_s8 );
 | 
						|
	Str s16_str = txt("s16"); t_s16 = def_type( s16_str ); code_set_global( t_s16 );
 | 
						|
	Str s32_str = txt("s32"); t_s32 = def_type( s32_str ); code_set_global( t_s32 );
 | 
						|
	Str s64_str = txt("s64"); t_s64 = def_type( s64_str ); code_set_global( t_s64 );
 | 
						|
 | 
						|
	Str u8_str  = txt("u8");  t_u8  = def_type( u8_str );  code_set_global( t_u8 );
 | 
						|
	Str u16_str = txt("u16"); t_u16 = def_type( u16_str ); code_set_global( t_u16 );
 | 
						|
	Str u32_str = txt("u32"); t_u32 = def_type( u32_str ); code_set_global( t_u32 );
 | 
						|
	Str u64_str = txt("u64"); t_u64 = def_type( u64_str ); code_set_global( t_u64 );
 | 
						|
 | 
						|
	Str ssize_str = txt("ssize"); t_ssize = def_type( ssize_str ); code_set_global( t_ssize );
 | 
						|
	Str usize_str = txt("usize"); t_usize = def_type( usize_str ); code_set_global( t_usize );
 | 
						|
 | 
						|
	Str f32_str = txt("f32"); t_f32 = def_type( f32_str ); code_set_global( t_f32 );
 | 
						|
	Str f64_str = txt("f64"); t_f64 = def_type( f64_str ); code_set_global( t_f64 );
 | 
						|
#endif
 | 
						|
 | 
						|
	spec_const            = def_specifier( Spec_Const);            code_set_global( cast(Code, spec_const ));
 | 
						|
	spec_consteval        = def_specifier( Spec_Consteval);        code_set_global( cast(Code, spec_consteval ));
 | 
						|
	spec_constexpr        = def_specifier( Spec_Constexpr);        code_set_global( cast(Code, spec_constexpr ));
 | 
						|
	spec_constinit        = def_specifier( Spec_Constinit);        code_set_global( cast(Code, spec_constinit ));
 | 
						|
	spec_extern_linkage   = def_specifier( Spec_External_Linkage); code_set_global( cast(Code, spec_extern_linkage ));
 | 
						|
	spec_final            = def_specifier( Spec_Final);            code_set_global( cast(Code, spec_final ));
 | 
						|
	spec_forceinline      = def_specifier( Spec_ForceInline);      code_set_global( cast(Code, spec_forceinline ));
 | 
						|
	spec_global           = def_specifier( Spec_Global);           code_set_global( cast(Code, spec_global ));
 | 
						|
	spec_inline           = def_specifier( Spec_Inline);           code_set_global( cast(Code, spec_inline ));
 | 
						|
	spec_internal_linkage = def_specifier( Spec_Internal_Linkage); code_set_global( cast(Code, spec_internal_linkage ));
 | 
						|
	spec_local_persist    = def_specifier( Spec_Local_Persist);    code_set_global( cast(Code, spec_local_persist ));
 | 
						|
	spec_mutable          = def_specifier( Spec_Mutable);          code_set_global( cast(Code, spec_mutable ));
 | 
						|
	spec_neverinline      = def_specifier( Spec_NeverInline);      code_set_global( cast(Code, spec_neverinline ));
 | 
						|
	spec_noexcept         = def_specifier( Spec_NoExceptions);     code_set_global( cast(Code, spec_noexcept ));
 | 
						|
	spec_override         = def_specifier( Spec_Override);         code_set_global( cast(Code, spec_override ));
 | 
						|
	spec_ptr              = def_specifier( Spec_Ptr);              code_set_global( cast(Code, spec_ptr ));
 | 
						|
	spec_pure             = def_specifier( Spec_Pure);             code_set_global( cast(Code, spec_pure ));
 | 
						|
	spec_ref              = def_specifier( Spec_Ref);              code_set_global( cast(Code, spec_ref ));
 | 
						|
	spec_register         = def_specifier( Spec_Register);         code_set_global( cast(Code, spec_register ));
 | 
						|
	spec_rvalue           = def_specifier( Spec_RValue);           code_set_global( cast(Code, spec_rvalue ));
 | 
						|
	spec_static_member    = def_specifier( Spec_Static);           code_set_global( cast(Code, spec_static_member ));
 | 
						|
	spec_thread_local     = def_specifier( Spec_Thread_Local);     code_set_global( cast(Code, spec_thread_local ));
 | 
						|
	spec_virtual          = def_specifier( Spec_Virtual);          code_set_global( cast(Code, spec_virtual ));
 | 
						|
	spec_volatile         = def_specifier( Spec_Volatile);         code_set_global( cast(Code, spec_volatile ));
 | 
						|
 | 
						|
	spec_local_persist = def_specifiers( 1, Spec_Local_Persist );
 | 
						|
	code_set_global(cast(Code, spec_local_persist));
 | 
						|
 | 
						|
	if (enum_underlying_macro.Name.Len == 0) {
 | 
						|
		enum_underlying_macro.Name  = txt("enum_underlying");
 | 
						|
		enum_underlying_macro.Type  = MT_Expression;
 | 
						|
		enum_underlying_macro.Flags = MF_Functional;
 | 
						|
	}
 | 
						|
	register_macro(enum_underlying_macro);
 | 
						|
}
 | 
						|
 | 
						|
void init(Context* ctx)
 | 
						|
{
 | 
						|
	do_once() {
 | 
						|
		context_counter = 0;
 | 
						|
	}
 | 
						|
	AllocatorInfo fallback_allocator = { & fallback_allocator_proc, nullptr };
 | 
						|
	
 | 
						|
	b32 using_fallback_allocator = false;
 | 
						|
	if (ctx->Allocator_DyanmicContainers.Proc == nullptr) {
 | 
						|
		ctx->Allocator_DyanmicContainers = fallback_allocator;
 | 
						|
		using_fallback_allocator = true;
 | 
						|
	}
 | 
						|
	if (ctx->Allocator_Pool.Proc == nullptr ) {
 | 
						|
		ctx->Allocator_Pool = fallback_allocator;
 | 
						|
		using_fallback_allocator = true;
 | 
						|
	}
 | 
						|
	if (ctx->Allocator_StrCache.Proc == nullptr) {
 | 
						|
		ctx->Allocator_StrCache = fallback_allocator;
 | 
						|
		using_fallback_allocator = true;
 | 
						|
	}
 | 
						|
	if (ctx->Allocator_Temp.Proc == nullptr) {
 | 
						|
		ctx->Allocator_Temp = fallback_allocator;
 | 
						|
		using_fallback_allocator = true;
 | 
						|
	}
 | 
						|
	// Setup fallback allocator
 | 
						|
	if (using_fallback_allocator)
 | 
						|
	{
 | 
						|
		ctx->Fallback_AllocatorBuckets = array_init_reserve(Arena, heap(), 128 );
 | 
						|
		if ( ctx->Fallback_AllocatorBuckets == nullptr )
 | 
						|
			GEN_FATAL( "Failed to reserve memory for Fallback_AllocatorBuckets");
 | 
						|
 | 
						|
		Arena bucket = arena_init_from_allocator( heap(), ctx->InitSize_Fallback_Allocator_Bucket_Size );
 | 
						|
		if ( bucket.PhysicalStart == nullptr )
 | 
						|
			GEN_FATAL( "Failed to create first bucket for Fallback_AllocatorBuckets");
 | 
						|
 | 
						|
		array_append( ctx->Fallback_AllocatorBuckets, bucket );
 | 
						|
	}
 | 
						|
 | 
						|
	if (ctx->Max_CommentLineLength == 0) {
 | 
						|
		ctx->Max_CommentLineLength = 1024;
 | 
						|
	}
 | 
						|
	if (ctx->Max_StrCacheLength == 0) {
 | 
						|
		ctx->Max_StrCacheLength = kilobytes(512);
 | 
						|
	}
 | 
						|
 | 
						|
	if (ctx->InitSize_BuilderBuffer == 0) {
 | 
						|
		ctx->InitSize_BuilderBuffer = megabytes(2);
 | 
						|
	}
 | 
						|
	if (ctx->InitSize_CodePoolsArray == 0) { 
 | 
						|
		ctx->InitSize_CodePoolsArray = 16; 
 | 
						|
	}
 | 
						|
	if (ctx->InitSize_StringArenasArray == 0) {
 | 
						|
		ctx->InitSize_StringArenasArray = 16; 
 | 
						|
	}
 | 
						|
	if (ctx->CodePool_NumBlocks == 0) {
 | 
						|
		ctx->CodePool_NumBlocks = kilobytes(16);
 | 
						|
	}
 | 
						|
 | 
						|
	if (ctx->InitSize_LexerTokens == 0 ) {
 | 
						|
		ctx->InitSize_LexerTokens = kilobytes(64);
 | 
						|
	}
 | 
						|
	if (ctx->SizePer_StringArena == 0) {
 | 
						|
		ctx->SizePer_StringArena = megabytes(1);
 | 
						|
	}
 | 
						|
 | 
						|
	if (ctx->InitSize_Fallback_Allocator_Bucket_Size == 0) { 
 | 
						|
		ctx->InitSize_Fallback_Allocator_Bucket_Size = megabytes(8);
 | 
						|
	}
 | 
						|
 | 
						|
	if (ctx->InitSize_StrCacheTable == 0)
 | 
						|
	{
 | 
						|
		ctx->InitSize_StrCacheTable = kilobytes(8);
 | 
						|
	}
 | 
						|
	if (ctx->InitSize_MacrosTable == 0)
 | 
						|
	{
 | 
						|
		ctx->InitSize_MacrosTable = kilobytes(8);
 | 
						|
	}
 | 
						|
 | 
						|
	if (ctx->Logger == nullptr) {
 | 
						|
		ctx->Logger = & fallback_logger;
 | 
						|
	}
 | 
						|
 | 
						|
	// Override the current context (user has to put it back if unwanted).
 | 
						|
	_ctx = ctx;
 | 
						|
 | 
						|
	// Setup the arrays
 | 
						|
	{
 | 
						|
		ctx->CodePools = array_init_reserve(Pool, ctx->Allocator_DyanmicContainers, ctx->InitSize_CodePoolsArray );
 | 
						|
		if ( ctx->CodePools == nullptr )
 | 
						|
			GEN_FATAL( "gen::init: Failed to initialize the CodePools array" );
 | 
						|
 | 
						|
		ctx->StringArenas = array_init_reserve(Arena, ctx->Allocator_DyanmicContainers, ctx->InitSize_StringArenasArray );
 | 
						|
		if ( ctx->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( ctx->Allocator_Pool, ctx->CodePool_NumBlocks, size_of(AST) );
 | 
						|
		if ( code_pool.PhysicalStart == nullptr )
 | 
						|
			GEN_FATAL( "gen::init: Failed to initialize the code pool" );
 | 
						|
		array_append( ctx->CodePools, code_pool );
 | 
						|
 | 
						|
		// TODO(Ed): Eventually the string arenas needs to be phased out for a dedicated string slab allocator
 | 
						|
		Arena strbuilder_arena = arena_init_from_allocator( ctx->Allocator_StrCache, ctx->SizePer_StringArena );
 | 
						|
		if ( strbuilder_arena.PhysicalStart == nullptr )
 | 
						|
			GEN_FATAL( "gen::init: Failed to initialize the string arena" );
 | 
						|
		array_append( ctx->StringArenas, strbuilder_arena );
 | 
						|
	}
 | 
						|
	// Setup the hash tables
 | 
						|
	{
 | 
						|
		ctx->StrCache = hashtable_init_reserve(StrCached, ctx->Allocator_DyanmicContainers, ctx->InitSize_StrCacheTable);
 | 
						|
		if ( ctx->StrCache.Entries == nullptr )
 | 
						|
			GEN_FATAL( "gen::init: Failed to initialize the StringCache");
 | 
						|
 | 
						|
		ctx->Macros = hashtable_init_reserve(Macro, ctx->Allocator_DyanmicContainers, ctx->InitSize_MacrosTable);
 | 
						|
		if (ctx->Macros.Hashes == nullptr || ctx->Macros.Entries == nullptr) {
 | 
						|
			GEN_FATAL( "gen::init: Failed to initialize the PreprocessMacros table" );
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	define_constants();
 | 
						|
	parser_init(ctx);
 | 
						|
 | 
						|
	++ context_counter;
 | 
						|
}
 | 
						|
 | 
						|
void deinit(Context* ctx)
 | 
						|
{
 | 
						|
	GEN_ASSERT(context_counter);
 | 
						|
	GEN_ASSERT_MSG(context_counter > 0, "Attempted to deinit a context that for some reason wan't accounted for!");
 | 
						|
	usize index = 0;
 | 
						|
	usize left  = array_num(ctx->CodePools);
 | 
						|
	do
 | 
						|
	{
 | 
						|
		Pool* code_pool = & ctx->CodePools[index];
 | 
						|
		pool_free(code_pool);
 | 
						|
		index++;
 | 
						|
	}
 | 
						|
	while ( left--, left );
 | 
						|
 | 
						|
	index = 0;
 | 
						|
	left  = array_num(ctx->StringArenas);
 | 
						|
	do
 | 
						|
	{
 | 
						|
		Arena* strbuilder_arena = & ctx->StringArenas[index];
 | 
						|
		arena_free(strbuilder_arena);
 | 
						|
		index++;
 | 
						|
	}
 | 
						|
	while ( left--, left );
 | 
						|
 | 
						|
	hashtable_destroy(ctx->StrCache);
 | 
						|
 | 
						|
	array_free( ctx->CodePools);
 | 
						|
	array_free( ctx->StringArenas);
 | 
						|
 | 
						|
	hashtable_destroy(ctx->Macros);
 | 
						|
 | 
						|
	left  = array_num( ctx->Fallback_AllocatorBuckets);
 | 
						|
	if (left)
 | 
						|
	{
 | 
						|
		index = 0;
 | 
						|
		do
 | 
						|
		{
 | 
						|
			Arena* bucket = & ctx->Fallback_AllocatorBuckets[ index ];
 | 
						|
			arena_free(bucket);
 | 
						|
			index++;
 | 
						|
		}
 | 
						|
		while ( left--, left );
 | 
						|
		array_free( ctx->Fallback_AllocatorBuckets);
 | 
						|
	}
 | 
						|
	parser_deinit(ctx);
 | 
						|
 | 
						|
	if (_ctx == ctx) 
 | 
						|
		_ctx = nullptr;
 | 
						|
	-- context_counter;
 | 
						|
 | 
						|
	Context wipe = {};
 | 
						|
	* ctx = wipe;
 | 
						|
}
 | 
						|
 | 
						|
Context* get_context() { 
 | 
						|
	return _ctx;
 | 
						|
}
 | 
						|
 | 
						|
void reset(Context* ctx)
 | 
						|
{
 | 
						|
	s32 index = 0;
 | 
						|
	s32 left  = array_num(ctx->CodePools);
 | 
						|
	do
 | 
						|
	{
 | 
						|
		Pool* code_pool = & ctx->CodePools[index];
 | 
						|
		pool_clear(code_pool);
 | 
						|
		index++;
 | 
						|
	}
 | 
						|
	while ( left--, left );
 | 
						|
 | 
						|
	index = 0;
 | 
						|
	left  = array_num(ctx->StringArenas);
 | 
						|
	do
 | 
						|
	{
 | 
						|
		Arena* strbuilder_arena = & ctx->StringArenas[index];
 | 
						|
		strbuilder_arena->TotalUsed = 0;;
 | 
						|
		index++;
 | 
						|
	}
 | 
						|
	while ( left--, left );
 | 
						|
 | 
						|
	hashtable_clear(ctx->StrCache);
 | 
						|
	hashtable_clear(ctx->Macros);
 | 
						|
	define_constants();
 | 
						|
}
 | 
						|
 | 
						|
void set_context(Context* new_ctx) {
 | 
						|
	GEN_ASSERT(new_ctx);
 | 
						|
	_ctx = new_ctx;
 | 
						|
}
 | 
						|
 | 
						|
AllocatorInfo get_cached_str_allocator( s32 str_length )
 | 
						|
{
 | 
						|
	Arena* last     = array_back(_ctx->StringArenas);
 | 
						|
	usize  size_req = str_length + sizeof(StrBuilderHeader) + sizeof(char*);
 | 
						|
	if ( last->TotalUsed + scast(ssize, size_req) > last->TotalSize )
 | 
						|
	{
 | 
						|
		Arena new_arena = arena_init_from_allocator( _ctx->Allocator_StrCache, _ctx->SizePer_StringArena );
 | 
						|
		if ( ! array_append( _ctx->StringArenas, new_arena ) )
 | 
						|
			GEN_FATAL( "gen::get_cached_str_allocator: Failed to allocate a new string arena" );
 | 
						|
 | 
						|
		last = array_back( _ctx->StringArenas);
 | 
						|
	}
 | 
						|
	return arena_allocator_info(last);
 | 
						|
}
 | 
						|
 | 
						|
// Will either make or retrive a code string.
 | 
						|
StrCached cache_str( Str str )
 | 
						|
{
 | 
						|
	if (str.Len > _ctx->Max_StrCacheLength) {
 | 
						|
		// Do not cache the string, just shove into the arena and and return it.
 | 
						|
		Str result = strbuilder_to_str( strbuilder_make_str( get_cached_str_allocator( str.Len ), str ));
 | 
						|
		return result;
 | 
						|
	}
 | 
						|
	u64 key = crc32( str.Ptr, str.Len ); {
 | 
						|
		StrCached* result = hashtable_get( _ctx->StrCache, key );
 | 
						|
		if ( result )
 | 
						|
			return * result;
 | 
						|
	}
 | 
						|
	Str result = strbuilder_to_str( strbuilder_make_str( get_cached_str_allocator( str.Len ), str ));
 | 
						|
	hashtable_set( _ctx->StrCache, key, result );
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
// Used internally to retireve a Code object form the CodePool.
 | 
						|
Code make_code()
 | 
						|
{
 | 
						|
	Pool* allocator = array_back( _ctx->CodePools);
 | 
						|
	if ( allocator->FreeList == nullptr )
 | 
						|
	{
 | 
						|
		Pool code_pool = pool_init( _ctx->Allocator_Pool, _ctx->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 ( ! array_append( _ctx->CodePools, code_pool ) )
 | 
						|
			GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePools failed to append new pool." );
 | 
						|
 | 
						|
		allocator = array_back( _ctx->CodePools);
 | 
						|
	}
 | 
						|
	Code result = { rcast( AST*, alloc( pool_allocator_info(allocator), sizeof(AST) )) };
 | 
						|
	mem_set( rcast(void*, cast(AST*, result)), 0, sizeof(AST) );
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
Macro* lookup_macro( Str name ) {
 | 
						|
	u32 key = crc32( name.Ptr, name.Len );
 | 
						|
	return hashtable_get( _ctx->Macros, key );
 | 
						|
}
 | 
						|
 | 
						|
void register_macro( Macro macro ) {
 | 
						|
	GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
 | 
						|
	GEN_ASSERT(macro.Name.Len > 0);
 | 
						|
	u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
 | 
						|
	macro.Name = cache_str(macro.Name);
 | 
						|
	hashtable_set( _ctx->Macros, key, macro );
 | 
						|
}
 | 
						|
 | 
						|
void register_macros( s32 num, ... )
 | 
						|
{
 | 
						|
	GEN_ASSERT(num > 0);
 | 
						|
	va_list va;
 | 
						|
	va_start(va, num);
 | 
						|
	do
 | 
						|
	{
 | 
						|
		Macro macro = va_arg(va, Macro);
 | 
						|
		GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
 | 
						|
		GEN_ASSERT(macro.Name.Len > 0);
 | 
						|
		macro.Name = cache_str(macro.Name);
 | 
						|
 | 
						|
		u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
 | 
						|
		hashtable_set( _ctx->Macros, key, macro );
 | 
						|
	}
 | 
						|
	while (num--, num > 0);
 | 
						|
	va_end(va);
 | 
						|
}
 | 
						|
 | 
						|
void register_macros_arr( s32 num,  Macro* macros )
 | 
						|
{
 | 
						|
	GEN_ASSERT(num > 0);
 | 
						|
	do
 | 
						|
	{
 | 
						|
		Macro macro = * macros;
 | 
						|
		GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
 | 
						|
		GEN_ASSERT(macro.Name.Len > 0);
 | 
						|
		macro.Name = cache_str(macro.Name);
 | 
						|
 | 
						|
		u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
 | 
						|
		hashtable_set( _ctx->Macros, key, macro );
 | 
						|
		++ macros;
 | 
						|
	}
 | 
						|
	while (num--, num > 0);
 | 
						|
}
 |