mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-10-30 06:20:52 -07:00 
			
		
		
		
	"compentiazation" of gen.hpp and gen.cpp
This commit is contained in:
		| @@ -5,6 +5,21 @@ Things related to the editor and scanner are in their own respective files. (Ex: | ||||
|  | ||||
| Dependencies are within `gen.dep.<hpp/cpp>` | ||||
|  | ||||
| The library is fragmented into a series of headers and sources files meant to be scanned in and then generated to a tailored format for the target | ||||
| `gen` files. | ||||
|  | ||||
| Both libraries use *pre-generated* (self-hosting I guess) version of the library to then generate the latest version of itself. | ||||
| (sort of a verification that the generated version is equivalent) | ||||
|  | ||||
| The default `gen.bootstrap.cpp` located in the project folder is meant to be produce a standard segmeneted library, where the components of the library | ||||
| have relatively dedicated header and source files. With dependencies included at the top of the file and each header starting with a pragma once. | ||||
|  | ||||
| `gen.singleheader.cpp` in the single header folder with its own `meson.build` generates the library as a single header `gen.hpp`.  | ||||
| Following the same convention seen in the gb, stb, and zpl libraries. | ||||
|  | ||||
| Use those to get a general idea of how to make your own tailored version. | ||||
|  | ||||
| If the naming convention is undesired, the `gencpp.refactor` script can be used with the [refactor]() | ||||
|  | ||||
| ## gen.hpp | ||||
|  | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										64
									
								
								project/components/gen.ast_case_macros.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								project/components/gen.ast_case_macros.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| #	define AST_BODY_CLASS_UNALLOWED_TYPES \ | ||||
| 	case PlatformAttributes:                      \ | ||||
| 	case Class_Body:                      \ | ||||
| 	case Enum_Body:                       \ | ||||
| 	case Extern_Linkage:                  \ | ||||
| 	case Function_Body:                   \ | ||||
| 	case Function_Fwd:                    \ | ||||
| 	case Global_Body:                     \ | ||||
| 	case Namespace:                       \ | ||||
| 	case Namespace_Body:                  \ | ||||
| 	case Operator:                        \ | ||||
| 	case Operator_Fwd:                    \ | ||||
| 	case Parameters:                      \ | ||||
| 	case Specifiers:                      \ | ||||
| 	case Struct_Body:                     \ | ||||
| 	case Typename: | ||||
|  | ||||
| #	define AST_BODY_FUNCTION_UNALLOWED_TYPES \ | ||||
| 	case Access_Public:                      \ | ||||
| 	case Access_Protected:                   \ | ||||
| 	case Access_Private:                     \ | ||||
| 	case PlatformAttributes:                         \ | ||||
| 	case Class_Body:                         \ | ||||
| 	case Enum_Body:                          \ | ||||
| 	case Extern_Linkage:                     \ | ||||
| 	case Friend:                             \ | ||||
| 	case Function_Body:                      \ | ||||
| 	case Function_Fwd:                       \ | ||||
| 	case Global_Body:                        \ | ||||
| 	case Namespace:                          \ | ||||
| 	case Namespace_Body:                     \ | ||||
| 	case Operator:                           \ | ||||
| 	case Operator_Fwd:                       \ | ||||
| 	case Operator_Member:                    \ | ||||
| 	case Operator_Member_Fwd:                \ | ||||
| 	case Parameters:                         \ | ||||
| 	case Specifiers:                         \ | ||||
| 	case Struct_Body:                        \ | ||||
| 	case Typename: | ||||
|  | ||||
| #	define AST_BODY_GLOBAL_UNALLOWED_TYPES \ | ||||
| 	case Access_Public: 				   \ | ||||
| 	case Access_Protected: 				   \ | ||||
| 	case Access_Private: 				   \ | ||||
| 	case PlatformAttributes:                       \ | ||||
| 	case Class_Body: 					   \ | ||||
| 	case Enum_Body: 					   \ | ||||
| 	case Execution: 					   \ | ||||
| 	case Friend: 						   \ | ||||
| 	case Function_Body: 				   \ | ||||
| 	case Global_Body: 					   \ | ||||
| 	case Namespace_Body: 				   \ | ||||
| 	case Operator_Member: 				   \ | ||||
| 	case Operator_Member_Fwd: 			   \ | ||||
| 	case Parameters: 					   \ | ||||
| 	case Specifiers: 					   \ | ||||
| 	case Struct_Body: 					   \ | ||||
| 	case Typename: | ||||
|  | ||||
| #	define AST_BODY_EXPORT_UNALLOWED_TYPES         AST_BODY_GLOBAL_UNALLOWED_TYPES | ||||
| #	define AST_BODY_NAMESPACE_UNALLOWED_TYPES      AST_BODY_GLOBAL_UNALLOWED_TYPES | ||||
| #	define AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES AST_BODY_GLOBAL_UNALLOWED_TYPES | ||||
|  | ||||
| #	define AST_BODY_STRUCT_UNALLOWED_TYPES         AST_BODY_CLASS_UNALLOWED_TYPES | ||||
							
								
								
									
										86
									
								
								project/components/gen.data.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								project/components/gen.data.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| #pragma region StaticData | ||||
| // TODO : Convert global allocation strategy to use a slab allocation strategy. | ||||
| global AllocatorInfo  GlobalAllocator; | ||||
| global Array<Arena>   Global_AllocatorBuckets; | ||||
|  | ||||
| global Array< Pool >  CodePools         = { nullptr }; | ||||
| global Array< Arena > StringArenas      = { nullptr }; | ||||
|  | ||||
| global StringTable StringCache; | ||||
|  | ||||
| global Arena LexArena; | ||||
|  | ||||
| global AllocatorInfo Allocator_DataArrays       = heap(); | ||||
| global AllocatorInfo Allocator_CodePool         = heap(); | ||||
| global AllocatorInfo Allocator_Lexer            = heap(); | ||||
| global AllocatorInfo Allocator_StringArena      = heap(); | ||||
| global AllocatorInfo Allocator_StringTable      = heap(); | ||||
| global AllocatorInfo Allocator_TypeTable        = heap(); | ||||
| #pragma endregion StaticData | ||||
|  | ||||
| #pragma region Constants | ||||
| global CodeType t_empty; | ||||
| global CodeType t_auto; | ||||
| global CodeType t_void; | ||||
| global CodeType t_int; | ||||
| global CodeType t_bool; | ||||
| global CodeType t_char; | ||||
| global CodeType t_wchar_t; | ||||
| global CodeType t_class; | ||||
| global CodeType t_typename; | ||||
|  | ||||
| #ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| global CodeType t_b32; | ||||
|  | ||||
| global CodeType t_s8; | ||||
| global CodeType t_s16; | ||||
| global CodeType t_s32; | ||||
| global CodeType t_s64; | ||||
|  | ||||
| global CodeType t_u8; | ||||
| global CodeType t_u16; | ||||
| global CodeType t_u32; | ||||
| global CodeType t_u64; | ||||
|  | ||||
| global CodeType t_sw; | ||||
| global CodeType t_uw; | ||||
|  | ||||
| global CodeType t_f32; | ||||
| global CodeType t_f64; | ||||
| #endif | ||||
|  | ||||
| global CodeParam param_varadic; | ||||
|  | ||||
| global CodeAttributes attrib_api_export; | ||||
| global CodeAttributes attrib_api_import; | ||||
|  | ||||
| global Code access_public; | ||||
| global Code access_protected; | ||||
| global Code access_private; | ||||
|  | ||||
| global Code module_global_fragment; | ||||
| global Code module_private_fragment; | ||||
|  | ||||
| global Code pragma_once; | ||||
|  | ||||
| global CodeSpecifiers spec_const; | ||||
| global CodeSpecifiers spec_consteval; | ||||
| global CodeSpecifiers spec_constexpr; | ||||
| global CodeSpecifiers spec_constinit; | ||||
| global CodeSpecifiers spec_extern_linkage; | ||||
| global CodeSpecifiers spec_final; | ||||
| global CodeSpecifiers spec_global; | ||||
| global CodeSpecifiers spec_inline; | ||||
| global CodeSpecifiers spec_internal_linkage; | ||||
| global CodeSpecifiers spec_local_persist; | ||||
| global CodeSpecifiers spec_mutable; | ||||
| global CodeSpecifiers spec_override; | ||||
| global CodeSpecifiers spec_ptr; | ||||
| global CodeSpecifiers spec_ref; | ||||
| global CodeSpecifiers spec_register; | ||||
| global CodeSpecifiers spec_rvalue; | ||||
| global CodeSpecifiers spec_static_member; | ||||
| global CodeSpecifiers spec_thread_local; | ||||
| global CodeSpecifiers spec_virtual; | ||||
| global CodeSpecifiers spec_volatile; | ||||
| #pragma endregion Constants | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										520
									
								
								project/components/gen.header_end.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										520
									
								
								project/components/gen.header_end.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,520 @@ | ||||
| #pragma region Inlines | ||||
|  | ||||
| void AST::append( AST* other ) | ||||
| { | ||||
| 	if ( other->Parent ) | ||||
| 		other = other->duplicate(); | ||||
|  | ||||
| 	other->Parent = this; | ||||
|  | ||||
| 	if ( Front == nullptr ) | ||||
| 	{ | ||||
| 		Front = other; | ||||
| 		Back  = other; | ||||
|  | ||||
| 		NumEntries++; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	AST* | ||||
| 		Current       = Back; | ||||
| 	Current->Next = other; | ||||
| 	other->Prev   = Current; | ||||
| 	Back          = other; | ||||
| 	NumEntries++; | ||||
| } | ||||
|  | ||||
| char const* AST::debug_str() | ||||
| { | ||||
| 	char const* fmt = stringize( | ||||
| 	                  \nCode Debug: | ||||
| 	                  \nType    : %s | ||||
| 	                  \nParent  : %s | ||||
| 	                  \nName    : %s | ||||
| 	                  \nComment : %s | ||||
| 	                  ); | ||||
|  | ||||
| 	// These should be used immediately in a log. | ||||
| 	// Thus if its desired to keep the debug str | ||||
| 	// for multiple calls to bprintf, | ||||
| 	// allocate this to proper string. | ||||
| 	return str_fmt_buf( fmt | ||||
| 	                   ,	type_str() | ||||
| 	                   ,	Parent   ? Parent->Name : "" | ||||
| 	                   ,	Name     ? Name         : "" | ||||
| 	                   ); | ||||
| } | ||||
|  | ||||
| Code& AST::entry( u32 idx ) | ||||
| { | ||||
| 	AST** current = & Front; | ||||
| 	while ( idx >= 0 && current != nullptr ) | ||||
| 	{ | ||||
| 		if ( idx == 0 ) | ||||
| 			return * rcast( Code*, current); | ||||
|  | ||||
| 		current = & ( * current )->Next; | ||||
| 		idx--; | ||||
| 	} | ||||
|  | ||||
| 	return * rcast( Code*, current); | ||||
| } | ||||
|  | ||||
| bool AST::has_entries() | ||||
| { | ||||
| 	return NumEntries; | ||||
| } | ||||
|  | ||||
| char const* AST::type_str() | ||||
| { | ||||
| 	return ECode::to_str( Type ); | ||||
| } | ||||
|  | ||||
| AST::operator Code() | ||||
| { | ||||
| 	return { this }; | ||||
| } | ||||
|  | ||||
| Code& Code::operator ++() | ||||
| { | ||||
| 	if ( ast ) | ||||
| 		ast = ast->Next; | ||||
|  | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| #pragma region AST & Code Gen Common | ||||
| #define Define_CodeImpl( Typename )                                                  \ | ||||
| char const* Typename::debug_str()                                                    \ | ||||
| {                                                                                    \ | ||||
| 	if ( ast == nullptr )                                                            \ | ||||
| 		return "Code::debug_str: AST is null!";                                      \ | ||||
| 	                                                                                 \ | ||||
| 	return rcast(AST*, ast)->debug_str();                                            \ | ||||
| }                                                                                    \ | ||||
| Code Typename::duplicate()														     \ | ||||
| {                                                                                    \ | ||||
| 	if ( ast == nullptr )                                                            \ | ||||
| 	{                                                                                \ | ||||
| 		log_failure("Code::duplicate: Cannot duplicate code, AST is null!");         \ | ||||
| 		return Code::Invalid;                                                        \ | ||||
| 	}                                                                                \ | ||||
| 	                                                                                 \ | ||||
| 	return { rcast(AST*, ast)->duplicate() };                                        \ | ||||
| }                                                                                    \ | ||||
| bool Typename::is_equal( Code other )                                                \ | ||||
| {                                                                                    \ | ||||
| 	if ( ast == nullptr || other.ast == nullptr )                                    \ | ||||
| 	{                                                                                \ | ||||
| 		log_failure("Code::is_equal: Cannot compare code, AST is null!");            \ | ||||
| 		return false;                                                                \ | ||||
| 	}                                                                                \ | ||||
|                                                                                      \ | ||||
| 	return rcast(AST*, ast)->is_equal( other.ast );                                  \ | ||||
| }                                                                                    \ | ||||
| bool Typename::is_valid()                                                            \ | ||||
| {                                                                                    \ | ||||
| 	return (AST*) ast != nullptr && rcast( AST*, ast)->Type != CodeT::Invalid;       \ | ||||
| }                                                                                    \ | ||||
| void Typename::set_global()                                                          \ | ||||
| {                                                                                    \ | ||||
| 	if ( ast == nullptr )                                                            \ | ||||
| 	{                                                                                \ | ||||
| 		log_failure("Code::set_global: Cannot set code as global, AST is null!");    \ | ||||
| 		return;                                                                      \ | ||||
| 	}                                                                                \ | ||||
| 	                                                                                 \ | ||||
| 	rcast(AST*, ast)->Parent = Code::Global.ast;                                     \ | ||||
| }                                                                                    \ | ||||
| String Typename::to_string()													     \ | ||||
| {                                                                                    \ | ||||
| 	if ( ast == nullptr )                                                            \ | ||||
| 	{                                                                                \ | ||||
| 	log_failure("Code::to_string: Cannot convert code to string, AST is null!");     \ | ||||
| 	return { nullptr };                                                              \ | ||||
| 	}                                                                                \ | ||||
| 	                                                                                 \ | ||||
| 	return rcast(AST*, ast)->to_string();                                            \ | ||||
| }                                                                                    \ | ||||
| Typename& Typename::operator =( Code other )                                         \ | ||||
| {                                                                                    \ | ||||
| 	if ( other.ast && other->Parent )                                                \ | ||||
| 	{                                                                                \ | ||||
| 		ast = rcast( decltype(ast), other.ast->duplicate() );                        \ | ||||
| 		rcast( AST*, ast)->Parent = nullptr;                                         \ | ||||
| 	}                                                                                \ | ||||
|                                                                                      \ | ||||
| 	ast = rcast( decltype(ast), other.ast );                                         \ | ||||
| 	return *this;                                                                    \ | ||||
| }                                                                                    \ | ||||
| bool Typename::operator ==( Code other )                                             \ | ||||
| {                                                                                    \ | ||||
| 	return (AST*) ast == other.ast;                                                  \ | ||||
| }                                                                                    \ | ||||
| bool Typename::operator !=( Code other )                                             \ | ||||
| {                                                                                    \ | ||||
| 	return (AST*) ast != other.ast;                                                  \ | ||||
| } | ||||
|  | ||||
| Define_CodeImpl( Code ); | ||||
| Define_CodeImpl( CodeBody ); | ||||
| Define_CodeImpl( CodeAttributes ); | ||||
| Define_CodeImpl( CodeComment ); | ||||
| Define_CodeImpl( CodeClass ); | ||||
| Define_CodeImpl( CodeEnum ); | ||||
| Define_CodeImpl( CodeExec ); | ||||
| Define_CodeImpl( CodeExtern ); | ||||
| Define_CodeImpl( CodeInclude ); | ||||
| Define_CodeImpl( CodeFriend ); | ||||
| Define_CodeImpl( CodeFn ); | ||||
| Define_CodeImpl( CodeModule ); | ||||
| Define_CodeImpl( CodeNamespace ); | ||||
| Define_CodeImpl( CodeOperator ); | ||||
| Define_CodeImpl( CodeOpCast ); | ||||
| Define_CodeImpl( CodeParam ); | ||||
| Define_CodeImpl( CodeSpecifiers ); | ||||
| Define_CodeImpl( CodeStruct ); | ||||
| Define_CodeImpl( CodeTemplate ); | ||||
| Define_CodeImpl( CodeType ); | ||||
| Define_CodeImpl( CodeTypedef ); | ||||
| Define_CodeImpl( CodeUnion ); | ||||
| Define_CodeImpl( CodeUsing ); | ||||
| Define_CodeImpl( CodeVar ); | ||||
| #undef Define_CodeImpl | ||||
|  | ||||
| #define Define_AST_Cast( typename )              \ | ||||
| AST::operator Code ## typename()                 \ | ||||
| {                                                \ | ||||
| 	return { rcast( AST_ ## typename*, this ) }; \ | ||||
| } | ||||
|  | ||||
| Define_AST_Cast( Body ); | ||||
| Define_AST_Cast( Attributes ); | ||||
| Define_AST_Cast( Comment ); | ||||
| Define_AST_Cast( Class ); | ||||
| Define_AST_Cast( Enum ); | ||||
| Define_AST_Cast( Exec ); | ||||
| Define_AST_Cast( Extern ); | ||||
| Define_AST_Cast( Include ); | ||||
| Define_AST_Cast( Friend ); | ||||
| Define_AST_Cast( Fn ); | ||||
| Define_AST_Cast( Module ); | ||||
| Define_AST_Cast( Namespace ); | ||||
| Define_AST_Cast( Operator ); | ||||
| Define_AST_Cast( OpCast ); | ||||
| Define_AST_Cast( Param ); | ||||
| Define_AST_Cast( Struct ); | ||||
| Define_AST_Cast( Specifiers ); | ||||
| Define_AST_Cast( Template ); | ||||
| Define_AST_Cast( Type ); | ||||
| Define_AST_Cast( Typedef ); | ||||
| Define_AST_Cast( Union ); | ||||
| Define_AST_Cast( Using ); | ||||
| Define_AST_Cast( Var ); | ||||
| #undef Define_AST_Cast | ||||
|  | ||||
| #define Define_CodeCast( type )     \ | ||||
| Code::operator Code ## type() const \ | ||||
| {                                   \ | ||||
| 	return { (AST_ ## type*) ast }; \ | ||||
| } | ||||
|  | ||||
| Define_CodeCast( Attributes ); | ||||
| Define_CodeCast( Comment ); | ||||
| Define_CodeCast( Class ); | ||||
| Define_CodeCast( Exec ); | ||||
| Define_CodeCast( Enum ); | ||||
| Define_CodeCast( Extern ); | ||||
| Define_CodeCast( Include ); | ||||
| Define_CodeCast( Friend ); | ||||
| Define_CodeCast( Fn ); | ||||
| Define_CodeCast( Module ); | ||||
| Define_CodeCast( Namespace ); | ||||
| Define_CodeCast( Operator ); | ||||
| Define_CodeCast( OpCast ); | ||||
| Define_CodeCast( Param ); | ||||
| Define_CodeCast( Specifiers ); | ||||
| Define_CodeCast( Struct ); | ||||
| Define_CodeCast( Template ); | ||||
| Define_CodeCast( Type ); | ||||
| Define_CodeCast( Typedef ); | ||||
| Define_CodeCast( Union ); | ||||
| Define_CodeCast( Using ); | ||||
| Define_CodeCast( Var ); | ||||
| Define_CodeCast( Body); | ||||
| #undef Define_CodeCast | ||||
| #pragma endregion AST & Code Gen Common | ||||
|  | ||||
| void CodeClass::add_interface( CodeType type ) | ||||
| { | ||||
| 	if ( ! ast->Next ) | ||||
| 	{ | ||||
| 		ast->Next = type; | ||||
| 		ast->Last = ast->Next; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	ast->Next->Next = type; | ||||
| 	ast->Last       = ast->Next->Next; | ||||
| } | ||||
|  | ||||
| void CodeParam::append( CodeParam other ) | ||||
| { | ||||
| 	AST* self  = (AST*) ast; | ||||
| 	AST* entry = (AST*) other.ast; | ||||
|  | ||||
| 	if ( entry->Parent ) | ||||
| 		entry = entry->duplicate(); | ||||
|  | ||||
| 	entry->Parent = self; | ||||
|  | ||||
| 	if ( self->Last == nullptr ) | ||||
| 	{ | ||||
| 		self->Last = entry; | ||||
| 		self->Next = entry; | ||||
| 		self->NumEntries++; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	self->Last->Next = entry; | ||||
| 	self->Last       = entry; | ||||
| 	self->NumEntries++; | ||||
| } | ||||
|  | ||||
| CodeParam CodeParam::get( s32 idx ) | ||||
| { | ||||
| 	CodeParam param = *this; | ||||
| 	do | ||||
| 	{ | ||||
| 		if ( ! ++ param ) | ||||
| 			return { nullptr }; | ||||
|  | ||||
| 		return { (AST_Param*) param.raw()->Next }; | ||||
| 	} | ||||
| 	while ( --idx ); | ||||
|  | ||||
| 	return { nullptr }; | ||||
| } | ||||
|  | ||||
| bool CodeParam::has_entries() | ||||
| { | ||||
| 	return ast->NumEntries > 0; | ||||
| } | ||||
|  | ||||
| CodeParam& CodeParam::operator ++() | ||||
| { | ||||
| 	ast = ast->Next.ast; | ||||
| 	return * this; | ||||
| } | ||||
|  | ||||
| void CodeStruct::add_interface( CodeType type ) | ||||
| { | ||||
| 	if ( ! ast->Next ) | ||||
| 	{ | ||||
| 		ast->Next = type; | ||||
| 		ast->Last = ast->Next; | ||||
| 	} | ||||
|  | ||||
| 	ast->Next->Next = type; | ||||
| 	ast->Last       = ast->Next->Next; | ||||
| } | ||||
|  | ||||
| CodeBody def_body( CodeT type ) | ||||
| { | ||||
| 	switch ( type ) | ||||
| 	{ | ||||
| 		using namespace ECode; | ||||
| 		case Class_Body: | ||||
| 		case Enum_Body: | ||||
| 		case Export_Body: | ||||
| 		case Extern_Linkage: | ||||
| 		case Function_Body: | ||||
| 		case Global_Body: | ||||
| 		case Namespace_Body: | ||||
| 		case Struct_Body: | ||||
| 		case Union_Body: | ||||
| 			break; | ||||
|  | ||||
| 		default: | ||||
| 			log_failure( "def_body: Invalid type %s", (char const*)ECode::to_str(type) ); | ||||
| 			return (CodeBody)Code::Invalid; | ||||
| 	} | ||||
|  | ||||
| 	Code | ||||
| 		result       = make_code(); | ||||
| 	result->Type = type; | ||||
| 	return (CodeBody)result; | ||||
| } | ||||
|  | ||||
| //! Do not use directly. Use the token_fmt macro instead. | ||||
| // Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string. | ||||
| StrC token_fmt_impl( sw num, ... ) | ||||
| { | ||||
| 	local_persist thread_local | ||||
| 		char buf[GEN_PRINTF_MAXLEN] = { 0 }; | ||||
| 	mem_set( buf, 0, GEN_PRINTF_MAXLEN ); | ||||
|  | ||||
| 	va_list va; | ||||
| 	va_start(va, num ); | ||||
| 	sw result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va); | ||||
| 	va_end(va); | ||||
|  | ||||
| 	return { result, buf }; | ||||
| } | ||||
| #pragma endregion Inlines | ||||
|  | ||||
| #pragma region Constants | ||||
| #ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| 	// Predefined typename codes. Are set to readonly and are setup during gen::init() | ||||
|  | ||||
| 	extern CodeType t_b32; | ||||
|  | ||||
| 	extern CodeType t_s8; | ||||
| 	extern CodeType t_s16; | ||||
| 	extern CodeType t_s32; | ||||
| 	extern CodeType t_s64; | ||||
|  | ||||
| 	extern CodeType t_u8; | ||||
| 	extern CodeType t_u16; | ||||
| 	extern CodeType t_u32; | ||||
| 	extern CodeType t_u64; | ||||
|  | ||||
| 	extern CodeType t_sw; | ||||
| 	extern CodeType t_uw; | ||||
|  | ||||
| 	extern CodeType t_f32; | ||||
| 	extern CodeType t_f64; | ||||
| #endif | ||||
|  | ||||
| #ifndef GEN_GLOBAL_BUCKET_SIZE | ||||
| #	define GEN_GLOBAL_BUCKET_SIZE megabytes(10) | ||||
| #endif | ||||
| #ifndef GEN_CODEPOOL_NUM_BLOCKS | ||||
| #	define GEN_CODEPOOL_NUM_BLOCKS kilobytes(64) | ||||
| #endif | ||||
| #ifndef GEN_SIZE_PER_STRING_ARENA | ||||
| #	define GEN_SIZE_PER_STRING_ARENA megabytes(1) | ||||
| #endif | ||||
| #ifndef GEN_MAX_COMMENT_LINE_LENGTH | ||||
| #	define GEN_MAX_COMMENT_LINE_LENGTH 1024 | ||||
| #endif | ||||
| #ifndef GEN_MAX_NAME_LENGTH | ||||
| #	define GEN_MAX_NAME_LENGTH 128 | ||||
| #endif | ||||
| #ifndef GEN_MAX_UNTYPED_STR_LENGTH | ||||
| #	define GEN_MAX_UNTYPED_STR_LENGTH kilobytes(640) | ||||
| #endif | ||||
| #ifndef GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE | ||||
| #	define GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE kilobytes(4) | ||||
| #endif | ||||
| #ifndef GEN_LEX_ALLOCATOR_SIZE | ||||
| #	define GEN_LEX_ALLOCATOR_SIZE megabytes(10) | ||||
| #endif | ||||
| #ifndef GEN_BUILDER_STR_BUFFER_RESERVE | ||||
| #	define GEN_BUILDER_STR_BUFFER_RESERVE megabytes(1) | ||||
| #endif | ||||
|  | ||||
| // These constexprs are used for allocation behavior of data structures | ||||
| // or string handling while constructing or serializing. | ||||
| // Change them to suit your needs. | ||||
|  | ||||
| constexpr s32 InitSize_DataArrays = 16; | ||||
|  | ||||
| // NOTE: This limits the maximum size of an allocation | ||||
| // If you are generating a string larger than this, increase the size of the bucket here. | ||||
| constexpr uw  Global_BucketSize         = GEN_GLOBAL_BUCKET_SIZE; | ||||
| constexpr s32 CodePool_NumBlocks        = GEN_CODEPOOL_NUM_BLOCKS; | ||||
| constexpr s32 SizePer_StringArena       = GEN_SIZE_PER_STRING_ARENA; | ||||
|  | ||||
| constexpr s32 MaxCommentLineLength      = GEN_MAX_COMMENT_LINE_LENGTH; | ||||
| constexpr s32 MaxNameLength             = GEN_MAX_NAME_LENGTH; | ||||
| constexpr s32 MaxUntypedStrLength       = GEN_MAX_UNTYPED_STR_LENGTH; | ||||
| constexpr s32 TokenFmt_TokenMap_MemSize	= GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE; | ||||
| constexpr s32 LexAllocator_Size         = GEN_LEX_ALLOCATOR_SIZE; | ||||
| constexpr s32 Builder_StrBufferReserve  = GEN_BUILDER_STR_BUFFER_RESERVE; | ||||
|  | ||||
| extern CodeType t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance) | ||||
| extern CodeType t_auto; | ||||
| extern CodeType t_void; | ||||
| extern CodeType t_int; | ||||
| extern CodeType t_bool; | ||||
| extern CodeType t_char; | ||||
| extern CodeType t_wchar_t; | ||||
| extern CodeType t_class; | ||||
| extern CodeType t_typename; | ||||
|  | ||||
| extern CodeParam param_varadic; | ||||
|  | ||||
| extern CodeAttributes attrib_api_export; | ||||
| extern CodeAttributes attrib_api_import; | ||||
|  | ||||
| extern Code access_public; | ||||
| extern Code access_protected; | ||||
| extern Code access_private; | ||||
|  | ||||
| extern Code module_global_fragment; | ||||
| extern Code module_private_fragment; | ||||
|  | ||||
| extern Code pragma_once; | ||||
|  | ||||
| extern CodeSpecifiers spec_const; | ||||
| extern CodeSpecifiers spec_consteval; | ||||
| extern CodeSpecifiers spec_constexpr; | ||||
| extern CodeSpecifiers spec_constinit; | ||||
| extern CodeSpecifiers spec_extern_linkage; | ||||
| extern CodeSpecifiers spec_final; | ||||
| extern CodeSpecifiers spec_global; | ||||
| extern CodeSpecifiers spec_inline; | ||||
| extern CodeSpecifiers spec_internal_linkage; | ||||
| extern CodeSpecifiers spec_local_persist; | ||||
| extern CodeSpecifiers spec_mutable; | ||||
| extern CodeSpecifiers spec_override; | ||||
| extern CodeSpecifiers spec_ptr; | ||||
| extern CodeSpecifiers spec_ref; | ||||
| extern CodeSpecifiers spec_register; | ||||
| extern CodeSpecifiers spec_rvalue; | ||||
| extern CodeSpecifiers spec_static_member; | ||||
| extern CodeSpecifiers spec_thread_local; | ||||
| extern CodeSpecifiers spec_virtual; | ||||
| extern CodeSpecifiers spec_volatile; | ||||
| #pragma endregion Constants | ||||
|  | ||||
| #pragma region Macros | ||||
| #	define gen_main main | ||||
|  | ||||
| #	define __ NoCode | ||||
|  | ||||
| 	//	Convienence for defining any name used with the gen api. | ||||
| 	//  Lets you provide the length and string literal to the functions without the need for the DSL. | ||||
| #	define name( Id_ )   { sizeof(stringize( Id_ )) - 1, stringize(Id_) } | ||||
|  | ||||
| 	//  Same as name just used to indicate intention of literal for code instead of names. | ||||
| #	define code( ... ) { sizeof(stringize(__VA_ARGS__)) - 1, stringize( __VA_ARGS__ ) } | ||||
|  | ||||
| #	define args( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__ | ||||
|  | ||||
| #	define code_str( ... ) gen::untyped_str( code( __VA_ARGS__ ) ) | ||||
| #	define code_fmt( ... ) gen::untyped_str( token_fmt( __VA_ARGS__ ) ) | ||||
|  | ||||
| 	// Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string. | ||||
| #	define token_fmt( ... ) gen::token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ ) | ||||
| #pragma endregion Macros | ||||
|  | ||||
| #ifdef GEN_EXPOSE_BACKEND | ||||
| 	// Global allocator used for data with process lifetime. | ||||
| 	extern AllocatorInfo  GlobalAllocator; | ||||
| 	extern Array< Arena > Global_AllocatorBuckets; | ||||
| 	extern Array< Pool >  CodePools; | ||||
| 	extern Array< Arena > StringArenas; | ||||
|  | ||||
| 	extern StringTable StringCache; | ||||
|  | ||||
| 	extern Arena LexArena; | ||||
|  | ||||
| 	extern AllocatorInfo Allocator_DataArrays; | ||||
| 	extern AllocatorInfo Allocator_CodePool; | ||||
| 	extern AllocatorInfo Allocator_Lexer; | ||||
| 	extern AllocatorInfo Allocator_StringArena; | ||||
| 	extern AllocatorInfo Allocator_StringTable; | ||||
| 	extern AllocatorInfo Allocator_TypeTable; | ||||
| #endif | ||||
							
								
								
									
										426
									
								
								project/components/gen.interface.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										426
									
								
								project/components/gen.interface.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,426 @@ | ||||
| internal | ||||
| void* Global_Allocator_Proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw 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 ) | ||||
| 					fatal( "Failed to create bucket for Global_AllocatorBuckets"); | ||||
|  | ||||
| 				if ( ! Global_AllocatorBuckets.append( bucket ) ) | ||||
| 					fatal( "Failed to append bucket to Global_AllocatorBuckets"); | ||||
|  | ||||
| 				last = & Global_AllocatorBuckets.back(); | ||||
| 			} | ||||
|  | ||||
| 			return alloc_align( * 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 ) | ||||
| 					fatal( "Failed to create bucket for Global_AllocatorBuckets"); | ||||
|  | ||||
| 				if ( ! Global_AllocatorBuckets.append( bucket ) ) | ||||
| 					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_StrC("Global Code") ); | ||||
| 	Code::Global->Content = Code::Global->Name; | ||||
|  | ||||
| 	Code::Invalid = make_code(); | ||||
| 	Code::Invalid.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( sw ); | ||||
| 	def_constant_code_type( uw ); | ||||
|  | ||||
| 	def_constant_code_type( f32 ); | ||||
| 	def_constant_code_type( f64 ); | ||||
| #endif | ||||
| #	undef def_constant_code_type | ||||
|  | ||||
| 	t_empty = (CodeType) make_code(); | ||||
| 	t_empty->Type    = ECode::Typename; | ||||
| 	t_empty->Name    = get_cached_string( txt_StrC("") ); | ||||
| 	t_empty.set_global(); | ||||
|  | ||||
| 	param_varadic            = (CodeType) make_code(); | ||||
| 	param_varadic->Type      = ECode::Parameters; | ||||
| 	param_varadic->Name      = get_cached_string( txt_StrC("...") ); | ||||
| 	param_varadic->ValueType = t_empty; | ||||
| 	param_varadic.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(); | ||||
|  | ||||
| 	access_private       = make_code(); | ||||
| 	access_private->Type = ECode::Access_Private; | ||||
| 	access_private->Name = get_cached_string( txt_StrC("private:") ); | ||||
| 	access_private.set_global(); | ||||
|  | ||||
| 	access_protected = make_code(); | ||||
| 	access_protected->Type = ECode::Access_Protected; | ||||
| 	access_protected->Name = get_cached_string( txt_StrC("protected:") ); | ||||
| 	access_protected.set_global(); | ||||
|  | ||||
| 	access_public = make_code(); | ||||
| 	access_public->Type = ECode::Access_Public; | ||||
| 	access_public->Name = get_cached_string( txt_StrC("public:") ); | ||||
| 	access_public.set_global(); | ||||
|  | ||||
| 	module_global_fragment          = make_code(); | ||||
| 	module_global_fragment->Type    = ECode::Untyped; | ||||
| 	module_global_fragment->Name    = get_cached_string( txt_StrC("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_StrC("module : private;") ); | ||||
| 	module_private_fragment->Content = module_private_fragment->Name; | ||||
| 	module_private_fragment.set_global(); | ||||
|  | ||||
| 	pragma_once          = make_code(); | ||||
| 	pragma_once->Type    = ECode::Untyped; | ||||
| 	pragma_once->Name    = get_cached_string( txt_StrC("#pragma once") ); | ||||
| 	pragma_once->Content = pragma_once->Name; | ||||
| 	pragma_once.set_global(); | ||||
|  | ||||
| #	pragma push_macro( "global" ) | ||||
| #	pragma push_macro( "internal" ) | ||||
| #	pragma push_macro( "local_persist" ) | ||||
| #	undef global | ||||
| #	undef internal | ||||
| #	undef local_persist | ||||
|  | ||||
| #	define def_constant_spec( Type_, ... )                                    \ | ||||
| 	spec_##Type_ = def_specifiers( num_args(__VA_ARGS__), __VA_ARGS__); \ | ||||
| 	spec_##Type_.set_global(); | ||||
|  | ||||
| 	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( 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( override,         ESpecifier::Override ); | ||||
| 	def_constant_spec( ptr,              ESpecifier::Ptr ); | ||||
| 	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( "global" ) | ||||
| #	pragma pop_macro( "internal" ) | ||||
| #	pragma pop_macro( "local_persist" ) | ||||
|  | ||||
| #	undef def_constant_spec | ||||
| } | ||||
|  | ||||
| void init() | ||||
| { | ||||
| 	// Setup global allocator | ||||
| 	{ | ||||
| 		GlobalAllocator = AllocatorInfo { & Global_Allocator_Proc, nullptr }; | ||||
|  | ||||
| 		Global_AllocatorBuckets = Array<Arena>::init_reserve( heap(), 128 ); | ||||
|  | ||||
| 		if ( Global_AllocatorBuckets == nullptr ) | ||||
| 			fatal( "Failed to reserve memory for Global_AllocatorBuckets"); | ||||
|  | ||||
| 		Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); | ||||
|  | ||||
| 		if ( bucket.PhysicalStart == nullptr ) | ||||
| 			fatal( "Failed to create first bucket for Global_AllocatorBuckets"); | ||||
|  | ||||
| 		Global_AllocatorBuckets.append( bucket ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	// Setup the arrays | ||||
| 	{ | ||||
| 		CodePools = Array<Pool>::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); | ||||
|  | ||||
| 		if ( CodePools == nullptr ) | ||||
| 			fatal( "gen::init: Failed to initialize the CodePools array" ); | ||||
|  | ||||
| 		StringArenas = Array<Arena>::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); | ||||
|  | ||||
| 		if ( StringArenas == nullptr ) | ||||
| 			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 ) | ||||
| 			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 ) | ||||
| 			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 ) | ||||
| 			fatal( "gen::init: Failed to initialize the StringCache"); | ||||
| 	} | ||||
|  | ||||
| 	define_constants(); | ||||
| } | ||||
|  | ||||
| void deinit() | ||||
| { | ||||
| 	uw index = 0; | ||||
| 	uw left  = CodePools.num(); | ||||
| 	do | ||||
| 	{ | ||||
| 		Pool* code_pool = & CodePools[index]; | ||||
| 		code_pool->free(); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	index = 0; | ||||
| 	left  = StringArenas.num(); | ||||
| 	do | ||||
| 	{ | ||||
| 		Arena* string_arena = & StringArenas[index]; | ||||
| 		string_arena->free(); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	StringCache.destroy(); | ||||
|  | ||||
| 	CodePools.free(); | ||||
| 	StringArenas.free(); | ||||
|  | ||||
| 	LexArena.free(); | ||||
|  | ||||
| 	index = 0; | ||||
| 	left  = Global_AllocatorBuckets.num(); | ||||
| 	do | ||||
| 	{ | ||||
| 		Arena* bucket = & Global_AllocatorBuckets[ index ]; | ||||
| 		bucket->free(); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	Global_AllocatorBuckets.free(); | ||||
| } | ||||
|  | ||||
| void reset() | ||||
| { | ||||
| 	s32 index = 0; | ||||
| 	s32 left  = CodePools.num(); | ||||
| 	do | ||||
| 	{ | ||||
| 		Pool* code_pool = & CodePools[index]; | ||||
| 		code_pool->clear(); | ||||
| 		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(); | ||||
|  | ||||
| 	uw size_req = str_length + sizeof(String::Header) + sizeof(char*); | ||||
|  | ||||
| 	if ( last->TotalUsed + size_req > last->TotalSize ) | ||||
| 	{ | ||||
| 		Arena new_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena ); | ||||
|  | ||||
| 		if ( ! StringArenas.append( new_arena ) ) | ||||
| 			fatal( "gen::get_string_allocator: Failed to allocate a new string arena" ); | ||||
|  | ||||
| 		last = & StringArenas.back(); | ||||
| 	} | ||||
|  | ||||
| 	return * 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 ) | ||||
| 			fatal( "gen::make_code: Failed to allocate a new code pool - CodePool allcoator returned nullptr." ); | ||||
|  | ||||
| 		if ( ! CodePools.append( code_pool ) ) | ||||
| 			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, sizeof(AST) )) }; | ||||
|  | ||||
| 	result->Content         = { nullptr }; | ||||
| 	result->Prev            = { nullptr }; | ||||
| 	result->Next			= { 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; | ||||
| } | ||||
| @@ -0,0 +1,155 @@ | ||||
| // Initialize the library. | ||||
| // This currently just initializes the CodePool. | ||||
| void init(); | ||||
|  | ||||
| // Currently manually free's the arenas, code for checking for leaks. | ||||
| // However on Windows at least, it doesn't need to occur as the OS will clean up after the process. | ||||
| void deinit(); | ||||
|  | ||||
| // Clears the allocations, but doesn't return to the heap, the calls init() again. | ||||
| // Ease of use. | ||||
| void reset(); | ||||
|  | ||||
| // Used internally to retrive or make string allocations. | ||||
| // Strings are stored in a series of string arenas of fixed size (SizePer_StringArena) | ||||
| StringCached get_cached_string( StrC str ); | ||||
|  | ||||
| /* | ||||
| 	This provides a fresh Code AST. | ||||
| 	The gen interface use this as their method from getting a new AST object from the CodePool. | ||||
| 	Use this if you want to make your own API for formatting the supported Code Types. | ||||
| */ | ||||
| Code make_code(); | ||||
|  | ||||
| // Set these before calling gen's init() procedure. | ||||
| // Data | ||||
|  | ||||
| void set_allocator_data_arrays       ( AllocatorInfo data_array_allocator ); | ||||
| void set_allocator_code_pool         ( AllocatorInfo pool_allocator ); | ||||
| void set_allocator_lexer             ( AllocatorInfo lex_allocator ); | ||||
| void set_allocator_string_arena      ( AllocatorInfo string_allocator ); | ||||
| void set_allocator_string_table      ( AllocatorInfo string_allocator ); | ||||
| void set_allocator_type_table        ( AllocatorInfo type_reg_allocator ); | ||||
|  | ||||
| #pragma region Upfront | ||||
| CodeAttributes def_attributes( StrC content ); | ||||
| CodeComment    def_comment   ( StrC content ); | ||||
|  | ||||
| CodeClass def_class( StrC name | ||||
| 	, Code           body         = NoCode | ||||
| 	, CodeType       parent       = NoCode, AccessSpec access = AccessSpec::Default | ||||
| 	, CodeAttributes attributes   = NoCode | ||||
| 	, ModuleFlag     mflags       = ModuleFlag::None | ||||
| 	, CodeType*      interfaces   = nullptr, s32 num_interfaces = 0 ); | ||||
|  | ||||
| CodeEnum def_enum( StrC name | ||||
| 	, Code         body      = NoCode,      CodeType       type       = NoCode | ||||
| 	, EnumT        specifier = EnumRegular, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag   mflags    = ModuleFlag::None ); | ||||
|  | ||||
| CodeExec   def_execution  ( StrC content ); | ||||
| CodeExtern def_extern_link( StrC name, Code body ); | ||||
| CodeFriend def_friend     ( Code symbol ); | ||||
|  | ||||
| CodeFn def_function( StrC name | ||||
| 	, CodeParam      params     = NoCode, CodeType       ret_type   = NoCode, Code body = NoCode | ||||
| 	, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag mflags     = ModuleFlag::None ); | ||||
|  | ||||
| CodeInclude   def_include  ( StrC content ); | ||||
| CodeModule    def_module   ( StrC name,            ModuleFlag mflags = ModuleFlag::None ); | ||||
| CodeNamespace def_namespace( StrC name, Code body, ModuleFlag mflags = ModuleFlag::None ); | ||||
|  | ||||
| CodeOperator def_operator( OperatorT op | ||||
| 	, CodeParam      params     = NoCode, CodeType       ret_type   = NoCode, Code body = NoCode | ||||
| 	, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag     mflags     = ModuleFlag::None ); | ||||
|  | ||||
| CodeOpCast def_operator_cast( CodeType type, Code body = NoCode, CodeSpecifiers specs = NoCode ); | ||||
|  | ||||
| CodeParam      def_param    ( CodeType type, StrC name, Code value = NoCode ); | ||||
| CodeSpecifiers def_specifier( SpecifierT specifier ); | ||||
|  | ||||
| CodeStruct def_struct( StrC name | ||||
| 	, Code           body       = NoCode | ||||
| 	, CodeType       parent     = NoCode, AccessSpec access = AccessSpec::Default | ||||
| 	, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag     mflags     = ModuleFlag::None | ||||
| 	, CodeType*      interfaces = nullptr, s32 num_interfaces = 0 ); | ||||
|  | ||||
| CodeTemplate def_template( CodeParam params, Code definition, ModuleFlag mflags = ModuleFlag::None ); | ||||
|  | ||||
| CodeType    def_type   ( StrC name, Code arrayexpr = NoCode, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode ); | ||||
| CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag::None ); | ||||
|  | ||||
| CodeUnion def_union( StrC name, Code body, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag::None ); | ||||
|  | ||||
| CodeUsing def_using( StrC name, CodeType type = NoCode | ||||
| 	, CodeAttributes attributess = NoCode | ||||
| 	, ModuleFlag     mflags      = ModuleFlag::None ); | ||||
|  | ||||
| CodeUsing def_using_namespace( StrC name ); | ||||
|  | ||||
| CodeVar def_variable( CodeType type, StrC name, Code value = NoCode | ||||
| 	, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag     mflags     = ModuleFlag::None ); | ||||
|  | ||||
| // Constructs an empty body. Use AST::validate_body() to check if the body is was has valid entries. | ||||
| CodeBody def_body( CodeT type ); | ||||
|  | ||||
| // There are two options for defining a struct body, either varadically provided with the args macro to auto-deduce the arg num, | ||||
| /// or provide as an array of Code objects. | ||||
|  | ||||
| CodeBody       def_class_body      ( s32 num, ... ); | ||||
| CodeBody       def_class_body      ( s32 num, Code* codes ); | ||||
| CodeBody       def_enum_body       ( s32 num, ... ); | ||||
| CodeBody       def_enum_body       ( s32 num, Code* codes ); | ||||
| CodeBody       def_export_body     ( s32 num, ... ); | ||||
| CodeBody       def_export_body     ( s32 num, Code* codes); | ||||
| CodeBody       def_extern_link_body( s32 num, ... ); | ||||
| CodeBody       def_extern_link_body( s32 num, Code* codes ); | ||||
| CodeBody       def_function_body   ( s32 num, ... ); | ||||
| CodeBody       def_function_body   ( s32 num, Code* codes ); | ||||
| CodeBody       def_global_body     ( s32 num, ... ); | ||||
| CodeBody       def_global_body     ( s32 num, Code* codes ); | ||||
| CodeBody       def_namespace_body  ( s32 num, ... ); | ||||
| CodeBody       def_namespace_body  ( s32 num, Code* codes ); | ||||
| CodeParam      def_params          ( s32 num, ... ); | ||||
| CodeParam      def_params          ( s32 num, CodeParam* params ); | ||||
| CodeSpecifiers def_specifiers      ( s32 num, ... ); | ||||
| CodeSpecifiers def_specifiers      ( s32 num, SpecifierT* specs ); | ||||
| CodeBody       def_struct_body     ( s32 num, ... ); | ||||
| CodeBody       def_struct_body     ( s32 num, Code* codes ); | ||||
| CodeBody       def_union_body      ( s32 num, ... ); | ||||
| CodeBody       def_union_body      ( s32 num, Code* codes ); | ||||
| #pragma endregion Upfront | ||||
|  | ||||
| #pragma region Parsing | ||||
| CodeClass     parse_class        ( StrC class_def     ); | ||||
| CodeEnum      parse_enum         ( StrC enum_def      ); | ||||
| CodeBody      parse_export_body  ( StrC export_def    ); | ||||
| CodeExtern    parse_extern_link  ( StrC exten_link_def); | ||||
| CodeFriend    parse_friend       ( StrC friend_def    ); | ||||
| CodeFn        parse_function     ( StrC fn_def        ); | ||||
| CodeBody      parse_global_body  ( StrC body_def      ); | ||||
| CodeNamespace parse_namespace    ( StrC namespace_def ); | ||||
| CodeOperator  parse_operator     ( StrC operator_def  ); | ||||
| CodeOpCast    parse_operator_cast( StrC operator_def  ); | ||||
| CodeStruct    parse_struct       ( StrC struct_def    ); | ||||
| CodeTemplate  parse_template     ( StrC template_def  ); | ||||
| CodeType      parse_type         ( StrC type_def      ); | ||||
| CodeTypedef   parse_typedef      ( StrC typedef_def   ); | ||||
| CodeUnion     parse_union        ( StrC union_def     ); | ||||
| CodeUsing     parse_using        ( StrC using_def     ); | ||||
| CodeVar       parse_variable     ( StrC var_def       ); | ||||
| #pragma endregion Parsing | ||||
|  | ||||
| #pragma region Untyped text | ||||
| sw   token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va ); | ||||
| StrC token_fmt_impl( sw, ... ); | ||||
|  | ||||
| Code untyped_str      ( StrC content); | ||||
| Code untyped_fmt      ( char const* fmt, ... ); | ||||
| Code untyped_token_fmt( char const* fmt, s32 num_tokens, ... ); | ||||
| #pragma endregion Untyped text | ||||
|  | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -0,0 +1,363 @@ | ||||
| using LogFailType = sw(*)(char const*, ...); | ||||
|  | ||||
| // By default this library will either crash or exit if an error is detected while generating codes. | ||||
| // Even if set to not use fatal, fatal will still be used for memory failures as the library is unusable when they occur. | ||||
| #ifdef GEN_DONT_USE_FATAL | ||||
| 	constexpr LogFailType log_failure = log_fmt; | ||||
| #else | ||||
| 	constexpr LogFailType log_failure = fatal; | ||||
| #endif | ||||
|  | ||||
| namespace ECode | ||||
| { | ||||
| #	define Define_Types           \ | ||||
| 	Entry( Untyped )              \ | ||||
| 	Entry( Comment )              \ | ||||
| 	Entry( Access_Private )       \ | ||||
| 	Entry( Access_Protected )     \ | ||||
| 	Entry( Access_Public )        \ | ||||
| 	Entry( PlatformAttributes )   \ | ||||
| 	Entry( Class )                \ | ||||
| 	Entry( Class_Fwd )            \ | ||||
| 	Entry( Class_Body )           \ | ||||
| 	Entry( Enum )                 \ | ||||
| 	Entry( Enum_Fwd )             \ | ||||
| 	Entry( Enum_Body )            \ | ||||
| 	Entry( Enum_Class )           \ | ||||
| 	Entry( Enum_Class_Fwd )       \ | ||||
| 	Entry( Execution )            \ | ||||
| 	Entry( Export_Body )          \ | ||||
| 	Entry( Extern_Linkage )       \ | ||||
| 	Entry( Extern_Linkage_Body )  \ | ||||
| 	Entry( Friend )               \ | ||||
| 	Entry( Function )             \ | ||||
| 	Entry( Function_Fwd )         \ | ||||
| 	Entry( Function_Body )        \ | ||||
| 	Entry( Global_Body )          \ | ||||
| 	Entry( Module )               \ | ||||
| 	Entry( Namespace )            \ | ||||
| 	Entry( Namespace_Body )       \ | ||||
| 	Entry( Operator )             \ | ||||
| 	Entry( Operator_Fwd )         \ | ||||
| 	Entry( Operator_Member )      \ | ||||
| 	Entry( Operator_Member_Fwd )  \ | ||||
| 	Entry( Operator_Cast )		  \ | ||||
| 	Entry( Operator_Cast_Fwd )    \ | ||||
| 	Entry( Parameters )           \ | ||||
| 	Entry( Preprocessor_Include ) \ | ||||
| 	Entry( Specifiers )           \ | ||||
| 	Entry( Struct )               \ | ||||
| 	Entry( Struct_Fwd )           \ | ||||
| 	Entry( Struct_Body )          \ | ||||
| 	Entry( Template )             \ | ||||
| 	Entry( Typedef )              \ | ||||
| 	Entry( Typename )             \ | ||||
| 	Entry( Union )			      \ | ||||
| 	Entry( Union_Body) 		      \ | ||||
| 	Entry( Using )                \ | ||||
| 	Entry( Using_Namespace )      \ | ||||
| 	Entry( Variable ) | ||||
|  | ||||
| 	enum Type : u32 | ||||
| 	{ | ||||
| 	#	define Entry( Type ) Type, | ||||
| 		Define_Types | ||||
| 	#	undef Entry | ||||
|  | ||||
| 		Num_Types, | ||||
| 		Invalid | ||||
| 	}; | ||||
|  | ||||
| 	inline | ||||
| 	StrC to_str( Type type ) | ||||
| 	{ | ||||
| 		static | ||||
| 		StrC lookup[Num_Types] = { | ||||
| 		#	define Entry( Type ) { sizeof(stringize(Type)), stringize(Type) }, | ||||
| 			Define_Types | ||||
| 		#	undef Entry | ||||
| 		}; | ||||
|  | ||||
| 		return lookup[ type ]; | ||||
| 	} | ||||
|  | ||||
| #	undef Define_Types | ||||
| } | ||||
| using CodeT = ECode::Type; | ||||
|  | ||||
| // Used to indicate if enum definitoin is an enum class or regular enum. | ||||
| enum class EnumT : u8 | ||||
| { | ||||
| 	Regular, | ||||
| 	Class | ||||
| }; | ||||
|  | ||||
| constexpr EnumT EnumClass   = EnumT::Class; | ||||
| constexpr EnumT EnumRegular = EnumT::Regular; | ||||
|  | ||||
| namespace EOperator | ||||
| { | ||||
| #	define Define_Operators       \ | ||||
| 	Entry( Assign,          =  )  \ | ||||
| 	Entry( Assign_Add,      += )  \ | ||||
| 	Entry( Assign_Subtract, -= )  \ | ||||
| 	Entry( Assign_Multiply, *= )  \ | ||||
| 	Entry( Assign_Divide,   /= )  \ | ||||
| 	Entry( Assign_Modulo,   %= )  \ | ||||
| 	Entry( Assign_BAnd,     &= )  \ | ||||
| 	Entry( Assign_BOr,      |= )  \ | ||||
| 	Entry( Assign_BXOr,     ^= )  \ | ||||
| 	Entry( Assign_LShift,   <<= ) \ | ||||
| 	Entry( Assign_RShift,   >>= ) \ | ||||
| 	Entry( Increment,       ++ )  \ | ||||
| 	Entry( Decrement,       -- )  \ | ||||
| 	Entry( Unary_Plus,      + )   \ | ||||
| 	Entry( Unary_Minus,     - )   \ | ||||
| 	Entry( UnaryNot,        ! )   \ | ||||
| 	Entry( Add,             + )   \ | ||||
| 	Entry( Subtract,        - )   \ | ||||
| 	Entry( Multiply,        * )   \ | ||||
| 	Entry( Divide,          / )   \ | ||||
| 	Entry( Modulo,          % )   \ | ||||
| 	Entry( BNot,            ~ )   \ | ||||
| 	Entry( BAnd,            & )   \ | ||||
| 	Entry( BOr,             | )   \ | ||||
| 	Entry( BXOr,            ^ )   \ | ||||
| 	Entry( LShift,          << )  \ | ||||
| 	Entry( RShift,          >> )  \ | ||||
| 	Entry( LAnd,            && )  \ | ||||
| 	Entry( LOr,             || )  \ | ||||
| 	Entry( LEqual,          == )  \ | ||||
| 	Entry( LNot,            != )  \ | ||||
| 	Entry( Lesser,          < )   \ | ||||
| 	Entry( Greater,         > )   \ | ||||
| 	Entry( LesserEqual,     <= )  \ | ||||
| 	Entry( GreaterEqual,    >= )  \ | ||||
| 	Entry( Subscript,       [] )  \ | ||||
| 	Entry( Indirection,     * )   \ | ||||
| 	Entry( AddressOf,       & )   \ | ||||
| 	Entry( MemberOfPointer, -> )  \ | ||||
| 	Entry( PtrToMemOfPtr,   ->* ) \ | ||||
| 	Entry( FunctionCall,    () ) | ||||
|  | ||||
| 	enum Type : u32 | ||||
| 	{ | ||||
| 	#	define Entry( Type_, Token_ ) Type_, | ||||
| 		Define_Operators | ||||
| 	#	undef Entry | ||||
| 		Comma, | ||||
|  | ||||
| 		Num_Ops, | ||||
| 		Invalid | ||||
| 	}; | ||||
|  | ||||
| 	inline | ||||
| 	char const* to_str( Type op ) | ||||
| 	{ | ||||
| 		local_persist | ||||
| 		char const* lookup[ Num_Ops ] = { | ||||
| 		#	define Entry( Type_, Token_ ) stringize(Token_), | ||||
| 			Define_Operators | ||||
| 		#	undef Entry | ||||
| 			"," | ||||
| 		}; | ||||
|  | ||||
| 		return lookup[ op ]; | ||||
| 	} | ||||
|  | ||||
| #	undef Define_Operators | ||||
| } | ||||
| using OperatorT = EOperator::Type; | ||||
|  | ||||
| namespace ESpecifier | ||||
| { | ||||
| /* | ||||
| 	Note: The following are handled separately: | ||||
| 	attributes | ||||
| 	alignas | ||||
| */ | ||||
|  | ||||
| #	define Define_Specifiers                     \ | ||||
| 	Entry( Invalid,          INVALID )           \ | ||||
| 	Entry( Consteval,        consteval )         \ | ||||
| 	Entry( Constexpr,        constexpr )         \ | ||||
| 	Entry( Constinit,        constinit )         \ | ||||
| 	Entry( Explicit,         explicit )          \ | ||||
| 	Entry( External_Linkage, extern )            \ | ||||
| 	Entry( Global,           global )            \ | ||||
| 	Entry( Inline,           inline )            \ | ||||
| 	Entry( Internal_Linkage, internal )          \ | ||||
| 	Entry( Local_Persist,    local_persist )     \ | ||||
| 	Entry( Mutable,          mutable )           \ | ||||
| 	Entry( Ptr,              * )                 \ | ||||
| 	Entry( Ref,              & )                 \ | ||||
| 	Entry( Register,         register )          \ | ||||
| 	Entry( RValue,           && )                \ | ||||
| 	Entry( Static,           static  )           \ | ||||
| 	Entry( Thread_Local,     thread_local )      \ | ||||
| 	Entry( Volatile,         volatile )          \ | ||||
| 	Entry( Virtual,          virtual )           \ | ||||
| 	Entry( Const,            const )             \ | ||||
| 	Entry( Final,            final )             \ | ||||
| 	Entry( Override,         override ) | ||||
|  | ||||
| 	enum Type : u32 | ||||
| 	{ | ||||
| 	#	define Entry( Specifier, Code ) Specifier, | ||||
| 		Define_Specifiers | ||||
| 	#	undef Entry | ||||
|  | ||||
| 		Num_Specifiers, | ||||
| 	}; | ||||
|  | ||||
| 	inline | ||||
| 	bool is_trailing( Type specifier ) | ||||
| 	{ | ||||
| 		return specifier > Virtual; | ||||
| 	} | ||||
|  | ||||
| 	// Specifier to string | ||||
| 	inline | ||||
| 	StrC to_str( Type specifier ) | ||||
| 	{ | ||||
| 		local_persist | ||||
| 		StrC lookup[ Num_Specifiers ] = { | ||||
| 		#	pragma push_macro( "global" ) | ||||
| 		#	pragma push_macro( "internal" ) | ||||
| 		#	pragma push_macro( "local_persist" ) | ||||
| 		#	undef global | ||||
| 		#	undef internal | ||||
| 		#	undef local_persist | ||||
|  | ||||
| 		#	define Entry( Spec_, Code_ ) { sizeof(stringize(Code_)), stringize(Code_) }, | ||||
| 			Define_Specifiers | ||||
| 		#	undef Entry | ||||
|  | ||||
| 		#	pragma pop_macro( "global" ) | ||||
| 		#	pragma pop_macro( "internal" ) | ||||
| 		#	pragma pop_macro( "local_persist" ) | ||||
| 		}; | ||||
|  | ||||
| 		return lookup[ specifier ]; | ||||
| 	} | ||||
|  | ||||
| 	inline | ||||
| 	Type to_type( StrC str ) | ||||
| 	{ | ||||
| 		local_persist | ||||
| 		u32 keymap[ Num_Specifiers ]; | ||||
| 		do_once_start | ||||
| 			for ( u32 index = 0; index < Num_Specifiers; index++ ) | ||||
| 			{ | ||||
| 				StrC enum_str = to_str( (Type)index ); | ||||
|  | ||||
| 				// We subtract 1 to remove the null terminator | ||||
| 				// This is because the tokens lexed are not null terminated. | ||||
| 				keymap[index] = crc32( enum_str.Ptr, enum_str.Len - 1); | ||||
| 			} | ||||
| 		do_once_end | ||||
|  | ||||
| 		u32 hash = crc32( str.Ptr, str.Len ); | ||||
|  | ||||
| 		for ( u32 index = 0; index < Num_Specifiers; index++ ) | ||||
| 		{ | ||||
| 			if ( keymap[index] == hash ) | ||||
| 				return (Type)index; | ||||
| 		} | ||||
|  | ||||
| 		return Invalid; | ||||
| 	} | ||||
|  | ||||
| #	undef Define_Specifiers | ||||
| } | ||||
| using SpecifierT = ESpecifier::Type; | ||||
|  | ||||
| enum class AccessSpec : u32 | ||||
| { | ||||
| 	Default, | ||||
| 	Public, | ||||
| 	Protected, | ||||
| 	Private, | ||||
|  | ||||
| 	Num_AccessSpec, | ||||
| 	Invalid, | ||||
| }; | ||||
|  | ||||
| inline | ||||
| char const* to_str( AccessSpec type ) | ||||
| { | ||||
| 	local_persist | ||||
| 	char const* lookup[ (u32)AccessSpec::Num_AccessSpec ] = { | ||||
| 		"", | ||||
| 		"public", | ||||
| 		"protected", | ||||
| 		"private", | ||||
| 	}; | ||||
|  | ||||
| 	if ( type > AccessSpec::Public ) | ||||
| 		return "Invalid"; | ||||
|  | ||||
| 	return lookup[ (u32)type ]; | ||||
| } | ||||
|  | ||||
| enum class ModuleFlag : u32 | ||||
| { | ||||
| 	None    = 0, | ||||
| 	Export  = bit(0), | ||||
| 	Import  = bit(1), | ||||
| 	// Private = bit(2), | ||||
|  | ||||
| 	Num_ModuleFlags, | ||||
| 	Invalid, | ||||
| }; | ||||
|  | ||||
| ModuleFlag operator|( ModuleFlag A, ModuleFlag B) | ||||
| { | ||||
| 	return (ModuleFlag)( (u32)A | (u32)B ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| 	Predefined attributes | ||||
| 	Used for the parser constructors to identify non-standard attributes | ||||
|  | ||||
| 	Override these to change the attribute to your own unique identifier convention. | ||||
|  | ||||
| 	The tokenizer identifies attribute defines with the GEN_Define_Attribute_Tokens macros. | ||||
| 	See the example below and the Define_TokType macro used in gen.cpp to know the format. | ||||
| 	While the library can parse raw attributes, most projects use defines to wrap them for compiler | ||||
| 	platform indendence. The token define allows support for them without having to modify the library. | ||||
| */ | ||||
| #if defined(GEN_SYSTEM_WINDOWS) || defined( __CYGWIN__ ) | ||||
| #ifndef GEN_Attribute_Keyword | ||||
| #	define GEN_API_Export_Code   __declspec(dllexport) | ||||
| #	define GEN_API_Import_Code   __declspec(dllimport) | ||||
| #	define GEN_Attribute_Keyword __declspec | ||||
| #endif | ||||
|  | ||||
| constexpr char const* Attribute_Keyword = stringize( GEN_Attribute_Keyword); | ||||
|  | ||||
| #elif GEN_HAS_ATTRIBUTE( visibility ) || GEN_GCC_VERSION_CHECK( 3, 3, 0 ) | ||||
| #ifndef GEN_Attribute_Keyword | ||||
| #	define GEN_API_Export_Code   __attribute__ ((visibility ("default"))) | ||||
| #	define GEN_API_Import_Code   __attribute__ ((visibility ("default"))) | ||||
| #	define GEN_Attribute_Keyword __attribute__ | ||||
| #endif | ||||
|  | ||||
| constexpr char const* Attribute_Keyword = stringize( GEN_Attribute_Keyword ); | ||||
|  | ||||
| #else | ||||
| #ifndef GEN_Attribute_Keyword | ||||
| #	define GEN_API_Export_Code | ||||
| #	define GEN_API_Import_Code | ||||
| #	define GEN_Attribute_Keyword | ||||
| #endif | ||||
|  | ||||
| constexpr char const* Attribute_Keyword = ""; | ||||
| #endif | ||||
|  | ||||
| #ifndef GEN_Define_Attribute_Tokens | ||||
| #	define GEN_Define_Attribute_Tokens         \ | ||||
| 	Entry( API_Export, "GEN_API_Export_Code" ) \ | ||||
| 	Entry( API_Import, "GEN_API_Import_Code" ) | ||||
| #endif | ||||
|  | ||||
|   | ||||
							
								
								
									
										148
									
								
								project/components/gen.untyped.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								project/components/gen.untyped.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,148 @@ | ||||
| sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va ) | ||||
| { | ||||
| 	char const* buf_begin = buf; | ||||
| 	sw          remaining = buf_size; | ||||
|  | ||||
| 	local_persist | ||||
| 		Arena tok_map_arena; | ||||
|  | ||||
| 	HashTable<StrC> tok_map; | ||||
| 	{ | ||||
| 		local_persist | ||||
| 			char tok_map_mem[ TokenFmt_TokenMap_MemSize ]; | ||||
|  | ||||
| 		tok_map_arena = Arena::init_from_memory( tok_map_mem, sizeof(tok_map_mem) ); | ||||
|  | ||||
| 		tok_map = HashTable<StrC>::init( tok_map_arena ); | ||||
|  | ||||
| 		s32 left = num_tokens - 1; | ||||
|  | ||||
| 		while ( left-- ) | ||||
| 		{ | ||||
| 			char const* token = va_arg( va, char const* ); | ||||
| 			StrC        value = va_arg( va, StrC ); | ||||
|  | ||||
| 			u32 key = crc32( token, str_len(token) ); | ||||
|  | ||||
| 			tok_map.set( key, value ); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	char const* fmt     = va_arg( va, char const* ); | ||||
| 	char        current = *fmt; | ||||
|  | ||||
| 	while ( current ) | ||||
| 	{ | ||||
| 		sw len = 0; | ||||
|  | ||||
| 		while ( current && current != '<' && remaining ) | ||||
| 		{ | ||||
| 			* buf = * fmt; | ||||
| 			buf++; | ||||
| 			fmt++; | ||||
| 			remaining--; | ||||
|  | ||||
| 			current = * fmt; | ||||
| 		} | ||||
|  | ||||
| 		if ( current == '<' ) | ||||
| 		{ | ||||
| 			char const* scanner = fmt + 1; | ||||
|  | ||||
| 			s32 tok_len = 0; | ||||
|  | ||||
| 			while ( *scanner != '>' ) | ||||
| 			{ | ||||
| 				tok_len++; | ||||
| 				scanner++; | ||||
| 			} | ||||
|  | ||||
| 			char const* token = fmt + 1; | ||||
|  | ||||
| 			u32       key   = crc32( token, tok_len ); | ||||
| 			StrC*     value = tok_map.get( key ); | ||||
|  | ||||
| 			if ( value ) | ||||
| 			{ | ||||
| 				sw          left = value->Len; | ||||
| 				char const* str  = value->Ptr; | ||||
|  | ||||
| 				while ( left-- ) | ||||
| 				{ | ||||
| 					* buf = * str; | ||||
| 					buf++; | ||||
| 					str++; | ||||
| 					remaining--; | ||||
| 				} | ||||
|  | ||||
| 				scanner++; | ||||
| 				fmt     = scanner; | ||||
| 				current = * fmt; | ||||
| 				continue; | ||||
| 			} | ||||
|  | ||||
| 			* buf = * fmt; | ||||
| 			buf++; | ||||
| 			fmt++; | ||||
| 			remaining--; | ||||
|  | ||||
| 			current = * fmt; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	tok_map.clear(); | ||||
| 	tok_map_arena.free(); | ||||
|  | ||||
| 	sw result = buf_size - remaining; | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| Code untyped_str( StrC content ) | ||||
| { | ||||
| 	Code | ||||
| 		result          = make_code(); | ||||
| 	result->Name    = get_cached_string( content ); | ||||
| 	result->Type    = ECode::Untyped; | ||||
| 	result->Content = result->Name; | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| Code untyped_fmt( char const* fmt, ...) | ||||
| { | ||||
| 	local_persist thread_local | ||||
| 		char buf[GEN_PRINTF_MAXLEN] = { 0 }; | ||||
|  | ||||
| 	va_list va; | ||||
| 	va_start(va, fmt); | ||||
| 	sw length = str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va); | ||||
| 	va_end(va); | ||||
|  | ||||
| 	Code | ||||
| 		result          = make_code(); | ||||
| 	result->Name    = get_cached_string( { str_len(fmt, MaxNameLength), fmt } ); | ||||
| 	result->Type    = ECode::Untyped; | ||||
| 	result->Content = get_cached_string( { length, buf } ); | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| Code untyped_token_fmt( s32 num_tokens, ... ) | ||||
| { | ||||
| 	local_persist thread_local | ||||
| 		char buf[GEN_PRINTF_MAXLEN] = { 0 }; | ||||
|  | ||||
| 	va_list va; | ||||
| 	va_start(va, num_tokens); | ||||
| 	sw length = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num_tokens, va); | ||||
| 	va_end(va); | ||||
|  | ||||
| 	Code | ||||
| 		result          = make_code(); | ||||
| 	result->Name    = get_cached_string( { length, buf } ); | ||||
| 	result->Type    = ECode::Untyped; | ||||
| 	result->Content = result->Name; | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
							
								
								
									
										43
									
								
								project/filesystem/gen.builder.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								project/filesystem/gen.builder.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| void Builder::print( Code code ) | ||||
| { | ||||
| 	Buffer.append_fmt( "%s\n", code->to_string() ); | ||||
| } | ||||
|  | ||||
| void Builder::print_fmt( char const* fmt, ... ) | ||||
| { | ||||
| 	sw   res; | ||||
| 	char buf[ GEN_PRINTF_MAXLEN ] = { 0 }; | ||||
|  | ||||
| 	va_list va; | ||||
| 	va_start( va, fmt ); | ||||
| 	res = str_fmt_va( buf, count_of( buf ) - 1, fmt, va ) - 1; | ||||
| 	va_end( va ); | ||||
|  | ||||
| 	Buffer.append( buf, res ); | ||||
| } | ||||
|  | ||||
| bool Builder::open( char const* path ) | ||||
| { | ||||
| 	FileError error = file_open_mode( & File, EFileMode_WRITE, path ); | ||||
|  | ||||
| 	if ( error != EFileError_NONE ) | ||||
| 	{ | ||||
| 		log_failure( "gen::File::open - Could not open file: %s", path); | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	Buffer = String::make_reserve( GlobalAllocator, Builder_StrBufferReserve ); | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void Builder::write() | ||||
| { | ||||
| 	bool result = file_write( & File, Buffer, Buffer.length() ); | ||||
|  | ||||
| 	if ( result == false ) | ||||
| 		log_failure("gen::File::write - Failed to write to file: %s", file_name( & File ) ); | ||||
|  | ||||
| 	file_close( & File ); | ||||
| 	Buffer.free(); | ||||
| } | ||||
| @@ -0,0 +1,11 @@ | ||||
| struct Builder | ||||
| { | ||||
| 	FileInfo File; | ||||
| 	String   Buffer; | ||||
|  | ||||
| 	void print( Code ); | ||||
| 	void print_fmt( char const* fmt, ... ); | ||||
|  | ||||
| 	bool open( char const* path ); | ||||
| 	void write(); | ||||
| }; | ||||
|   | ||||
							
								
								
									
										6858
									
								
								project/gen.cpp
									
									
									
									
									
								
							
							
						
						
									
										6858
									
								
								project/gen.cpp
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2078
									
								
								project/gen.hpp
									
									
									
									
									
								
							
							
						
						
									
										2078
									
								
								project/gen.hpp
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user