mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-10-31 06:50:53 -07:00 
			
		
		
		
	WIP: Design is almost done, impl this weekend.
This commit is contained in:
		
							
								
								
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @@ -7,6 +7,7 @@ | ||||
| 		"utility": "cpp", | ||||
| 		"xtr1common": "cpp", | ||||
| 		"xutility": "cpp", | ||||
| 		"initializer_list": "cpp" | ||||
| 		"initializer_list": "cpp", | ||||
| 		"table.h": "c" | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										44
									
								
								Readme.md
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								Readme.md
									
									
									
									
									
								
							| @@ -2,7 +2,7 @@ | ||||
|  | ||||
| An attempt at simple staged metaprogramming for c/c++. | ||||
|  | ||||
| This library is intended for small-to midsize projects. | ||||
| This library is intended for small-to midsized projects. | ||||
|  | ||||
| ### TOC | ||||
|  | ||||
| @@ -174,20 +174,27 @@ The construction will fail and return InvalidCode otherwise. | ||||
|  | ||||
| Interface : | ||||
|  | ||||
| * def_forward_decl | ||||
| * def_class | ||||
| * def_class_body | ||||
| * def_class_fwd | ||||
| * def_enum | ||||
| * def_enum_class | ||||
| * def_enum_body | ||||
| * def_global_body | ||||
| * def_proc | ||||
| * def_proc_body | ||||
| * def_namespace | ||||
| * def_namespace_body | ||||
| * def_operator | ||||
| * def_operator_fwd | ||||
| * def_param | ||||
| * def_params | ||||
| * def_operator | ||||
| * def_proc | ||||
| * def_proc_body | ||||
| * def_proc_fwd | ||||
| * def_specifier | ||||
| * def_specifiers | ||||
| * def_struct | ||||
| * def_struct_body | ||||
| * def_struct_fwd | ||||
| * def_variable | ||||
| * def_type | ||||
| * def_using | ||||
| @@ -206,19 +213,20 @@ Code ASTs may be explictly validated at anytime using Code's check() member func | ||||
|  | ||||
| Interface : | ||||
|  | ||||
| * make_forward_decl | ||||
| * make_class | ||||
| * make_enum | ||||
| * make_enum_class | ||||
| * make_fwd | ||||
| * make_global_body | ||||
| * make_proc | ||||
| * make_namespace | ||||
| * make_params | ||||
| * make_operator | ||||
| * make_params | ||||
| * make_proc | ||||
| * make_specifiers | ||||
| * make_struct | ||||
| * make_variable | ||||
| * make_type | ||||
| * make_using | ||||
| * make_using_namespace | ||||
|  | ||||
| ### Parse construction | ||||
|  | ||||
| @@ -226,19 +234,29 @@ A string provided to the API is parsed for the intended language construct. | ||||
|  | ||||
| Interface : | ||||
|  | ||||
| * parse_forward_decl | ||||
| * parse_class | ||||
| * parse_glboal_body | ||||
| * parse_proc | ||||
| * parse_classes | ||||
| * parse_class_fwd | ||||
| * parse_classes_fwd | ||||
| * parse_enum | ||||
| * parse_enums | ||||
| * parse_global_body | ||||
| * parse_namespace | ||||
| * parse_namespaces | ||||
| * parse_params | ||||
| * parse_proc | ||||
| * parse_procs | ||||
| * parse_operator | ||||
| * parse_operators | ||||
| * parse_specifiers | ||||
| * parse_struct | ||||
| * parse_strucs | ||||
| * parse_variable | ||||
| * parse_variables | ||||
| * parse_type | ||||
| * parse_types | ||||
| * parse_using | ||||
| * parse_using | ||||
| * parse_usings | ||||
|  | ||||
| The parse API treats any execution scope definitions with no validation and are turned into untyped Code ASTs. | ||||
| This includes the assignmetn of variables; due to the library not yet supporting c/c++ expression parsing. | ||||
|   | ||||
| @@ -124,5 +124,7 @@ sw token_fmt_va( char* buf, uw buf_size, char const* fmt, s32 num_tokens, va_lis | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	tokmap_clear( & tok_map ); | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|   | ||||
| @@ -73,17 +73,17 @@ | ||||
| #endif | ||||
|  | ||||
| #define bit( Value_ )                      ( 1 << Value_ ) | ||||
| #define bitfield_is_equal( Field_, Mask_ ) ( ( Mask_ & Field_ ) == Mask_ ) | ||||
| #define bitfield_is_equal( Field_, Mask_ ) ( ( (Mask_) & (Field_) ) == (Mask_) ) | ||||
| #define ct                                 constexpr | ||||
| #define forceinline                        ZPL_ALWAYS_INLINE | ||||
| #define print_nl( _)                       zpl_printf("\n") | ||||
| #define ccast( Type_, Value_ )             * const_cast< Type_* >( & Value_ ) | ||||
| #define ccast( Type_, Value_ )             * const_cast< Type_* >( & (Value_) ) | ||||
| #define scast( Type_, Value_ )			   static_cast< Type_ >( Value_ ) | ||||
| #define rcast( Type_, Value_ )			   reinterpret_cast< Type_ >( Value_ ) | ||||
| #define pcast( Type_, Value_ )             ( * (Type_*)( & Value_ ) ) | ||||
| #define pcast( Type_, Value_ )             ( * (Type_*)( & (Value_) ) ) | ||||
| #define txt_impl( Value_ )                 #Value_ | ||||
| #define txt( Value_ )                      txt_impl( Value_ ) | ||||
| #define txt_with_length( Value_ )		   txt_impl( Value_ ), sizeof( txt_impl( Value_) ) | ||||
| #define txt_with_length( Value_ )		   txt_impl( Value_ ), sizeof( txt_impl( Value_ ) ) | ||||
|  | ||||
| #define do_once()      \ | ||||
| do                     \ | ||||
| @@ -131,6 +131,8 @@ namespace Memory | ||||
| 	void cleanup(); | ||||
| } | ||||
|  | ||||
| sw token_fmt_va( char* buf, uw buf_size, char const* fmt, s32 num_tokens, va_list va ); | ||||
|  | ||||
| inline | ||||
| char const* token_fmt( char const* fmt, sw num_tokens, ... ) | ||||
| { | ||||
| @@ -185,3 +187,4 @@ sw fatal(char const *fmt, ...) | ||||
| 	return -1; | ||||
| #endif | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										411
									
								
								project/gen.cpp
									
									
									
									
									
								
							
							
						
						
									
										411
									
								
								project/gen.cpp
									
									
									
									
									
								
							| @@ -4,40 +4,57 @@ | ||||
| #ifdef gen_time | ||||
| namespace gen | ||||
| { | ||||
| 	ZPL_TABLE_DEFINE( StringTable, str_tbl_,   string ); | ||||
| 	ZPL_TABLE_DEFINE( TypeTable,   type_tbl_ , Code   ); | ||||
|  | ||||
| 	namespace StaticData | ||||
| 	{ | ||||
| 		static array(CodePOD) CodePool = nullptr; | ||||
|  | ||||
| 		static array(arena) StringArenas =  nullptr; | ||||
|  | ||||
| 		static StringTable    StringMap; | ||||
| 		static TypeTable      TypeMap; | ||||
|  | ||||
| 		static sw InitSize_CodePool       = megabytes(64); | ||||
| 		static sw InitSize_StringArena    = megabytes(32); | ||||
| 		static sw InitSize_StringTable    = megabytes(4); | ||||
| 		static sw InitSize_TypeTable      = megabytes(4); | ||||
|  | ||||
| 		static allocator Allocator_CodePool    = zpl_heap(); | ||||
| 		static allocator Allocator_StringArena = zpl_heap(); | ||||
| 		static allocator Allocator_StringTable = zpl_heap(); | ||||
| 		static allocator Allocator_TypeTable   = zpl_heap(); | ||||
| 	} | ||||
|  | ||||
| #pragma region CONSTANTS | ||||
| #	ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| 	const Code t_void; | ||||
| 	Code t_void; | ||||
|  | ||||
| 	const Code t_bool; | ||||
| 	const Code t_char; | ||||
| 	const Code t_char_wide; | ||||
| 	Code t_bool; | ||||
| 	Code t_char; | ||||
| 	Code t_char_wide; | ||||
|  | ||||
| 	const Code t_s8; | ||||
| 	const Code t_s16; | ||||
| 	const Code t_s32; | ||||
| 	const Code t_s64; | ||||
| 	Code t_s8; | ||||
| 	Code t_s16; | ||||
| 	Code t_s32; | ||||
| 	Code t_s64; | ||||
|  | ||||
| 	const Code t_u8; | ||||
| 	const Code t_u16; | ||||
| 	const Code t_u32; | ||||
| 	const Code t_u64; | ||||
| 	Code t_u8; | ||||
| 	Code t_u16; | ||||
| 	Code t_u32; | ||||
| 	Code t_u64; | ||||
|  | ||||
| 	const Code t_sw; | ||||
| 	const Code t_uw; | ||||
| 	Code t_sw; | ||||
| 	Code t_uw; | ||||
|  | ||||
| 	const Code t_f32; | ||||
| 	const Code t_f64; | ||||
|  | ||||
| 	const Code spec_constexpr; | ||||
| 	const Code spec_inline; | ||||
| 	Code t_f32; | ||||
| 	Code t_f64; | ||||
| #	endif | ||||
| #pragma endregion CONSTANTS | ||||
|  | ||||
| 	Code spec_constexpr; | ||||
| 	Code spec_inline; | ||||
| #pragma endregion CONSTANTS | ||||
|  | ||||
| 	/* | ||||
| 		Used internally to retireve a Code object form the CodePool. | ||||
| @@ -66,10 +83,9 @@ namespace gen | ||||
| 		t_bool_write = ccast( Code, t_void ); | ||||
| 		t_bool_write = def_type( txt(void) ); | ||||
|  | ||||
| 	#	define def_constant_code_type( Type_ )        \ | ||||
| 		Code&                                         \ | ||||
| 		t_##Type_##_write = ccast( Code, t_##Type_ ); \ | ||||
| 		t_##Type_##_write = def_type( txt(Type_) )    \ | ||||
| 	#	define def_constant_code_type( Type_ ) \ | ||||
| 		Code&                                  \ | ||||
| 		t_##Type_ = def_type( txt(Type_) )      | ||||
|  | ||||
| 		def_constant_code_type( bool ); | ||||
| 		def_constant_code_type( char ); | ||||
| @@ -109,80 +125,92 @@ namespace gen | ||||
| 	#endif | ||||
| 	} | ||||
|  | ||||
| 	Code decl_type( Code type, char const* name, Code specifiers ) | ||||
| 	void clear_code_pool() | ||||
| 	{ | ||||
| 		using namespace ECode; | ||||
| 		array_clear( StaticData::CodePool ); | ||||
|  | ||||
| 		if ( type->Type != Specifiers ) | ||||
| 		{ | ||||
| 			log_failure( "gen::decl_type: type is not a Typename"); | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
| 		sw size = array_capacity( StaticData::CodePool ); | ||||
|  | ||||
| 		if ( type->Type != Typename ) | ||||
| 		{ | ||||
| 			log_failure( "gen::decl_type: specifiers is not a 'Specfiers' type"); | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		Code  | ||||
| 		result       = make_code(); | ||||
| 		result->Type = Decl_Type; | ||||
| 		result->Name = string_make( g_allocator, name ); | ||||
|  | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
| 		result->add( specifiers ); | ||||
| 		result->add( type ); | ||||
| 		result.lock(); | ||||
|  | ||||
| 		return result; | ||||
| 		zpl_memset( StaticData::CodePool, 0, size ); | ||||
| 	} | ||||
|  | ||||
| 	Code decl_proc( char const* name | ||||
| 		, Code specifiers | ||||
| 		, Code params | ||||
| 		, Code ret_type | ||||
| 	) | ||||
| 	allocator get_string_allocator( s32 str_length ) | ||||
| 	{ | ||||
| 		using namespace ECode; | ||||
| 		using namespace StaticData; | ||||
|  | ||||
| 		if ( specifiers->Type != Specifiers ) | ||||
| 		if ( StringArenas->total_allocated + str_length > StringArenas->total_size ) | ||||
| 		{ | ||||
| 			log_failure( "gen::decl_fn: specifiers was not a `Specifiers` type" ); | ||||
| 			return InvalidCode; | ||||
| 			arena new_arena; | ||||
| 			arena_init_from_allocator( & new_arena, Allocator_StringArena, InitSize_StringArena ); | ||||
|  | ||||
| 			array_append( StringArenas, new_arena ); | ||||
|  | ||||
| 			return arena_allocator( StringArenas ); | ||||
| 		} | ||||
|  | ||||
| 		if ( params->Type != Parameters ) | ||||
| 		{ | ||||
| 			log_failure( "gen::decl_fn: params was not a `Parameters` type" ); | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		if ( ret_type->Type != Typename ) | ||||
| 		{ | ||||
| 			log_failure( "gen::decl_fn: ret_type was not a Typename" ); | ||||
| 			return InvalidCode; | ||||
| 		} | ||||
|  | ||||
| 		Code | ||||
| 		result       = make_code(); | ||||
| 		result->Type = Decl_Function; | ||||
| 		result->Name = string_make( g_allocator, name ); | ||||
| 		 | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
|  | ||||
| 		if ( specifiers ) | ||||
| 			result->add( specifiers ); | ||||
|  | ||||
| 		result->add( ret_type ); | ||||
|  | ||||
| 		if ( params ) | ||||
| 			result->add( params ); | ||||
|  | ||||
| 		result.lock(); | ||||
| 		return result; | ||||
| 		return arena_allocator( StringArenas ); | ||||
| 	} | ||||
|  | ||||
| 	// Will either make or retrive a code string. | ||||
| 	string code_string( char const* cstr, s32 length ) | ||||
| 	{ | ||||
| 		s32 hash_length = length > kilobytes(1) ? kilobytes(1) : length; | ||||
|  | ||||
| 		u32 key = crc32( cstr, hash_length ); | ||||
|  | ||||
| 		string* result = str_tbl_get( & StaticData::StringMap, key ); | ||||
|  | ||||
| 		if ( result ) | ||||
| 		{ | ||||
| 			return * result; | ||||
| 		} | ||||
|  | ||||
| 		str_tbl_set( & StaticData::StringMap, key, * result ); | ||||
|  | ||||
| 		return * result; | ||||
| 	} | ||||
|  | ||||
| 	void set_init_reserve_code_pool( sw size ) | ||||
| 	{ | ||||
| 		StaticData::InitSize_CodePool = size; | ||||
| 	} | ||||
|  | ||||
| 	void set_init_reserve_string_arena( sw size ) | ||||
| 	{ | ||||
| 		StaticData::InitSize_StringArena = size; | ||||
| 	} | ||||
|  | ||||
| 	void set_init_reserve_string_table( sw size ) | ||||
| 	{ | ||||
| 		StaticData::InitSize_StringTable = size; | ||||
| 	} | ||||
|  | ||||
| 	void set_init_reserve_type_table( sw size ) | ||||
| 	{ | ||||
| 		StaticData::InitSize_TypeTable = size; | ||||
| 	} | ||||
|  | ||||
| 	void set_allocator_code_pool( allocator pool_allocator ) | ||||
| 	{ | ||||
| 		StaticData::Allocator_CodePool = pool_allocator; | ||||
| 	} | ||||
|  | ||||
| 	void set_allocator_string_arena( allocator string_allocator ) | ||||
| 	{ | ||||
| 		StaticData::Allocator_StringArena = string_allocator; | ||||
| 	} | ||||
|  | ||||
| 	void set_allocator_string_table( allocator string_allocator ) | ||||
| 	{ | ||||
| 		StaticData::Allocator_StringArena = string_allocator; | ||||
| 	} | ||||
|  | ||||
| 	void set_allocator_type_table( allocator type_reg_allocator ) | ||||
| 	{ | ||||
| 		StaticData::Allocator_TypeTable = type_reg_allocator; | ||||
| 	} | ||||
|  | ||||
| #	pragma region Upfront Constructors | ||||
| 	Code def_params( s32 num, ... ) | ||||
| 	{ | ||||
| 		using namespace ECode; | ||||
| @@ -271,7 +299,7 @@ namespace gen | ||||
|  | ||||
| 		switch ( body->Type ) | ||||
| 		{ | ||||
| 			case Function_Body: | ||||
| 			case Proc_Body: | ||||
| 			case Untyped: | ||||
| 				break; | ||||
|  | ||||
| @@ -285,7 +313,7 @@ namespace gen | ||||
| 		Code  | ||||
| 		result       = make_code(); | ||||
| 		result->Name = string_make( g_allocator, name ); | ||||
| 		result->Type = Function; | ||||
| 		result->Type = Proc; | ||||
| 		 | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
|  | ||||
| @@ -331,8 +359,7 @@ namespace gen | ||||
|  | ||||
| 			switch ( entry->Type ) | ||||
| 			{ | ||||
| 				case Decl_Function: | ||||
| 				case Decl_Type: | ||||
| 				case Proc_Forward: | ||||
| 				case Namespace: | ||||
| 				case Namespace_Body: | ||||
| 				case Parameters: | ||||
| @@ -387,8 +414,7 @@ namespace gen | ||||
|  | ||||
| 			switch ( entry->Type ) | ||||
| 			{ | ||||
| 				case Decl_Function: | ||||
| 				case Decl_Type: | ||||
| 				case Proc_Forward: | ||||
| 				case Namespace: | ||||
| 				case Namespace_Body: | ||||
| 				case Parameters: | ||||
| @@ -630,7 +656,7 @@ namespace gen | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code def_type( char const* name ) | ||||
| 	Code def_type( char const* name,  Code specifiers ) | ||||
| 	{ | ||||
| 		Code  | ||||
| 		result       = make_code(); | ||||
| @@ -654,57 +680,9 @@ namespace gen | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
| #	pragma endregion Upfront Constructors | ||||
|  | ||||
| 	Code untyped_str(char const* fmt) | ||||
| 	{ | ||||
| 		Code  | ||||
| 		result       = make_code(); | ||||
| 		result->Name = string_make( g_allocator, fmt ); | ||||
| 		result->Type = ECode::Untyped; | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code untyped_fmt(char const* fmt, ...) | ||||
| 	{ | ||||
| 		local_persist thread_local  | ||||
| 		char buf[ZPL_PRINTF_MAXLEN] = { 0 }; | ||||
|  | ||||
| 		va_list va; | ||||
| 		va_start(va, fmt); | ||||
| 		zpl_snprintf_va(buf, ZPL_PRINTF_MAXLEN, fmt, va); | ||||
| 		va_end(va); | ||||
|           | ||||
| 		Code  | ||||
| 		result          = make_code(); | ||||
| 		result->Name    = string_make( g_allocator, fmt ); | ||||
| 		result->Type    = ECode::Untyped; | ||||
| 		result->Content = string_make( g_allocator, buf ); | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code untyped_token_fmt( char const* fmt, s32 num_tokens, ... ) | ||||
| 	{ | ||||
| 		local_persist thread_local  | ||||
| 		char buf[ZPL_PRINTF_MAXLEN] = { 0 }; | ||||
|  | ||||
| 		va_list va; | ||||
| 		va_start(va, fmt); | ||||
| 		token_fmt_va(buf, ZPL_PRINTF_MAXLEN, fmt, num_tokens, va); | ||||
| 		va_end(va); | ||||
|  | ||||
| 		Code | ||||
| 		result           = make_code(); | ||||
| 		result->Name     = string_make( g_allocator, fmt ); | ||||
| 		result->Type     = ECode::Untyped; | ||||
| 		result->Content  = string_make( g_allocator, buf ); | ||||
|  | ||||
| 		result.lock(); | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| #	pragma region Incremetnal Constructors | ||||
| 	Code make_proc( char const* name | ||||
| 		, Code specifiers | ||||
| 		, Code params | ||||
| @@ -734,7 +712,7 @@ namespace gen | ||||
| 		Code  | ||||
| 		result       = make_code(); | ||||
| 		result->Name = string_make( g_allocator, name ); | ||||
| 		result->Type = Function; | ||||
| 		result->Type = Proc; | ||||
| 		 | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
|  | ||||
| @@ -788,12 +766,12 @@ namespace gen | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code make_unit( char const* name ) | ||||
| 	Code make_global_body( char const* name = "", s32 num = 0, ... ) | ||||
| 	{ | ||||
| 		Code | ||||
| 		result = make_code(); | ||||
| 		result->Type = ECode::Unit; | ||||
| 		result->Name = string_make( g_allocator, name ); | ||||
| 		result->Type = ECode::Global_Body; | ||||
| 		result->Name = string_make( g_allocator, ""); | ||||
|  | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
|  | ||||
| @@ -802,7 +780,9 @@ namespace gen | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
| #	pragma endregion Incremetnal Constructions | ||||
|  | ||||
| #	pragma region Parsing Constructors | ||||
| 	Code parse_proc( char const* def, s32 length ) | ||||
| 	{ | ||||
| 		if ( def == nullptr ) | ||||
| @@ -856,7 +836,7 @@ namespace gen | ||||
| 			while ( left && char_is_space( * scanner ) ) \ | ||||
| 			{                                            \ | ||||
| 				left--;                                  \ | ||||
| 				scanner++ ; | ||||
| 				scanner++ ;                              \ | ||||
| 			} | ||||
|  | ||||
| 			#define Get | ||||
| @@ -947,7 +927,7 @@ namespace gen | ||||
| 		Code  | ||||
| 		result       = make_code(); | ||||
| 		result->Name = string_make( g_allocator, name ); | ||||
| 		result->Type = ECode::Function; | ||||
| 		result->Type = ECode::Proc; | ||||
| 		 | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
|  | ||||
| @@ -985,8 +965,124 @@ namespace gen | ||||
|  | ||||
|  | ||||
| 	} | ||||
| #	pragma endregion Parsing Constructors | ||||
|  | ||||
| #	pragma region Untyped Constructors | ||||
| 	Code untyped_str(char const* fmt) | ||||
| 	{ | ||||
| 		Code  | ||||
| 		result          = make_code(); | ||||
| 		result->Name    = string_make( g_allocator, fmt ); | ||||
| 		result->Type    = ECode::Untyped; | ||||
| 		result->Content = result->Name; | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code untyped_fmt(char const* fmt, ...) | ||||
| 	{ | ||||
| 		local_persist thread_local  | ||||
| 		char buf[ZPL_PRINTF_MAXLEN] = { 0 }; | ||||
|  | ||||
| 		va_list va; | ||||
| 		va_start(va, fmt); | ||||
| 		zpl_snprintf_va(buf, ZPL_PRINTF_MAXLEN, fmt, va); | ||||
| 		va_end(va); | ||||
|           | ||||
| 		Code  | ||||
| 		result          = make_code(); | ||||
| 		result->Name    = string_make( g_allocator, fmt ); | ||||
| 		result->Type    = ECode::Untyped; | ||||
| 		result->Content = string_make( g_allocator, buf ); | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code untyped_token_fmt( char const* fmt, s32 num_tokens, ... ) | ||||
| 	{ | ||||
| 		local_persist thread_local  | ||||
| 		char buf[ZPL_PRINTF_MAXLEN] = { 0 }; | ||||
|  | ||||
| 		va_list va; | ||||
| 		va_start(va, fmt); | ||||
| 		token_fmt_va(buf, ZPL_PRINTF_MAXLEN, fmt, num_tokens, va); | ||||
| 		va_end(va); | ||||
|  | ||||
| 		Code | ||||
| 		result           = make_code(); | ||||
| 		result->Name     = string_make( g_allocator, fmt ); | ||||
| 		result->Type     = ECode::Untyped; | ||||
| 		result->Content  = string_make( g_allocator, buf ); | ||||
|  | ||||
| 		result.lock(); | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
| #	pragma endregion Untyped Constructors | ||||
|  | ||||
| #	pragma region AST | ||||
| 	bool AST::add( AST* other ) | ||||
| 	{ | ||||
| 		switch ( Type ) | ||||
| 		{ | ||||
| 			using namespace ECode; | ||||
|  | ||||
| 			case Untyped: | ||||
| 			break; | ||||
|  | ||||
| 			case Global_Body: | ||||
| 			break; | ||||
|  | ||||
| 			case Proc: | ||||
| 			break; | ||||
|  | ||||
| 			case Proc_Body: | ||||
| 			break; | ||||
|  | ||||
| 			case Proc_Forward: | ||||
| 			break; | ||||
|  | ||||
| 			case Namespace: | ||||
| 			break; | ||||
|  | ||||
| 			case Namespace_Body: | ||||
| 			break; | ||||
|  | ||||
| 			case Parameters: | ||||
| 			break; | ||||
|  | ||||
| 			case Specifiers: | ||||
| 			break; | ||||
|  | ||||
| 			case Struct: | ||||
| 			break; | ||||
|  | ||||
| 			case Struct_Body: | ||||
| 			break; | ||||
|  | ||||
| 			case Variable: | ||||
| 			break; | ||||
|  | ||||
| 			case Typedef: | ||||
| 			break; | ||||
|  | ||||
| 			case Typename: | ||||
| 			break; | ||||
|  | ||||
| 			case Using: | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		array_append( Entries, other ); | ||||
|  | ||||
| 		other->Parent = this; | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	bool AST::check() | ||||
| 	{ | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	string AST::to_string() const | ||||
| 	{ | ||||
| @@ -1007,7 +1103,7 @@ namespace gen | ||||
| 				result = string_append_length( result, Content, string_length(Content) ); | ||||
| 			break; | ||||
|  | ||||
| 			case Decl_Function: | ||||
| 			case Proc_Forward: | ||||
| 			{ | ||||
| 				u32 index = 0; | ||||
| 				u32 left  = array_count( Entries ); | ||||
| @@ -1040,14 +1136,7 @@ namespace gen | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 			case Decl_Type: | ||||
| 				if ( Entries[0]->Type == Specifiers ) | ||||
| 					result = string_append_fmt( result, "%s\n", Entries[0]->to_string()); | ||||
|  | ||||
| 				result = string_append_fmt( result, "%s %s;\n", Entries[1]->to_string(), Name ); | ||||
| 			break; | ||||
|  | ||||
| 			case Function: | ||||
| 			case Proc: | ||||
| 			{ | ||||
| 				u32 index = 0; | ||||
| 				u32 left  = array_count( Entries ); | ||||
| @@ -1080,7 +1169,7 @@ namespace gen | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 			case Function_Body: | ||||
| 			case Proc_Body: | ||||
| 				fatal("NOT SUPPORTED YET"); | ||||
| 			break; | ||||
|  | ||||
| @@ -1138,9 +1227,10 @@ namespace gen | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
| #	pragma endregion AST | ||||
|  | ||||
|  | ||||
|  | ||||
| #	pragma region Builder | ||||
| 	void Builder::print( Code code ) | ||||
| 	{ | ||||
| 		Buffer = string_append_fmt( Buffer, "%s\n\n", code->to_string() ); | ||||
| @@ -1171,5 +1261,6 @@ namespace gen | ||||
| 		// file_seek( & File, 0 ); | ||||
| 		file_close( & File ); | ||||
| 	} | ||||
| #	pragma endregion Builder | ||||
| } | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										574
									
								
								project/gen.hpp
									
									
									
									
									
								
							
							
						
						
									
										574
									
								
								project/gen.hpp
									
									
									
									
									
								
							| @@ -13,17 +13,14 @@ | ||||
| 	* Expression validation             : Execution expressions are defined using the untyped string API.  | ||||
| 	                                      There is no parse API for validating expression (possibly will add in the future) | ||||
| 	* Complete file parser DSL          : This isn't like the unreal header tool.  | ||||
| 	                                      Code injection to file or based off a file contents is not supported by the api.  | ||||
| 										  However nothing is stopping you using the library for that purpose. | ||||
| 	                                      Code injection to file or based off a file contents is not supported by the api. However nothing is stopping you using the library for that purpose. | ||||
| 	* Modern c++ (STL library) features | ||||
|  | ||||
| 	As mentioned in [Usage](#Usage), the user is provided Code objects by calling the interface procedures to generate them or find existing matches. | ||||
|  | ||||
| 	The AST is managed by the library and provided the user via its interface prodedures. | ||||
|  | ||||
| 	Notes: | ||||
|  | ||||
| 	* The allocator definitions used are exposed to the user incase they want to dictate memory usage* | ||||
| 	* The allocator definitions used are exposed to the user incase they want to dictate memory usage | ||||
| 	* ASTs are wrapped for the user in a Code struct which essentially a warpper for a AST* type.   | ||||
| 	* Both AST and Code have member symbols but their data layout is enforced to be POD types. | ||||
|  | ||||
| @@ -58,22 +55,30 @@ | ||||
|  | ||||
| 	Interface : | ||||
|  | ||||
| 	* def_forward_decl | ||||
| 	* def_class | ||||
| 	* def_class_body | ||||
| 	* def_class_fwd | ||||
| 	* def_enum | ||||
| 	* def_enum_class | ||||
| 	* def_enum_body | ||||
| 	* def_global_body | ||||
| 	* def_proc | ||||
| 	* def_proc_body | ||||
| 	* def_namespace | ||||
| 	* def_namespace_body | ||||
| 	* def_operator | ||||
| 	* def_operator_fwd | ||||
| 	* def_param | ||||
| 	* def_params | ||||
| 	* def_operator | ||||
| 	* def_proc | ||||
| 	* def_proc_body | ||||
| 	* def_proc_fwd | ||||
| 	* def_specifier | ||||
| 	* def_specifiers | ||||
| 	* def_struct | ||||
| 	* def_struct_body | ||||
| 	* def_struct_fwd | ||||
| 	* def_variable | ||||
| 	* def_type | ||||
| 	* def_typedef | ||||
| 	* def_using | ||||
| 	* def_using_namespace | ||||
|  | ||||
| @@ -82,27 +87,27 @@ | ||||
| 	A Code ast is provided but only completed upfront if all components are provided. | ||||
| 	Components are then added using the AST API for adding ASTs: | ||||
|  | ||||
| 	* code.add( AST* )         // Adds AST with validation. | ||||
| 	* code.add_entry( AST* )   // Adds AST entry without validation. | ||||
| 	* code.add_content( AST* ) // Adds AST string content without validation. | ||||
| 	* code.add( AST* )                     // Adds AST with validation. | ||||
| 	* code.add_entry( AST* )               // Adds AST entry without validation. | ||||
|  | ||||
| 	Code ASTs may be explictly validated at anytime using Code's check() member function. | ||||
|  | ||||
| 	Interface : | ||||
|  | ||||
| 	* make_forward_decl | ||||
| 	* make_class | ||||
| 	* make_enum | ||||
| 	* make_enum_class | ||||
| 	* make_global_body | ||||
| 	* make_proc | ||||
| 	* make_namespace | ||||
| 	* make_params | ||||
| 	* make_operator | ||||
| 	* make_params | ||||
| 	* make_proc | ||||
| 	* make_specifiers | ||||
| 	* make_struct | ||||
| 	* make_variable | ||||
| 	* make_type | ||||
| 	* make_typedef | ||||
| 	* make_using | ||||
| 	* make_using_namespace | ||||
|  | ||||
| 	### Parse construction | ||||
|  | ||||
| @@ -110,23 +115,33 @@ | ||||
|  | ||||
| 	Interface : | ||||
|  | ||||
| 	* parse_forward_decl | ||||
| 	* parse_class | ||||
| 	* parse_glboal_body | ||||
| 	* parse_proc | ||||
| 	* parse_classes | ||||
| 	* parse_enum | ||||
| 	* parse_enums | ||||
| 	* parse_global_body | ||||
| 	* parse_namespace | ||||
| 	* parse_params | ||||
| 	* parse_namespaces | ||||
| 	* parse_operator | ||||
| 	* parse_specifiers | ||||
| 	* parse_operators | ||||
| 	* parse_proc | ||||
| 	* parse_procs | ||||
| 	* parse_struct | ||||
| 	* parse_strucs | ||||
| 	* parse_variable | ||||
| 	* parse_variables | ||||
| 	* parse_type | ||||
| 	* parse_typedef | ||||
| 	* parse_typedefs | ||||
| 	* parse_using | ||||
| 	* parse_using | ||||
| 	* parse_usings | ||||
|  | ||||
| 	The parse API treats any execution scope definitions with no validation and are turned into untyped Code ASTs. | ||||
| 	This includes the assignmetn of variables; due to the library not yet supporting c/c++ expression parsing. | ||||
|  | ||||
| 	The plural variants provide an array of codes, its up to the user to add them to a body AST  | ||||
| 	(they are not auto-added to a body) | ||||
|  | ||||
| 	### Untyped constructions | ||||
|  | ||||
| 	Code ASTs are constructed using unvalidated strings. | ||||
| @@ -158,7 +173,7 @@ | ||||
| // #define GEN_DEFINE_DSL | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| // #define GEN_BAN_CPP_TEMPLATES | ||||
| // #define GEN_USE_FATAL | ||||
| #define GEN_USE_FATAL | ||||
|  | ||||
| #ifdef gen_time | ||||
| namespace gen | ||||
| @@ -179,41 +194,52 @@ namespace gen | ||||
| 	{ | ||||
| 		enum Type : u8 | ||||
| 		{ | ||||
| 			Invalid,        // Used only with improperly created Code nodes | ||||
| 			Untyped,        // User provided raw string | ||||
| 			Decl_Function,  // <specifier> <type> <name> ( <params> ) | ||||
| 			Decl_Type,      // <type> <name>; | ||||
| 			Function,       // <type> <name>( <parameters> ) | ||||
| 			Function_Body,  // { <body> } | ||||
| 			Namespace,      // Define a namespace | ||||
| 			Namespace_Body, // { <body> }  | ||||
| 			Parameters,     // <type> <param> ... | ||||
| 			Specifiers,     // Used with functions, structs, variables | ||||
| 			Struct,         // struct <specifier> <name> <parent> | ||||
| 			Struct_Body,    // {<body> } | ||||
| 			Variable,       // <type> <name> | ||||
| 			Typedef,        // typedef <type> <alias> | ||||
| 			Typename,       // Typename, used with other types | ||||
| 			Using,          // using <name> = <type> | ||||
| 			Unit,           // Represents a file. | ||||
| 			Invalid,         | ||||
| 			Untyped,         | ||||
| 			Access_Public, | ||||
| 			Access_Private, | ||||
| 			Access_Protected, | ||||
| 			Class,           | ||||
| 			Enum,            | ||||
| 			Enum_Body,       | ||||
| 			Global_Body,     | ||||
| 			Namespace,       | ||||
| 			Namespace_Body,  | ||||
| 			Parameters,      | ||||
| 			Proc,            | ||||
| 			Proc_Body,       | ||||
| 			Proc_Forward,    | ||||
| 			Specifiers,      | ||||
| 			Struct,          | ||||
| 			Struct_Body,     | ||||
| 			Variable,        | ||||
| 			Typedef,         | ||||
| 			Typename,        | ||||
| 			Using,           | ||||
|  | ||||
| 			Num_Types | ||||
| 		}; | ||||
|  | ||||
| 		inline | ||||
| 		local_persist | ||||
| 		char const* str( Type type ) | ||||
| 		{ | ||||
| 			static  | ||||
| 			char const* lookup[Num_Types] = { | ||||
| 				"Invalid", | ||||
| 				"Untyped", | ||||
| 				"Decl_Function", | ||||
| 				"Decl_Type", | ||||
| 				"Function", | ||||
| 				"Function_Body", | ||||
| 				"Access_Public", | ||||
| 				"Access_Private", | ||||
| 				"Access_Protected", | ||||
| 				"Class", | ||||
| 				"Enum", | ||||
| 				"Enum_Body", | ||||
| 				"Global_Body", | ||||
| 				"Namespace", | ||||
| 				"Namespace_Body", | ||||
| 				"Parameters", | ||||
| 				"Proc", | ||||
| 				"Proc_Body", | ||||
| 				"Proc_Forward", | ||||
| 				"Specifiers", | ||||
| 				"Struct", | ||||
| 				"Struct_Body", | ||||
| @@ -221,7 +247,6 @@ namespace gen | ||||
| 				"Typedef", | ||||
| 				"Typename", | ||||
| 				"Using", | ||||
| 				"Unit", | ||||
| 			}; | ||||
|  | ||||
| 			return lookup[ type ]; | ||||
| @@ -245,7 +270,7 @@ namespace gen | ||||
| 		inline  | ||||
| 		char const* str( Type op ) | ||||
| 		{ | ||||
| 			static  | ||||
| 			local_persist | ||||
| 			char const* lookup[ Num_Ops ] = { | ||||
| 				"+", | ||||
| 				"-", | ||||
| @@ -262,43 +287,48 @@ namespace gen | ||||
| 	{ | ||||
| 		enum Type : u8 | ||||
| 		{ | ||||
| 			Attribute,          // [ <attributes ] | ||||
| 			Alignas,            // alignas(#) | ||||
| 			Constexpr,          // constexpr | ||||
| 			Const,              // const | ||||
| 			Inline,             // inline | ||||
| 			RValue,             //  | ||||
| 			Attribute,           | ||||
| 			Alignas,             | ||||
| 			Constexpr,           | ||||
| 			Const,               | ||||
| 			Inline,              | ||||
| 			Pointer,             | ||||
| 			Reference,           | ||||
| 			RValue,              | ||||
|  | ||||
| 			C_Linkage,          // extern "C" | ||||
| 			API_Import,         // Vendor specific way dynamic import symbol | ||||
| 			API_Export,         // Vendor specific way to dynamic export | ||||
| 			External_Linkage,   // extern | ||||
| 			Internal_Linkage,   // static (within unit file) | ||||
| 			Static_Member,      // static (within sturct/class) | ||||
| 			Local_Persist,      // static (within function) | ||||
| 			Thread_Local,       // thread_local | ||||
| 			C_Linkage,           | ||||
| 			API_Import,          | ||||
| 			API_Export,          | ||||
| 			External_Linkage,    | ||||
| 			Internal_Linkage,    | ||||
| 			Static_Member,       | ||||
| 			Local_Persist,       | ||||
| 			Thread_Local,        | ||||
|  | ||||
| 			Invalid, | ||||
| 			Num_Specifiers, | ||||
| 			Invalid | ||||
| 		}; | ||||
|  | ||||
| 		// Specifier to string | ||||
| 		inline | ||||
| 		char const* to_str( Type specifier ) | ||||
| 		{ | ||||
| 			static  | ||||
| 			local_persist | ||||
| 			char const* lookup[ Num_Specifiers ] = { | ||||
| 				"alignas", | ||||
| 				"constexpr", | ||||
| 				"const", | ||||
| 				"inline", | ||||
| 				"*", | ||||
| 				"&", | ||||
| 				"&&", | ||||
|  | ||||
| 				"extern \"C\"", | ||||
|  | ||||
| 			#if defined(ZPL_SYSTEM_WINDOWS) && 0// API_Import and API_Export strings | ||||
| 			#if defined(ZPL_SYSTEM_WINDOWS) | ||||
| 				"__declspec(dllexport)", | ||||
| 				"__declspec(dllimport)", | ||||
| 			#elif defined(ZPL_SYSTEM_MACOS) || 1 | ||||
| 			#elif defined(ZPL_SYSTEM_MACOS) | ||||
| 				"__attribute__ ((visibility (\"default\")))", | ||||
| 				"__attribute__ ((visibility (\"default\")))", | ||||
| 			#endif | ||||
| @@ -315,14 +345,14 @@ namespace gen | ||||
| 		 | ||||
| 		Type to_type( char const* str, s32 length ) | ||||
| 		{ | ||||
| 			static  | ||||
| 			local_persist | ||||
| 			u32 keymap[ Num_Specifiers ]; | ||||
| 			do_once_start | ||||
| 				for ( u32 index = 0; index < Num_Specifiers; index++ ) | ||||
| 				{ | ||||
| 					char const* enum_str = to_str( (Type)index ); | ||||
|  | ||||
| 					keymap[index] = crc32( enum_str, strnlen(enum_str, 42) ); | ||||
| 					keymap[index] = crc32( enum_str, zpl_strnlen(enum_str, 42) ); | ||||
| 				} | ||||
| 			do_once_end | ||||
|  | ||||
| @@ -339,6 +369,7 @@ namespace gen | ||||
| 	} | ||||
| 	using SpecifierT = ESpecifier::Type; | ||||
|  | ||||
| #pragma region Data Structures | ||||
| 	// TODO: If perf needs it, convert layout an SOA format. | ||||
| 	/*  | ||||
| 		Simple AST POD with functionality to seralize into C++ syntax. | ||||
| @@ -349,32 +380,46 @@ namespace gen | ||||
| 	*/ | ||||
| 	struct AST | ||||
| 	{ | ||||
| 	#pragma region Member API | ||||
| 	#pragma region Member Procedures | ||||
| 		bool add( AST* other ); | ||||
|  | ||||
| 		forceinline | ||||
| 		void add( AST* other ) | ||||
| 		void add_entry( AST* other ) | ||||
| 		{ | ||||
| 			array_append( Entries, other ); | ||||
|  | ||||
| 			other->Parent = this; | ||||
| 		} | ||||
|  | ||||
| 		forceinline | ||||
| 		AST* body() | ||||
| 		{ | ||||
| 			return Entries[0]; | ||||
| 		} | ||||
|  | ||||
| 		forceinline | ||||
| 		bool check(); | ||||
|  | ||||
| 		forceinline | ||||
| 		bool has_entries() const | ||||
| 		{ | ||||
| 			static bool lookup[ ECode::Num_Types] = { | ||||
| 				false, // Invalid | ||||
| 				false, // Untyped | ||||
| 				true,  // Decl_Function | ||||
| 				true,  // Decl_Type | ||||
| 				true,  // Function | ||||
| 				false, | ||||
| 				false, | ||||
| 				false, | ||||
| 				true,  // Global_Body | ||||
| 				true,  // Parameters | ||||
| 				true,  // Proc | ||||
| 				true,  // Proc_Body | ||||
| 				true,  // Proc_Forward | ||||
| 				false, // Specifies | ||||
| 				true,  // Struct | ||||
| 				true,  // Struct_Body | ||||
| 				true,  // Variable | ||||
| 				true,  // Typedef | ||||
| 				true,  // Typename | ||||
| 				true,  // Using | ||||
| 			}; | ||||
|  | ||||
| 			return lookup[Type]; | ||||
| @@ -394,7 +439,7 @@ namespace gen | ||||
|  | ||||
| 		string to_string() const; | ||||
|  | ||||
| 	#pragma endregion Member API | ||||
| 	#pragma endregion Member Procedures | ||||
|  | ||||
| 	#define Using_Code_POD          \ | ||||
| 		CodeT             Type;     \ | ||||
| @@ -434,20 +479,32 @@ namespace gen | ||||
| 		Code body() | ||||
| 		{ | ||||
| 			if ( ast->Type == ECode::Invalid ) | ||||
| 				fatal("Code::body: Type is invalid, cannot get"); | ||||
| 			{ | ||||
| 				log_failure("Code::body: Type is invalid, cannot get"); | ||||
| 				return InvalidCode; | ||||
| 			} | ||||
|  | ||||
| 			if ( ast->Entries == nullptr || array_count(ast->Entries) == 0 ) | ||||
| 				fatal("Code::body: Entries of ast not properly setup."); | ||||
| 			{ | ||||
| 				log_failure("Code::body: Entries of ast not properly setup."); | ||||
| 				return InvalidCode; | ||||
| 			} | ||||
|  | ||||
| 			return pcast( Code, ast->Entries[0]); | ||||
| 		#ifdef GEN_ENFORCE_READONLY_AST  | ||||
| 			if ( ast->Readonly ) | ||||
| 			{ | ||||
| 				log_failure("Attempted to a body AST from a readonly AST!");			 | ||||
| 				return InvalidCode; | ||||
| 			} | ||||
| 		#endif | ||||
|  | ||||
| 			return * (Code*)( ast->body() ); | ||||
| 		} | ||||
|  | ||||
| 		forceinline | ||||
| 		void lock() | ||||
| 		{ | ||||
| 		#ifdef GEN_ENFORCE_READONLY_AST | ||||
| 			ast->Readonly = true; | ||||
| 		#endif | ||||
| 		} | ||||
|  | ||||
| 		forceinline | ||||
| @@ -468,6 +525,20 @@ namespace gen | ||||
| 		 | ||||
| 		Code& operator =( Code other ) | ||||
| 		{ | ||||
| 			if ( ast == nullptr ) | ||||
| 			{ | ||||
| 				log_failure("Attempt to set with a null AST!"); | ||||
| 				return *this; | ||||
| 			} | ||||
|  | ||||
| 		#ifdef GEN_ENFORCE_READONLY_AST  | ||||
| 			if ( ast->Readonly ) | ||||
| 			{ | ||||
| 				log_failure("Attempted to set a readonly AST!");			 | ||||
| 				return *this; | ||||
| 			} | ||||
| 		#endif | ||||
|  | ||||
| 			ast = other.ast; | ||||
|  | ||||
| 			return *this; | ||||
| @@ -476,12 +547,18 @@ namespace gen | ||||
| 		forceinline | ||||
| 		AST* operator ->()  | ||||
| 		{ | ||||
| 		#ifdef GEN_ENFORCE_READONLY_AST  | ||||
| 			if ( ast == nullptr ) | ||||
| 				fatal("Attempt to dereference a nullptr!"); | ||||
| 			{ | ||||
| 				log_failure("Attempt to dereference a nullptr!"); | ||||
| 				return nullptr; | ||||
| 			} | ||||
|  | ||||
| 		#ifdef GEN_ENFORCE_READONLY_AST  | ||||
| 			if ( ast->Readonly ) | ||||
| 				fatal("Attempted to access a member from a readonly ast!");			 | ||||
| 			{ | ||||
| 				log_failure("Attempted to access a member from a readonly AST!");			 | ||||
| 				return nullptr; | ||||
| 			} | ||||
| 		#endif | ||||
|  | ||||
| 			return ast; | ||||
| @@ -495,6 +572,10 @@ namespace gen | ||||
| 	// Used internally for the most part to identify invaidly generated code. | ||||
| 	extern const Code InvalidCode; | ||||
|  | ||||
| 	/* | ||||
| 	*/ | ||||
| 	ZPL_TABLE_DECLARE( ZPL_EXTERN, StringTable, str_tbl_, string ); | ||||
|  | ||||
| 	/* | ||||
| 		Type registy: Used to store Typename ASTs. Types are registered by their string literal value. | ||||
|  | ||||
| @@ -502,47 +583,56 @@ namespace gen | ||||
| 		Strings made with the Typename ASTs are stored in thier own arena allocator. | ||||
| 		TODO: Implement and replace usage of def_type. | ||||
| 	*/ | ||||
| 	ZPL_TABLE_DECLARE( ZPL_EXTERN, TypeRegistry, type_reg_, Code ); | ||||
| 	ZPL_TABLE_DECLARE( ZPL_EXTERN, TypeTable, type_tbl_, Code ); | ||||
| #pragma endregion Data Structures | ||||
|  | ||||
| #pragma region gen API | ||||
| #pragma region Gen Interface | ||||
| 	/* | ||||
| 		Initialize the library. | ||||
| 		This currently just initializes the CodePool. | ||||
| 	*/	 | ||||
| 	void init(); | ||||
|  | ||||
| 	#pragma region Upfront | ||||
| 	/* | ||||
| 		Foward Declare a type: | ||||
| 		<specifiers> <type> <name>; | ||||
| 	*/ | ||||
| 	Code def_fwd_type( Code type, char const* name, Code specifiers = UnusedCode ); | ||||
| 	// Use this only if you know you generated the code you needed to a file | ||||
| 	// And rather get rid of current code asts instead of growing the pool memory. | ||||
| 	void clear_code_pool(); | ||||
|  | ||||
| 	/* | ||||
| 		Foward Declare a function: | ||||
| 		<specifiers> <name> ( <params> ); | ||||
| 	*/ | ||||
| 	Code def_fwd_proc( char const* name | ||||
| 	// Set these before calling gen's init() procedure. | ||||
|  | ||||
| 	void set_init_reserve_code_pool   ( sw size ); | ||||
| 	void set_init_reserve_string_arena( sw size ); | ||||
| 	void set_init_reserve_string_table( sw size ); | ||||
| 	void set_init_reserve_type_table  ( sw size ); | ||||
|  | ||||
| 	void set_allocator_code_pool   ( allocator pool_allocator ); | ||||
| 	void set_allocator_string_arena( allocator string_allocator ); | ||||
| 	void set_allocator_string_table( allocator string_allocator ); | ||||
| 	void set_allocator_type_table  ( allocator type_reg_allocator ); | ||||
|  | ||||
| #	pragma region Upfront | ||||
| 	Code def_class     ( char const* name, Code body, Code parent = UnusedCode, Code specifiers = UnusedCode ); | ||||
| 	Code def_class_body( s32 num, ... ); | ||||
| 	Code def_class_fwd ( char const* name ); | ||||
|  | ||||
| 	Code def_enum( char const* name, Code type, Code body ); | ||||
|  | ||||
| 	Code def_global_body( s32 num, ... ); | ||||
|  | ||||
| 	Code def_namespace     ( char const* name, Code body ); | ||||
| 	Code def_namespace_body( s32 num, ... ); | ||||
|  | ||||
| 	Code def_operator( OperatorT op | ||||
| 		, Code specifiers | ||||
| 		, Code params | ||||
| 		, Code ret_type | ||||
| 		, Code body  | ||||
| 	); | ||||
| 	Code def_operator_fwd( OperatorT op, Code specifiers, Code params, Code ret_type ); | ||||
|  | ||||
| 	/* | ||||
| 		Define an expression: | ||||
| 		< c/c++ expression > | ||||
| 	Code def_param( Code type, char const* name ); | ||||
| 	Code def_params( s32 num, ... ); | ||||
| 	Code def_params( s32 num, Code* params ); | ||||
|  | ||||
| 		TODO: Evalute if you want to validiate at the execution layer during gen_time (dosen't seem necessary) | ||||
| 	*/ | ||||
| 	// Code def_expression( Code value ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a function: | ||||
| 		<specifiers> <name> ( <params> ) | ||||
| 		{ | ||||
| 			<body> | ||||
| 		} | ||||
| 	*/ | ||||
| 	Code def_proc( char const* name | ||||
| 		, Code specifiers | ||||
| 		, Code params | ||||
| @@ -550,197 +640,101 @@ namespace gen | ||||
| 		, Code body  | ||||
| 	); | ||||
|  | ||||
| 	/* | ||||
| 		Define a fucntion body: | ||||
| 		{ | ||||
| 			<entry> | ||||
|  | ||||
| 			... | ||||
| 		} | ||||
|  | ||||
| 		There will be an empty line separation between entires | ||||
| 	*/ | ||||
| 	Code def_proc_body( s32 num, ... ); | ||||
| 	Code def_proc_body( s32 num, Code* codes ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a namespace; | ||||
| 		namespace <name> | ||||
| 		{ | ||||
| 			<body> | ||||
| 		} | ||||
| 	*/ | ||||
| 	Code def_namespace( char const* name, Code body ); | ||||
| 	Code def_proc_fwd( char const* name | ||||
| 		, Code specifiers | ||||
| 		, Code params | ||||
| 		, Code ret_type | ||||
| 	); | ||||
|  | ||||
| 	/* | ||||
| 		Define a namespace body: | ||||
| 		{ | ||||
| 			<entry> | ||||
|  | ||||
| 			... | ||||
| 		} | ||||
|  | ||||
| 		There will be an empty line separation between entires | ||||
| 	*/ | ||||
| 	Code def_namespace_body( s32 num, ... ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a set of parameters for a function: | ||||
| 		<name> <type>, ... | ||||
| 	*/ | ||||
| 	Code def_params( s32 num, ... ); | ||||
| 	Code def_params( s32 num, char const** params ); | ||||
|  | ||||
| 	/* | ||||
| 		Define an operator definition. | ||||
| 	*/ | ||||
| 	Code def_operator( OperatorT op, Code specifiers, Code params, Code ret_type, Code body ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a set of specifiers for a function, struct, type, or varaible | ||||
|  | ||||
| 		Note: 		 | ||||
| 		If alignas is specified the procedure expects the next argument to be the alignment value. | ||||
| 		If attribute is specified the procedure expects the next argument to be its content as a string. | ||||
| 	*/ | ||||
| 	Code def_specifier( SpecifierT* specifier ); | ||||
| 	Code def_specifiers( s32 num , ... ); | ||||
| 	Code def_specifiers( s32 num, SpecifierT* specs ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a struct: | ||||
| 		struct <specifiers> <name> : <parent> | ||||
| 		{ | ||||
| 			<body> | ||||
| 		} | ||||
| 	*/ | ||||
| 	Code def_struct( char const* name, Code body, Code parent = UnusedCode, Code specifiers = UnusedCode ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a struct's body: | ||||
| 		{ | ||||
| 			<entry> | ||||
|  | ||||
| 			... | ||||
| 		} | ||||
|  | ||||
| 		There will be an empty line separation between entires | ||||
| 	*/ | ||||
| 	Code def_struct_body( s32 num, ... ); | ||||
| 	Code def_struct_body( s32 num, Code* codes ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a variable: | ||||
| 		<specifiers> <type> <name> = <value>; | ||||
| 	*/ | ||||
| 	Code def_sturct_fwd(); | ||||
|  | ||||
| 	Code def_variable( Code type, char const* name, Code value = UnusedCode, Code specifiers = UnusedCode ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a typename AST value. | ||||
| 		Useless by itself, its intended to be used in conjunction with other Code. | ||||
| 	Code def_type( char const* name, Code specifiers = UnusedCode ); | ||||
|  | ||||
| 	Planned - Not yet Implemented: | ||||
| 		Typename Codes are not held in the CodePool, instead they are stored in a  | ||||
| 		type registry (hastable where the key is a crc hash of the name string). | ||||
|  | ||||
| 		If a key exists the existing code value will be provided. | ||||
| 	*/ | ||||
| 	Code def_type( char const* name ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a using typedef: | ||||
| 		using <name> = <type>; | ||||
| 	*/ | ||||
| 	Code def_using( char const* name, Code type ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a using namespace: | ||||
| 		using namespace <name>; | ||||
|  | ||||
| 		Can only be used in either a  | ||||
| 	*/ | ||||
| 	Code def_using          ( char const* name, Code type ); | ||||
| 	Code def_using_namespace( char const* name ); | ||||
| 	#pragma endregion Upfront | ||||
| #	pragma endregion Upfront | ||||
|  | ||||
| 	#pragma region Incremental | ||||
| 	/* | ||||
| 		Provides an incomplete procedure AST but sets the intended type. | ||||
| 		Any adds will be type checked. | ||||
| #	pragma region Incremental | ||||
| 	Code make_class( char const* name, Code parent = UnusedCode, Code specifiers = UnusedCode ); | ||||
|  | ||||
| 	Code make_enum      ( char const* name, Code type = UnusedCode, Code body = UnusedCode ); | ||||
| 	Code make_enum_class( char const* name, Code type = UnusedCode, Code body = UnusedCode ); | ||||
|  | ||||
| 	Code make_global_body( char const* name = "", s32 num = 0, ... ); | ||||
| 	 | ||||
| 	Code make_namespace( char const* name ); | ||||
|  | ||||
| 	Code make_operator( OperatorT op | ||||
| 		, Code specifiers = UnusedCode | ||||
| 		, Code params = UnusedCode | ||||
| 		, Code ret_type = UnusedCode | ||||
| 		, Code body  = UnusedCode | ||||
| 	); | ||||
|  | ||||
| 	Code make_params( s32 num, ... ); | ||||
|  | ||||
| 		Body is automatically made. Use body() to retrieve. | ||||
| 	*/ | ||||
| 	Code make_proc( char const* name | ||||
| 		, Code specifiers = UnusedCode | ||||
| 		, Code params = UnusedCode | ||||
| 		, Code ret_type = UnusedCode | ||||
| 	); | ||||
| 	 | ||||
| 	/* | ||||
| 		Provides an incomplete struct AST but sets the intended type. | ||||
| 		Any adds will be type checked. | ||||
|  | ||||
| 		Body is automatically made. Use body() to retrieve. | ||||
| 	*/ | ||||
| 	Code make_specifiers( s32 num , ... ); | ||||
| 	Code make_specifiers( s32 num, SpecifierT* specs ); | ||||
| 	 | ||||
| 	Code make_struct( char const* name, Code parent = UnusedCode, Code specifiers = UnusedCode ); | ||||
|  | ||||
| /* | ||||
| 	Creates a unit file. | ||||
| 	Code make_variable( char const* name, Code type = UnusedCode, Code value = UnusedCode, Code specifiers = UnusedCode ); | ||||
|  | ||||
| 	These represent an encapsulation of a generated file | ||||
| 	Used this if you need to pass around a group of Code entires at file scope level. | ||||
| 	Code make_type( char const* name, Code specifiers = UnusedCode ); | ||||
|  | ||||
| 	The name provided is the name of the file. | ||||
| */ | ||||
| Code make_file_body( char const* name ); | ||||
| 	#pragma endregion Incremental | ||||
| 	Code make_using( char const* name, Code type = UnusedCode, Code specifiers = UnusedCode ); | ||||
| #	pragma endregion Incremental | ||||
|  | ||||
| 	/* | ||||
| 	*/ | ||||
| 	Code parse_variable( char const* var_def, s32 length ); | ||||
| #	pragma region Parsing | ||||
| 	Code parse_class( char const* class_def, s32 length ); | ||||
| 	s32 parse_classes( char const* class_defs, s32 length, Code* out_classes ); | ||||
|  | ||||
| 	/* | ||||
| 	*/ | ||||
| 	Code parse_using( char const* using_def, s32 length ); | ||||
| 	Code parse_enum( char const* enum_def, s32 length); | ||||
| 	s32 parse_enums( char const* enum_defs, s32 length, Code* out_enums ); | ||||
|  | ||||
| 	/* | ||||
| 	Code parse_global_body( char const* body_def, s32 length ); | ||||
|  | ||||
| 	*/ | ||||
| 	Code parse_operator( char const* operator_def, s32 length ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a procedure by parsing a string. | ||||
|  | ||||
| 		Note: This parser only supports the language features the library supports | ||||
| 		Any other features used and the lex or parse operation will fail. | ||||
|  | ||||
| 		This is not a full-on c/c++ parser, it literally only grabs  | ||||
| 		what it needs to reconstruct the Code AST for seralization in the  | ||||
| 		builder, nothing else. | ||||
| 	*/ | ||||
| 	Code parse_proc( char const* proc_def, s32 length ); | ||||
| 	s32 parse_procs( char const* proc_defs, s32 length, Code* out_procs ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a struct by parsing a string. | ||||
|  | ||||
| 		Note: This parser only supports the language features the library supports | ||||
| 		Any other features used and the lex or parse operation will fail. | ||||
|  | ||||
| 		This is not a full-on c/c++ parser, it literally only grabs  | ||||
| 		what it needs to reconstruct the Code AST for seralization in the  | ||||
| 		builder, nothing else. | ||||
| 	*/ | ||||
| 	Code parse_struct( char const* struct_def, s32 length ); | ||||
| 	s32 parse_structs( char const* struct_defs, s32 length, Code* out_struct_codes ); | ||||
|  | ||||
| 	/* | ||||
| 	 | ||||
| 	*/ | ||||
| 	s32 parse_vars( char const* vars_def, s32 length, Code* out_vars_codes ); | ||||
| 	Code parse_variable( char const* var_def, s32 length ); | ||||
| 	s32 parse_variables( char const* vars_def, s32 length, Code* out_var_codes ); | ||||
|  | ||||
| 	/* | ||||
| 	Code parse_type( char const* type_def, s32 length ); | ||||
|  | ||||
| 	*/ | ||||
| 	s32 parse_usings( char const* usings_def, s32 length, Code* out_usings_codes ); | ||||
| 	Code parse_typedef( char const* typedef_def, s32 length ); | ||||
| 	s32 parse_typedef( char const* typedef_def, s32 length, Code* out_typedef_codes ); | ||||
|  | ||||
| 	#pragma region Untyped text | ||||
| 	Code parse_using ( char const* using_def, s32 length ); | ||||
| 	s32 parse_usings( char const* usings_def, s32 length, Code* out_using_codes ); | ||||
| #	pragma endregion Parsing | ||||
|  | ||||
| #	pragma region Untyped text | ||||
| 	/* | ||||
| 		Define an untyped code string. | ||||
|  | ||||
| @@ -779,7 +773,7 @@ Code make_file_body( char const* name ); | ||||
| 		Consider this an a preprocessor define. | ||||
| 	*/ | ||||
| 	Code untyped_token_fmt( char const* fmt, s32 num_tokens, ... ); | ||||
| 	#pragma endregion Untyped text | ||||
| #	pragma endregion Untyped text | ||||
|  | ||||
| 	/*  | ||||
| 		Used to generate the files. | ||||
| @@ -806,7 +800,7 @@ Code make_file_body( char const* name ); | ||||
| 		bool open( char const* path ); | ||||
| 		void write(); | ||||
| 	}; | ||||
| #pragma endregion gen API | ||||
| #pragma endregion Gen Interface | ||||
| } | ||||
|  | ||||
| #pragma region MACROS | ||||
| @@ -839,7 +833,7 @@ Code make_file_body( char const* name ); | ||||
| #	define using_type( Name_, Type_ )		 Code Name_     = gen::def_using( #Name_, t_##Type_ ) | ||||
| #	define variable( Type_, Name_, ... )     Code Name_     = gen::def_variable( t_##Type_, #Name_, __VA_ARGS__ ) | ||||
|  | ||||
| #   define untyped( Value_ )                      gen::untyped_str( txt(Value_) ) | ||||
| #   define untyped( Value_ )                      gen::untyped_str( txt_with_length(Value_) ) | ||||
| #	define code_token( Fmt_, ... )                gen::untyped_token_fmt( Fmt_, VA_NARGS( __VA_ARGS__), __VA_ARGS__ ) | ||||
| #	define code_fmt( Fmt_, ... )                  gen::untyped_fmt( Fmt_, __VA_ARGS__ ) | ||||
| #	define specifiers( ... )                      gen::def_specifiers( VA_NARGS( __VA_ARGS__ ), __VA_ARGS__ ) | ||||
| @@ -849,19 +843,24 @@ Code make_file_body( char const* name ); | ||||
| #	define var( Type_, Name_, ... )               gen::def_variable( Type_, #Name_, __VA_ARGS__ ) | ||||
|  | ||||
| #   define make( Type_, Name_, ... )                                Code Name_ = make_##Type_( #Name_, __VA_ARGS__ ); | ||||
| #	define enum( Name_, Type_, Body_ )                                      gen::def_enum( #Name_, t_##Type_, Body_ ) | ||||
| #	define proc( Name_, Specifiers_, RetType_, Parameters_, Body_ ) Name_ = gen::def_proc( #Name_, Specifiers_, Parameters_, RetType_, Body_ ) | ||||
| #	define proc_body( ... )                                                 gen::def_proc_body( VA_NARGS( __VA_ARS__ ), __VA_ARGS__ ) | ||||
| #	define params( ... )                                                    gen::def_params( VA_NARGS( __VA_ARGS__ ) / 2, __VA_ARGS__ ) | ||||
| #	define struct( Name_, Parent_, Specifiers_, Body_ )             Name_ = gen::def_struct( #Name_, Body_, Parent_, Specifiers_ ) | ||||
| #	define struct_body( ... )                                               gen::def_struct_body( VA_NARGS( __VA_ARGS__ ), __VA_ARGS__ ) | ||||
|  | ||||
| #	define add_var( Type_, Name_, ... ) add( gen::def_variable( t_##Type_, #Name_, __VA_ARGS__ ) ) | ||||
| #	define add_untyped( Value_ )        add( gen::untyped_str( txt( Value ) ) ) | ||||
| #	define add_ret_type( ... ) | ||||
| #	define add_params( ... ) | ||||
| #	define add_var( Value_ )     add( gen::parse_variable( txt_with_length(Value_)) ) | ||||
| #	define add_untyped( Value_ ) add( gen::untyped_str( txt_with_length( Value_ ) ) ) | ||||
| #	define add_type( Value_ )    add( gen::parse_type( txt_with_length(Value_)) ) | ||||
| #	define add_params( Value_ )  add( gen::parse_params( txt_with_length(Value_) )) | ||||
|  | ||||
| #	define enum_code( Def_ )   gen::parse_enum( txt( Def_ ), sizeof( txt( Def_ )) ) | ||||
| #	define global_code( Def_ ) gen::parse_global_body( txt_with_length( Def_ )) | ||||
| #	define namespace_code( Def_ ) gen::parse_namespace( txt(Def_), sizeof( txt(Def_)) ) | ||||
| #	define proc_code( Def_ )   gen::parse_proc( txt( Def_ ), sizeof( txt( Def_ )) ) | ||||
| #	define struct_code( Def_ ) gen::parse_struct( txt( Def_ ), sizeof( txt( Def_ )) ) | ||||
| #	define variable_code( Def_ ) gen::parse_variable( txt_with_length( Def_ ) ) | ||||
| #endif | ||||
| #pragma endregion MACROS | ||||
|  | ||||
| @@ -873,31 +872,38 @@ namespace gen | ||||
| 	// These are not set until gen::init is called. | ||||
| 	// This just preloads a bunch of Code types into the code pool. | ||||
|  | ||||
| 	extern const Code t_void; | ||||
| 	extern Code t_void; | ||||
|  | ||||
| 	extern const Code t_bool; | ||||
| 	extern const Code t_char; | ||||
| 	extern const Code t_wchar_t; | ||||
| 	extern Code t_bool; | ||||
| 	extern Code t_char; | ||||
| 	extern Code t_wchar_t; | ||||
|  | ||||
| 	extern const Code t_s8; | ||||
| 	extern const Code t_s16; | ||||
| 	extern const Code t_s32; | ||||
| 	extern const Code t_s64; | ||||
| 	extern Code t_s8; | ||||
| 	extern Code t_s16; | ||||
| 	extern Code t_s32; | ||||
| 	extern Code t_s64; | ||||
|  | ||||
| 	extern const Code t_u8; | ||||
| 	extern const Code t_u16; | ||||
| 	extern const Code t_u32; | ||||
| 	extern const Code t_u64; | ||||
| 	extern Code t_u8; | ||||
| 	extern Code t_u16; | ||||
| 	extern Code t_u32; | ||||
| 	extern Code t_u64; | ||||
|  | ||||
| 	extern const Code t_sw; | ||||
| 	extern const Code t_uw; | ||||
| 	extern Code t_sw; | ||||
| 	extern Code t_uw; | ||||
|  | ||||
| 	extern const Code t_f32; | ||||
| 	extern const Code t_f64; | ||||
| 	extern Code t_f32; | ||||
| 	extern Code t_f64; | ||||
|  | ||||
| 	extern const Code spec_constexpr; | ||||
| 	extern const Code spec_inline; | ||||
| 	extern Code spec_constexpr; | ||||
| 	extern Code spec_inline; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| namespace gen | ||||
| { | ||||
| 	extern Code access_public; | ||||
| 	extern Code access_protected; | ||||
| 	extern Code access_private; | ||||
| } | ||||
| #pragma endregion CONSTANTS | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										543
									
								
								project/gen.singleheader.c99.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										543
									
								
								project/gen.singleheader.c99.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,543 @@ | ||||
| /* | ||||
| 	Will generate a c99 compliant version of the gen library | ||||
|  | ||||
| 	Note: This is done this way to test usage of library. | ||||
| */ | ||||
|  | ||||
| #define GEN_DEFINE_DSL | ||||
| #include "gen.cpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| ct char const* Header_Comment =  | ||||
| R"(/* | ||||
| 	genc: A simple staged metaprogramming library for C99. | ||||
| 	 | ||||
| 	This library is intended for small-to midsize projects. | ||||
|  | ||||
| 	AST type checking supports only a small subset of c++.  | ||||
| 	See the 'ECode' namespace and 'gen API' region to see what is supported. | ||||
|  | ||||
| 	### *WHAT IS NOT PROVIDED* | ||||
|  | ||||
| 	* Macro or template generation      : This library is to avoid those, adding support for them adds unnecessary complexity.  | ||||
| 	                                      If you desire define them outside the gen_time scopes.  | ||||
| 	* Expression validation             : Execution expressions are defined using the untyped string API.  | ||||
| 	                                      There is no parse API for validating expression (possibly will add in the future) | ||||
| 	* Complete file parser DSL          : This isn't like the unreal header tool.  | ||||
| 	                                      Code injection to file or based off a file contents is not supported by the api. However nothing is stopping you using the library for that purpose. | ||||
| 	* Modern c++ (STL library) features | ||||
|  | ||||
| 	The AST is managed by the library and provided the user via its interface prodedures. | ||||
|  | ||||
| 	Notes: | ||||
|  | ||||
| 	* The allocator definitions used are exposed to the user incase they want to dictate memory usage | ||||
| 	* ASTs are wrapped for the user in a Code struct which essentially a warpper for a AST* type.   | ||||
| 	* Both AST and Code have member symbols but their data layout is enforced to be POD types. | ||||
|  | ||||
| 	Data layout of AST struct: | ||||
|  | ||||
| 	genc_CodeT             Type;     | ||||
| 	bool                   Readonly; | ||||
| 	genc_AST*              Parent;   | ||||
| 	genc_string            Name ;     | ||||
| 	genc_string            Comment;  | ||||
| 	union {                     | ||||
| 		array(genc_AST*)   Entries; | ||||
| 		genc_string        Content; | ||||
| 	}; | ||||
|  | ||||
| 	*`CodeT` is a typedef for `ECode::Type` which is the type of the enum.* | ||||
|  | ||||
| 	ASTs can be set to readonly by calling Code's lock() member function. | ||||
| 	Adding comments is always available even if the AST is set to readonly.   | ||||
|  | ||||
| 	### There are four sets of interfaces for Code AST generation the library provides | ||||
|  | ||||
| 	* Upfront | ||||
| 	* Incremental | ||||
| 	* Parsing | ||||
| 	* Untyped | ||||
|  | ||||
| 	### Upfront Construction | ||||
|  | ||||
| 	All component ASTs must be previously constructed, and provided on creation of the code AST. | ||||
| 	The construction will fail and return InvalidCode otherwise. | ||||
|  | ||||
| 	Interface : | ||||
|  | ||||
| 	* genc_def_class | ||||
| 	* genc_def_class_body | ||||
| 	* genc_def_class_fwd | ||||
| 	* genc_def_enum | ||||
| 	* genc_def_enum_class | ||||
| 	* genc_def_enum_body | ||||
| 	* genc_def_global_body | ||||
| 	* genc_def_namespace | ||||
| 	* genc_def_namespace_body | ||||
| 	* genc_def_operator | ||||
| 	* genc_def_param | ||||
| 	* genc_def_params | ||||
| 	* genc_def_proc | ||||
| 	* genc_def_proc_body | ||||
| 	* genc_def_proc_fwd | ||||
| 	* genc_def_operator_fwd | ||||
| 	* genc_def_specifier | ||||
| 	* genc_def_specifiers | ||||
| 	* genc_def_struct | ||||
| 	* genc_def_struct_body | ||||
| 	* genc_def_struct_fwd | ||||
| 	* genc_def_variable | ||||
| 	* genc_def_type | ||||
| 	* genc_def_using | ||||
| 	* genc_def_using_namespace | ||||
|  | ||||
| 	### Incremental construction | ||||
|  | ||||
| 	A Code ast is provided but only completed upfront if all components are provided. | ||||
| 	Components are then added using the AST API for adding ASTs: | ||||
|  | ||||
| 	* genc_code_add( AST*, AST* other )                     // Adds AST with validation. | ||||
| 	* genc_code_add_entry( AST*, AST* other )               // Adds AST entry without validation. | ||||
|  | ||||
| 	Code ASTs may be explictly validated at anytime using Code's check() member function. | ||||
|  | ||||
| 	Interface : | ||||
|  | ||||
| 	* genc_make_class | ||||
| 	* genc_make_enum | ||||
| 	* genc_make_enum_class | ||||
| 	* genc_make_fwd | ||||
| 	* genc_make_global_body | ||||
| 	* genc_make_namespace | ||||
| 	* genc_make_operator | ||||
| 	* genc_make_params | ||||
| 	* genc_make_proc | ||||
| 	* genc_make_specifiers | ||||
| 	* genc_make_struct | ||||
| 	* genc_make_variable | ||||
| 	* genc_make_type | ||||
| 	* genc_make_using | ||||
|  | ||||
| 	### Parse construction | ||||
|  | ||||
| 	A string provided to the API is parsed for the intended language construct. | ||||
|  | ||||
| 	Interface : | ||||
|  | ||||
| 	* genc_parse_class | ||||
| 	* genc_parse_classes | ||||
| 	* genc_parse_class_fwd | ||||
| 	* genc_parse_classes_fwd | ||||
| 	* genc_parse_enum | ||||
| 	* genc_parse_enums | ||||
| 	* genc_parse_global_body | ||||
| 	* genc_parse_namespace | ||||
| 	* genc_parse_namespaces | ||||
| 	* genc_parse_params | ||||
| 	* genc_parse_proc | ||||
| 	* genc_parse_procs | ||||
| 	* genc_parse_operator | ||||
| 	* genc_parse_operators | ||||
| 	* genc_parse_specifiers | ||||
| 	* genc_parse_struct | ||||
| 	* genc_parse_strucs | ||||
| 	* genc_parse_variable | ||||
| 	* genc_parse_variables | ||||
| 	* genc_parse_type | ||||
| 	* genc_parse_types | ||||
| 	* genc_parse_using | ||||
| 	* genc_parse_usings | ||||
|  | ||||
| 	The parse API treats any execution scope definitions with no validation and are turned into untyped Code ASTs. | ||||
| 	This includes the assignmetn of variables; due to the library not yet supporting c/c++ expression parsing. | ||||
|  | ||||
| 	The plural variants provide an array of codes, its up to the user to add them to a body AST  | ||||
| 	(they are not auto-added to a body) | ||||
|  | ||||
| 	### Untyped constructions | ||||
|  | ||||
| 	Code ASTs are constructed using unvalidated strings. | ||||
|  | ||||
| 	Interface : | ||||
|  | ||||
| 	* genc_untyped_str | ||||
| 	* genc_untyped_fmt | ||||
| 	* genc_untyped_token_fmt | ||||
|  | ||||
| 	During serialization any untyped Code AST is has its string value directly injected inline of  | ||||
| 	whatever context the content existed as an entry within. | ||||
| 	Even though thse are not validated from somewhat correct c/c++ syntax or components, it doesn't mean that | ||||
| 	Untyped code can be added as any component of a Code AST: | ||||
|  | ||||
| 	* Untyped code cannot have children, thus there cannot be recursive injection this way. | ||||
| 	* Untyped code can only be a child of a parent of body AST, or for values of an assignment. | ||||
|  | ||||
| 	These restrictions help prevent abuse of untyped code to some extent. | ||||
| */ | ||||
| )"; | ||||
|  | ||||
| Code IfDef_GENC_IMPLEMENTATION; | ||||
| Code EndIf_GENC_IMPLEMENTATION; | ||||
|  | ||||
| Code make_log_failure() | ||||
| { | ||||
| 	Code result = make_global_body(); | ||||
| 	{ | ||||
| 		result->add( untyped_str( | ||||
| 			R"(#ifdef GEN_USE_FATAL)" | ||||
| 		)); | ||||
|  | ||||
| 		result->add( proc_code( | ||||
| 			inline | ||||
| 			sw genc_log_failure(char const *fmt, ...)  | ||||
| 			{ | ||||
| 				if ( genc_global_ShouldShowDebug == false ) | ||||
| 					return 0; | ||||
|  | ||||
| 				sw res; | ||||
| 				va_list va; | ||||
| 				 | ||||
| 				va_start(va, fmt); | ||||
| 				res = zpl_printf_va(fmt, va); | ||||
| 				va_end(va); | ||||
| 				 | ||||
| 				return res; | ||||
| 			} | ||||
| 		)); | ||||
|  | ||||
| 		result->add( untyped_str( | ||||
| 			R"(#else)" | ||||
| 		)); | ||||
|  | ||||
| 		result->add( parse_proc( | ||||
| R"(inline | ||||
| sw genc_log_failure(char const *fmt, ...)  | ||||
| { | ||||
| 	local_persist thread_local  | ||||
| 	char buf[ZPL_PRINTF_MAXLEN] = { 0 }; | ||||
|  | ||||
| 	va_list va; | ||||
|  | ||||
| #if Build_Debug | ||||
| 	va_start(va, fmt); | ||||
| 	zpl_snprintf_va(buf, ZPL_PRINTF_MAXLEN, fmt, va); | ||||
| 	va_end(va); | ||||
|  | ||||
| 	assert_crash(buf); | ||||
| 	return -1; | ||||
| #else | ||||
| 	va_start(va, fmt); | ||||
| 	zpl_printf_err_va( fmt, va); | ||||
| 	va_end(va); | ||||
|  | ||||
| 	zpl_exit(1); | ||||
| 	return -1; | ||||
| #endif | ||||
| })" | ||||
| 		,	372 | ||||
| 		)); | ||||
|  | ||||
| 		result->add( untyped_str( | ||||
| 			R"(#endif)" | ||||
| 		)); | ||||
|  | ||||
| 		result->check(); | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| Code make_ECode() | ||||
| { | ||||
| 	Code ECode = make_global_body(); | ||||
| 	{ | ||||
| 		ECode->add( parse_enum( | ||||
| R"(enum genc_ECode | ||||
| { | ||||
| 	Invalid, | ||||
| 	Untyped, | ||||
| 	Enum, | ||||
| 	Enum_Body, | ||||
| 	Global_Body, | ||||
| 	Parameters, | ||||
| 	Proc,            | ||||
| 	Proc_Body,       | ||||
| 	Proc_Forward,    | ||||
| 	Specifiers,      | ||||
| 	Struct,          | ||||
| 	Struct_Body,     | ||||
| 	Variable,        | ||||
| 	Typedef,         | ||||
| 	Typename,   | ||||
|  | ||||
| 	Num_Types | ||||
| }; | ||||
| typedef u32 genc_CodeT;)" + 1 | ||||
| 		,	280 | ||||
| 		)); | ||||
|  | ||||
| 		ECode->add( proc_code( | ||||
| 			inline | ||||
| 			char const* genc_ecode_to_str( Type type ) | ||||
| 			{ | ||||
| 				genc_local_persist | ||||
| 				char const* lookup[Num_Types] = { | ||||
| 					"Invalid", | ||||
| 					"Untyped", | ||||
| 					"Access_Public", | ||||
| 					"Access_Private", | ||||
| 					"Access_Protected", | ||||
| 					"Class", | ||||
| 					"Enum", | ||||
| 					"Enum_Body", | ||||
| 					"Global_Body", | ||||
| 					"Namespace", | ||||
| 					"Namespace_Body", | ||||
| 					"Parameters", | ||||
| 					"Proc", | ||||
| 					"Proc_Body", | ||||
| 					"Proc_Forward", | ||||
| 					"Specifiers", | ||||
| 					"Struct", | ||||
| 					"Struct_Body", | ||||
| 					"Variable", | ||||
| 					"Typedef", | ||||
| 					"Typename", | ||||
| 					"Using", | ||||
| 				}; | ||||
|  | ||||
| 				return lookup[ type ]; | ||||
| 			} | ||||
| 		)); | ||||
|  | ||||
| 		ECode->check(); | ||||
| 	} | ||||
|  | ||||
| 	return ECode; | ||||
| } | ||||
|  | ||||
| Code make_EOperator() | ||||
| { | ||||
| 	Code eoperator = make_global_body(); | ||||
|  | ||||
| 	return eoperator; | ||||
| } | ||||
|  | ||||
| Code make_ESpecifier() | ||||
| { | ||||
| 	Code especifier = make_global_body(); | ||||
|  | ||||
| 	return especifier; | ||||
| } | ||||
|  | ||||
| Code make_Code() | ||||
| { | ||||
| 	Code code = make_global_body(); | ||||
|  | ||||
| 	code->add( struct_code( | ||||
| 		struct genc_AST | ||||
| 		{ | ||||
| 			genc_CodeT             Type;     | ||||
| 			bool                   Readonly; | ||||
| 			genc_AST*              Parent;   | ||||
| 			genc_string            Name;     | ||||
| 			genc_string            Comment;  | ||||
| 			union {                     | ||||
| 				array(genc_AST*)   Entries; | ||||
| 				genc_string        Content; | ||||
| 			}; | ||||
| 		}; | ||||
| 		typedef struct genc_AST genc_AST; | ||||
| 		typedef genc_AST* Code; | ||||
| 	)); | ||||
|  | ||||
| 	code->add( proc_code( | ||||
| 		bool genc_ast_add( genc_Code other ); | ||||
| 	)); | ||||
|  | ||||
| 	code->add( proc_code(  | ||||
| 		genc_forceinline | ||||
| 		void genc_ast_add_entry( genc_Code self,  genc_Code other ) | ||||
| 		{ | ||||
| 			genc_array_append( self->Entries, other ); | ||||
|  | ||||
| 			other->Parent = self; | ||||
| 		} | ||||
| 	)); | ||||
|  | ||||
| 	code->add( untyped_str( | ||||
| 		R"(#define genc_code_body( AST_ ) AST->Entries[0])", 47 | ||||
| 	)); | ||||
|  | ||||
| 	code->add( proc_code(  | ||||
| 		genc_forceinline | ||||
| 		bool genc_code_has_entries( Code self ) const | ||||
| 		{ | ||||
| 			genc_local_persist  | ||||
| 			bool lookup[ genc_ECode::Num_Types] = { | ||||
| 				false, // Invalid | ||||
| 				false, // Untyped | ||||
| 				true,  // Global_Body | ||||
| 				true,  // Parameters | ||||
| 				true,  // Proc | ||||
| 				true,  // Proc_Body | ||||
| 				true,  // Proc_Foward | ||||
| 				false, // Specifies | ||||
| 				true,  // Struct | ||||
| 				true,  // Struct_Body | ||||
| 				true,  // Variable | ||||
| 				true,  // Typedef | ||||
| 				true,  // Typename | ||||
| 			}; | ||||
|  | ||||
| 			return lookup[self->Type]; | ||||
| 		} | ||||
| 	)); | ||||
|  | ||||
| 	code->check(); | ||||
|  | ||||
| 	return code; | ||||
| } | ||||
|  | ||||
| Code make_static_Data() | ||||
| { | ||||
| 	Code  | ||||
| 	data = make_global_body(); | ||||
| 	data->add( IfDef_GENC_IMPLEMENTATION ); | ||||
| 	data->add( global_code( | ||||
| 		static genc_array(genc_AST) genc_CodePool = nullptr; | ||||
|  | ||||
| 		static genc_array(genc_arena) genc_StringArenas =  nullptr; | ||||
|  | ||||
| 		static genc_StringTable    genc_StringMap; | ||||
| 		static genc_TypeTable      genc_TypeMap; | ||||
|  | ||||
| 		static sw genc_InitSize_CodePool       = genc_megabytes(64); | ||||
| 		static sw genc_InitSize_StringArena    = genc_megabytes(32); | ||||
| 		static sw genc_InitSize_StringTable    = genc_megabytes(4); | ||||
| 		static sw genc_InitSize_TypeTable      = genc_megabytes(4); | ||||
|  | ||||
| 		static allocator genc_Allocator_CodePool    = zpl_heap(); | ||||
| 		static allocator genc_Allocator_StringArena = zpl_heap(); | ||||
| 		static allocator genc_Allocator_StringTable = zpl_heap(); | ||||
| 		static allocator genc_Allocator_TypeTable   = zpl_heap(); | ||||
| 	)); | ||||
| 	data->add( untyped_str( R"(#ifdef GENC_DEFINE_LIBRARY_CODE_CONSTANTS)")); | ||||
| 	data->add( global_code( | ||||
| 		Code t_void; | ||||
|  | ||||
| 		Code t_bool; | ||||
| 		Code t_char; | ||||
| 		Code t_char_wide; | ||||
|  | ||||
| 		Code t_s8; | ||||
| 		Code t_s16; | ||||
| 		Code t_s32; | ||||
| 		Code t_s64; | ||||
|  | ||||
| 		Code t_u8; | ||||
| 		Code t_u16; | ||||
| 		Code t_u32; | ||||
| 		Code t_u64; | ||||
|  | ||||
| 		Code t_sw; | ||||
| 		Code t_uw; | ||||
|  | ||||
| 		Code t_f32; | ||||
| 		Code t_f64; | ||||
| 	)); | ||||
| 	data->add( untyped_str( R"(#endif)")); | ||||
| 	data->add( global_code( | ||||
| 		Code spec_inline; | ||||
| 		Code spec_const; | ||||
| 	)); | ||||
| 	data->add( EndIf_GENC_IMPLEMENTATION ); | ||||
|  | ||||
| 	return data; | ||||
| } | ||||
|  | ||||
| Code make_make_code() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| Code make_init() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| Code make_mem_config_interface() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| Code make_internal_funcs() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| Code make_upfront() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| Code make_incremental() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| Code make_parsing() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| Code make_untyped() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| Code make_interface() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| int gen_main() | ||||
| { | ||||
| 	Memory::setup(); | ||||
| 	gen::init(); | ||||
| 	 | ||||
| 	IfDef_GENC_IMPLEMENTATION = untyped( | ||||
| 		R"(#ifdef GENC_IMPLEMENTATION)" | ||||
| 	); | ||||
|  | ||||
| 	EndIf_GENC_IMPLEMENTATION = untyped( | ||||
| 		R"(#endif // GENC_IMPLEMENTATION)" | ||||
| 	); | ||||
|  | ||||
| 	Code header_comment = untyped_str( Header_Comment, sizeof( Header_Comment ) ); | ||||
| 	Code log_failure    = make_log_failure(); | ||||
|  | ||||
| 	Code ecode          = make_ECode(); | ||||
| 	Code eoperator      = make_EOperator(); | ||||
| 	Code especifier     = make_ESpecifier(); | ||||
| 	Code code           = make_Code(); | ||||
| 	 | ||||
| 	Builder | ||||
| 	builder; | ||||
| 	builder.open( "genc.h" ); | ||||
|  | ||||
| 	builder.print( header_comment ); | ||||
| 	builder.print( log_failure ); | ||||
| 	builder.print( ecode ); | ||||
| 	builder.print( eoperator ); | ||||
| 	builder.print( especifier ); | ||||
| 	builder.print( code ); | ||||
|  | ||||
| 	builder.write(); | ||||
|  | ||||
| 	Memory::cleanup(); | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										55
									
								
								project/gen.singleheader.c99.data
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								project/gen.singleheader.c99.data
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| # HEADER COMMENT | ||||
| 1, 166 | ||||
|  | ||||
| # CODE TYPES | ||||
| Invalid | ||||
| Untyped         | ||||
| Enum            | ||||
| Enum_Body | ||||
| Global_Body | ||||
| Parameters | ||||
| Proc       | ||||
| Proc_Body | ||||
| Proc_Forward | ||||
| Specifiers     | ||||
| Struct       | ||||
| Struct_Body | ||||
| Variable      | ||||
| Typedef         | ||||
| Typename | ||||
| Using     | ||||
|  | ||||
| # CODE_HAS_ENTRIES | ||||
|  | ||||
| # SPECIFIER_TYPES | ||||
| Attribute | ||||
| Alignas           | ||||
| Constexpr | ||||
| Const           | ||||
| Inline | ||||
| Pointer | ||||
| API_Import         | ||||
| API_Export         | ||||
| External_Linkage | ||||
| Internal_Linkage   | ||||
| Local_Persist | ||||
| Thread_Local       | ||||
| Invalid | ||||
|  | ||||
| # SPECIFIER_STRINGS | ||||
| "alignas", | ||||
| "const", | ||||
| "inline", | ||||
| "*", | ||||
| #if defined(ZPL_SYSTEM_WINDOWS) | ||||
| "__declspec(dllexport)", | ||||
| "__declspec(dllimport)", | ||||
| #elif defined(ZPL_SYSTEM_MACOS) | ||||
| "__attribute__ ((visibility (\"default\")))", | ||||
| "__attribute__ ((visibility (\"default\")))", | ||||
| #endif | ||||
| "extern", | ||||
| "static", | ||||
| "static", | ||||
| "thread_local" | ||||
|  | ||||
							
								
								
									
										34
									
								
								project/gen.singleheader.c99.refactor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								project/gen.singleheader.c99.refactor
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| __VERSION 1 | ||||
|  | ||||
| word AST,  genc_AST | ||||
| word Code, genc_Code | ||||
|  | ||||
| word ECode,      genc_ECode | ||||
| word EOperator,  genc_EOperator | ||||
| word ESpecifier, genc_ESpecifier | ||||
| word CodeT,      genc_CodeT | ||||
|  | ||||
| word string, genc_string | ||||
| word init,   genc_init | ||||
|  | ||||
| namespace def_,           genc_def_ | ||||
| namespace make_,          genc_make_ | ||||
| namespace parse_,         genc_parse_ | ||||
| namespace untyped_,       genc_untyped_ | ||||
| namespace set_init_,      genc_set_init_ | ||||
| namespace set_allocator_, genc_set_allocator_ | ||||
|  | ||||
| word clean_code_pool, genc_clean_code_pool | ||||
|  | ||||
| word Builder, genc_Builder | ||||
|  | ||||
| word CodePool,     genc_CodePool | ||||
| word StringArenas, genc_StringArenas | ||||
| word CodePOD,      genc_AST | ||||
| word StringMap,    genc_StringMap | ||||
| word TypeMap,      genc_TypeMap | ||||
|  | ||||
| namespace InitSize_,  genc_InitSize_ | ||||
| namespace Allocator_, genc_Allocator_ | ||||
|  | ||||
| namespace spec_, genc_spec | ||||
							
								
								
									
										0
									
								
								project/gen.singleheader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								project/gen.singleheader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										4
									
								
								singleheader/genc.refactor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								singleheader/genc.refactor
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| // Removes the genc_ namespace if desired | ||||
|  | ||||
| namespace genc_ | ||||
|  | ||||
| @@ -16,7 +16,7 @@ | ||||
| 	#ifndef GEN_DEFINE_DSL | ||||
| 		using namespace gen; | ||||
|  | ||||
| 		Code t_allocator = def_type( txt(allocator) ); | ||||
| 		Code t_allocator = def_type( txt(allocator)  ); | ||||
|  | ||||
| 		Code header; | ||||
| 		{ | ||||
| @@ -64,7 +64,6 @@ | ||||
| 		return ArrayBase; | ||||
| 	} | ||||
|  | ||||
| 	#define gen_array( Type_ ) gen__array( #Type_, sizeof(Type_), a_base ) | ||||
| 	Code gen__array( char const* type_str, s32 type_size, Code parent ) | ||||
| 	{ | ||||
| 	#ifndef GEN_DEFINE_DSL | ||||
| @@ -155,6 +154,7 @@ | ||||
| 			Code append = make_proc( "append" ); | ||||
| 			{ | ||||
| 				append->add( def_params( 1, type, "value") ); | ||||
| 				append->add( t_bool ); | ||||
|  | ||||
| 				Code  | ||||
| 				body = append.body(); | ||||
| @@ -172,6 +172,8 @@ | ||||
| 					 | ||||
| 					return true; | ||||
| 				))); | ||||
|  | ||||
| 				append->check(); | ||||
| 			} | ||||
|  | ||||
| 			Code back; | ||||
| @@ -295,7 +297,7 @@ | ||||
| 			} | ||||
|  | ||||
| 			Code set_capacity = parse_proc( txt_with_length( | ||||
| 				bool set_capacity( new_capacity ) | ||||
| 				bool set_capacity( sw new_capacity ) | ||||
| 				{ | ||||
| 					Header& header = get_header(); | ||||
|  | ||||
| @@ -305,7 +307,7 @@ | ||||
| 					if ( capacity < header.Num ) | ||||
| 						header.Num = capacity; | ||||
|  | ||||
| 					uw      size       = sizeof(Header) + sizeof(Type) * capacity; | ||||
| 					sw      size       = sizeof(Header) + sizeof(Type) * capacity; | ||||
| 					Header* new_header = rcast( Header* alloc( header.Allocator, size )); | ||||
|  | ||||
| 					if ( new_header == nullptr ) | ||||
| @@ -591,18 +593,58 @@ | ||||
| 		return array_def; | ||||
| 	} | ||||
|  | ||||
| 	struct ArrayRequest | ||||
| 	{ | ||||
| 		char const* Name; | ||||
| 		sw          Size; | ||||
| 	}; | ||||
|  | ||||
| 	array(ArrayRequest) UserArrayGenQueue; | ||||
|  | ||||
| 	#define gen_array( Type_ ) add_gen_array_request( #Type_, sizeof(Type_) ) | ||||
|  | ||||
| 	void add_gen_array_request( const char* type_str, sw type_size ) | ||||
| 	{ | ||||
| 		ArrayRequest request = { type_str, type_size }; | ||||
|  | ||||
| 		array_append( UserArrayGenQueue, request ); | ||||
| 	} | ||||
|  | ||||
| 	u32 gen_array_file() | ||||
| 	{ | ||||
| 		Code a_base = gen__array_base(); | ||||
|  | ||||
| 		Code a_u32  = gen_array( u32 ); | ||||
| 		Code a_cstr = gen_array( char const* ); | ||||
| 		add_gen_array_request( "u32", sizeof(u32) ); | ||||
| 		gen_array( char const* ); | ||||
|  | ||||
| 		array(Code) array_asts; | ||||
| 		array_init( array_asts, g_allocator ); | ||||
|  | ||||
| 		sw left  = array_count( UserArrayGenQueue ); | ||||
| 		sw index = 0; | ||||
| 		while( left -- ) | ||||
| 		{ | ||||
| 			ArrayRequest request = UserArrayGenQueue[index]; | ||||
|  | ||||
| 			Code result = gen__array( request.Name, request.Size, a_base ); | ||||
|  | ||||
| 			array_append( array_asts, result ); | ||||
| 		} | ||||
|  | ||||
| 		Builder | ||||
| 		arraygen; | ||||
| 		arraygen.open( "Array.gen.hpp" ); | ||||
| 		arraygen.print( a_u32 ); | ||||
| 		arraygen.print( a_cstr ); | ||||
|  | ||||
| 		left  = array_count( array_asts ); | ||||
| 		index = 0; | ||||
|  | ||||
| 		while( left-- ) | ||||
| 		{ | ||||
| 			Code code = array_asts[index]; | ||||
|  | ||||
| 			arraygen.print( code ); | ||||
| 		} | ||||
|  | ||||
| 		arraygen.write(); | ||||
| 		return 0; | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										22
									
								
								test/c99/meson.build
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								test/c99/meson.build
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| project( 'test', 'c', default_options : ['buildtype=debug'] ) | ||||
|  | ||||
| # add_global_arguments('-E', language : 'cpp') | ||||
|  | ||||
| includes = include_directories(  | ||||
|   [  | ||||
|     '../gen', | ||||
|     '../../singleheader'  | ||||
|   ]) | ||||
|  | ||||
| # get_sources = files('./get_sources.ps1') | ||||
| # sources     = files(run_command('powershell', get_sources, check: true).stdout().strip().split('\n')) | ||||
|  | ||||
| sources = [ 'test.c99.c' ] | ||||
|  | ||||
| if get_option('buildtype').startswith('debug') | ||||
|  | ||||
|   add_project_arguments('-DBuild_Debug', language : ['c' ]) | ||||
|  | ||||
| endif | ||||
|  | ||||
| executable( 'test_c99', sources, include_directories : includes ) | ||||
							
								
								
									
										79
									
								
								test/c99/table.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								test/c99/table.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| #include "gen.h" | ||||
|  | ||||
| #define Table( Type_ ) Table_##Type_ | ||||
|  | ||||
| typedef u64(*)(void*) HashingFn; | ||||
|  | ||||
| #if gen_time | ||||
| #	define gen_table( Type_, HashingFn_ ) gen_request_table( #Type_, sizeof(Type_), HashingFn_ )  | ||||
|  | ||||
| 	u64 table_default_hash_fn( void* address ) | ||||
| 	{ | ||||
| 		return crc32( address, 4 ); | ||||
| 	} | ||||
|  | ||||
| 	Code gen_table_code( char const* type_str, sw type_size, HashingFn hash_fn ) | ||||
| 	{ | ||||
| 		Code table; | ||||
|  | ||||
| 		return table; | ||||
| 	} | ||||
|  | ||||
| 	struct TableRequest | ||||
| 	{ | ||||
| 		char const* Type; | ||||
| 		sw          Size; | ||||
| 		HashingFn   HashFn; | ||||
| 	}; | ||||
|  | ||||
| 	array(TableRequest) TableRequests; | ||||
|  | ||||
| 	void gen_request_table( const char* type_str, sw type_size, HashingFn hash_fn ) | ||||
| 	{ | ||||
| 		TableRequest request = { type_str, type_size, hash_fn }; | ||||
|  | ||||
| 		array_append( TableRequests, request ); | ||||
| 	} | ||||
|  | ||||
| 	u32 gen_table_file() | ||||
| 	{ | ||||
| 		gen_table( u32 ); | ||||
| 		gen_table( char const* ); | ||||
|  | ||||
| 		array(Code) array_asts; | ||||
| 		array_init( array_asts, g_allocator ); | ||||
|  | ||||
| 		sw left  = array_count( TableRequests ); | ||||
| 		sw index = 0; | ||||
| 		while( left -- ) | ||||
| 		{ | ||||
| 			ArrayRequest request = TableRequests[index]; | ||||
|  | ||||
| 			Code result = gen_table_code( request.Name, request.Size, request.HashFn ); | ||||
|  | ||||
| 			array_append( array_asts, result ); | ||||
| 		} | ||||
|  | ||||
| 		Builder | ||||
| 		arraygen; | ||||
| 		arraygen.open( "table.gen.h" ); | ||||
|  | ||||
| 		left  = array_count( array_asts ); | ||||
| 		index = 0; | ||||
|  | ||||
| 		while( left-- ) | ||||
| 		{ | ||||
| 			Code code = array_asts[index]; | ||||
|  | ||||
| 			arraygen.print( code ); | ||||
| 		} | ||||
|  | ||||
| 		arraygen.write(); | ||||
| 		return 0; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| #ifndef gen_time | ||||
| #	include "table.gen.h" | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										40
									
								
								test/c99/test.c99.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								test/c99/test.c99.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| #define GENC_IMPLEMENTATION | ||||
| #include "genc.h" | ||||
| #include "table.h" | ||||
|  | ||||
|  | ||||
| struct Test | ||||
| { | ||||
| 	u64 A; | ||||
| 	u64 B; | ||||
| }; | ||||
|  | ||||
|  | ||||
|  | ||||
| #if gen_time | ||||
|  | ||||
|  | ||||
| u64 hash_struct( void* test ) | ||||
| { | ||||
| 	return crc32( ((Test)test).A, sizeof(u64) ); | ||||
| } | ||||
|  | ||||
|  | ||||
| int gen_main() | ||||
| { | ||||
| 	gen_table( Test, & hash_struct ) | ||||
|  | ||||
| 	gen_table_file(); | ||||
| }	 | ||||
| #endif | ||||
|  | ||||
|  | ||||
|  | ||||
| #if runtime | ||||
| int main() | ||||
| { | ||||
| 	Table(Test) test_table; | ||||
|  | ||||
| 	 | ||||
| } | ||||
| #endif | ||||
| @@ -25,7 +25,7 @@ | ||||
| 	#ifndef GEN_DEFINE_DSL | ||||
| 		string name = string_sprintf( g_allocator, (char*)sprintf_buf, ZPL_PRINTF_MAXLEN, "square", type ); | ||||
|  | ||||
| 		#if 1 | ||||
| 		#if 0 | ||||
| 		Code square; | ||||
| 		{ | ||||
| 			Code params     = def_params( 1, integral_type, "value" ); | ||||
| @@ -43,9 +43,9 @@ | ||||
| 				return value * value; | ||||
| 			} | ||||
| 		); | ||||
| 		char const* gen_code = token_fmt( tmpl, 1, type ); | ||||
| 		char const* gen_code = token_fmt( tmpl, 1, "type", type ); | ||||
|  | ||||
| 		Code square = parse_proc(gen_code); | ||||
| 		Code square = parse_proc(gen_code, strlen(gen_code)); | ||||
| 		#endif | ||||
|  | ||||
| 	#else  | ||||
|   | ||||
							
								
								
									
										0
									
								
								test/test.singleheader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								test/test.singleheader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										2
									
								
								thirdparty/zpl.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								thirdparty/zpl.h
									
									
									
									
										vendored
									
									
								
							| @@ -5095,8 +5095,8 @@ License: | ||||
|           | ||||
|          typedef struct string_header { | ||||
|              allocator allocator; | ||||
|              sw length; | ||||
|              sw capacity; | ||||
|              sw length; | ||||
|          } string_header; | ||||
|           | ||||
|          #define ZPL_STRING_HEADER(str) (zpl_cast(ZPL_NS string_header *)(str) - 1) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user