mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-10-30 22:40:54 -07:00 
			
		
		
		
	Major changes to library design, change test to reflect it.
This commit is contained in:
		| @@ -4,6 +4,28 @@ | ||||
|  | ||||
| #pragma once	 | ||||
|  | ||||
| #if defined(__GNUC__) || defined(__clang__) || 1 | ||||
|   // Supports 0-10 arguments | ||||
|   #define VA_NARGS_IMPL( _0,                          \ | ||||
| 	 _1,  _2,  _3,  _4,  _5,  _6,  _7,  _8,  _9, _10, \ | ||||
| 	_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ | ||||
| 	_21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ | ||||
| 	  N, ...) N  | ||||
|   // ## deletes preceding comma if _VA_ARGS__ is empty (GCC, Clang) | ||||
|   #define VA_NARGS(...) VA_NARGS_IMPL(_, ## __VA_ARGS__, \ | ||||
|   	30, 29, 28, 27, 26, 25, 24, 23, 22, 21,              \ | ||||
| 	20, 19, 18, 17, 16, 15, 14, 13, 12, 11,              \ | ||||
| 	10, 9, 8, 7, 6, 5, 4, 3, 2, 1,                       \ | ||||
| 	0)     | ||||
| 	                 | ||||
| #else | ||||
|   // Supports 1-10 arguments | ||||
|   #define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N | ||||
|   #define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) | ||||
| #endif | ||||
|  | ||||
| #define VA_NARGS2(...) ((int)(sizeof((int[]){ __VA_ARGS__ })/sizeof(int))) | ||||
|  | ||||
| #ifdef BLOAT_IMPL | ||||
| #	define ZPL_IMPLEMENTATION | ||||
| #endif | ||||
| @@ -21,7 +43,7 @@ | ||||
| #		define ZPL_MODULE_ESSENTIALS | ||||
| #		define ZPL_MODULE_CORE | ||||
| #		define ZPL_MODULE_TIMER | ||||
| // #	define ZPL_MODULE_HASHING | ||||
| #		define ZPL_MODULE_HASHING | ||||
| // #	define ZPL_MODULE_REGEX | ||||
| // #	define ZPL_MODULE_EVENT | ||||
| // #	define ZPL_MODULE_DLL | ||||
|   | ||||
							
								
								
									
										575
									
								
								project/gen.cpp
									
									
									
									
									
								
							
							
						
						
									
										575
									
								
								project/gen.cpp
									
									
									
									
									
								
							| @@ -5,26 +5,48 @@ | ||||
| #ifdef gen_time | ||||
| namespace gen | ||||
| { | ||||
| 	void init() | ||||
| 	namespace StaticData | ||||
| 	{ | ||||
|  | ||||
| 		static array(CodePOD) CodePool = nullptr; | ||||
| 	} | ||||
|  | ||||
| 	ct Code make() | ||||
| 	/* | ||||
| 		Used internally to retireve a Code object form the CodePool. | ||||
| 	*/ | ||||
| 	Code make() | ||||
| 	{ | ||||
| 		return { Code::Invalid, nullptr, nullptr, { nullptr } }; | ||||
| 		using namespace StaticData; | ||||
|  | ||||
| 		array_append( CodePool, InvalidCode ); | ||||
|  | ||||
| 		return * (Code*) & array_back( CodePool ); | ||||
| 	} | ||||
|  | ||||
|  | ||||
|  | ||||
| 	void init() | ||||
| 	{ | ||||
| 		array_init( StaticData::CodePool, g_allocator ); | ||||
| 	} | ||||
|  | ||||
| 	Code decl_type( char const* name, Code type, Code specifiers ) | ||||
| 	{ | ||||
| 		Code  | ||||
| 		result      = make(); | ||||
| 		result.Type = Code::Decl_Type; | ||||
| 		result.Name = string_make( g_allocator, name ); | ||||
| 		using namespace ECode; | ||||
|  | ||||
| 		array_init( result.Entries, g_allocator ); | ||||
| 		result.add( specifiers ); | ||||
| 		result.add( type ); | ||||
| 		if ( type->Type != Specifiers ) | ||||
| 			fatal( "gen::decl_type: type is not a Typename"); | ||||
|  | ||||
| 		if ( type->Type != Typename ) | ||||
| 			fatal( "gen::decl_type: specifiers is not a 'Specfiers' type"); | ||||
|  | ||||
| 		Code  | ||||
| 		result       = make(); | ||||
| 		result->Type = Decl_Type; | ||||
| 		result->Name = string_make( g_allocator, name ); | ||||
|  | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
| 		result->add( specifiers ); | ||||
| 		result->add( type ); | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
| @@ -35,57 +57,77 @@ namespace gen | ||||
| 		, Code ret_type | ||||
| 	) | ||||
| 	{ | ||||
| 		Code  | ||||
| 		result      = make(); | ||||
| 		result.Type = Code::Decl_Function; | ||||
| 		result.Name = string_make( g_allocator, name ); | ||||
| 		using namespace ECode; | ||||
|  | ||||
| 		if ( specifiers->Type != Specifiers ) | ||||
| 			fatal( "gen::decl_fn: specifiers was not a `Specifiers` type" ); | ||||
|  | ||||
| 		if ( params->Type != Parameters ) | ||||
| 			fatal( "gen::decl_fn: params was not a `Parameters` type" ); | ||||
|  | ||||
| 		if ( ret_type->Type != Typename ) | ||||
| 			fatal( "gen::decl_fn: ret_type was not a Typename" ); | ||||
|  | ||||
| 		Code | ||||
| 		result       = make(); | ||||
| 		result->Type = Decl_Function; | ||||
| 		result->Name = string_make( g_allocator, name ); | ||||
| 		 | ||||
| 		array_init( result.Entries, g_allocator ); | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
|  | ||||
| 		if ( specifiers ) | ||||
| 			result.add( specifiers ); | ||||
| 			result->add( specifiers ); | ||||
|  | ||||
| 		result.add( ret_type ); | ||||
| 		result->add( ret_type ); | ||||
|  | ||||
| 		if ( params ) | ||||
| 			result.add( params ); | ||||
| 			result->add( params ); | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code def_parameters( s32 num, ... ) | ||||
| 	{ | ||||
| 		if (num <= 0) | ||||
| 			fatal("TT::make_paramters: num is %d", num); | ||||
| 		using namespace ECode; | ||||
|  | ||||
| 		Code  | ||||
| 		result      = make(); | ||||
| 		result.Type = Code::Parameters; | ||||
| 		if (num <= 0) | ||||
| 			fatal( "TT::make_paramters: num cannot be zero or neg" ); | ||||
|  | ||||
| 		Code | ||||
| 		result       = make(); | ||||
| 		result->Type = Parameters; | ||||
|  | ||||
| 		va_list va; | ||||
| 		va_start(va, num); | ||||
|  | ||||
| 		result.Name = string_make( g_allocator, va_arg(va, char const*) ); | ||||
| 		result->Name = string_make( g_allocator, va_arg(va, char const*) ); | ||||
|  | ||||
| 		array_init( result.Entries, g_allocator ); | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
|  | ||||
| 		Code type = va_arg(va, Code); | ||||
| 		result.add( type ); | ||||
|  | ||||
| 		if ( type->Type != Typename ) | ||||
| 			fatal( "gen::def_parameters: type of param %d is not a Typename", num - num + 1 ); | ||||
|  | ||||
| 		result->add( type ); | ||||
|  | ||||
| 		while( num -= 2, num && num % 2 == 0 ) | ||||
| 		{ | ||||
| 			Code | ||||
| 			param      = make(); | ||||
| 			param.Name = string_make( g_allocator, va_arg(va, char const*) ); | ||||
|  | ||||
| 			array_init( param.Entries, g_allocator ); | ||||
|  | ||||
| 			type = va_arg(va, Code); | ||||
| 			param.add( type ); | ||||
|  | ||||
| 			result.add(param); | ||||
| 			Code | ||||
| 			param       = make(); | ||||
| 			param->Type = Parameters; | ||||
| 			param->Name = string_make( g_allocator, va_arg(va, char const*) ); | ||||
|  | ||||
| 			array_init( param->Entries, g_allocator ); | ||||
|  | ||||
| 			if ( type->Type != Typename ) | ||||
| 				fatal( "gen::def_parameters: type of param %d is not a Typename", num - num + 1 ); | ||||
|  | ||||
| 			param->add( type ); | ||||
| 			result->add(param); | ||||
| 		} | ||||
| 		 | ||||
| 		va_end(va); | ||||
|  | ||||
| 		return result; | ||||
| @@ -98,50 +140,155 @@ namespace gen | ||||
| 		, Code body  | ||||
| 	) | ||||
| 	{ | ||||
| 		using namespace ECode; | ||||
|  | ||||
| 		if ( specifiers && specifiers->Type != Specifiers ) | ||||
| 			fatal( "gen::def_function: specifiers was not a `Specifiers` type" ); | ||||
|  | ||||
| 		if ( params && params->Type != Parameters ) | ||||
| 			fatal( "gen::def_function: params was not a `Parameters` type" ); | ||||
|  | ||||
| 		if ( ret_type == nullptr || ret_type->Type != Typename ) | ||||
| 			fatal( "gen::def_function: ret_type was not a Typename" ); | ||||
|  | ||||
| 		switch ( body->Type ) | ||||
| 		{ | ||||
| 			case Function_Body: | ||||
| 			case Untyped: | ||||
| 				break; | ||||
|  | ||||
| 			default: | ||||
| 				fatal("gen::def_function: body must be either of Function_Body or Untyped type."); | ||||
| 		} | ||||
|  | ||||
| 		Code  | ||||
| 		result      = make(); | ||||
| 		result.Name = string_make( g_allocator, name ); | ||||
| 		result.Type = Code::Function; | ||||
| 		result       = make(); | ||||
| 		result->Name = string_make( g_allocator, name ); | ||||
| 		result->Type = Function; | ||||
| 		 | ||||
| 		array_init( result.Entries, g_allocator ); | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
|  | ||||
| 		if ( specifiers ) | ||||
| 			result.add( specifiers ); | ||||
| 			result->add( specifiers ); | ||||
|  | ||||
| 		result.add( ret_type ); | ||||
| 		result->add( ret_type ); | ||||
|  | ||||
| 		if ( params ) | ||||
| 			result.add( params ); | ||||
| 			result->add( params ); | ||||
|  | ||||
| 		result.add( body ); | ||||
| 		result->add( body ); | ||||
|  | ||||
| 		body->Parent = result; | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code def_function_body( u32 num, ... ) | ||||
| 	Code def_function_body( s32 num, ... ) | ||||
| 	{ | ||||
| 		using namespace ECode; | ||||
|  | ||||
| 		if ( num <= 0 ) | ||||
| 			fatal("gen::def_function_body: num cannot zero or neg"); | ||||
|  | ||||
| 		Code result = make(); | ||||
|  | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
|  | ||||
| 		va_list va; | ||||
| 		va_start(va, num); | ||||
| 		do | ||||
| 		{ | ||||
| 			Code entry = va_arg(va, Code); | ||||
|  | ||||
| 			switch ( entry->Type ) | ||||
| 			{ | ||||
| 				case Decl_Function: | ||||
| 				case Decl_Type: | ||||
| 				case Namespace: | ||||
| 				case Namespace_Body: | ||||
| 				case Parameters: | ||||
| 				case Specifiers: | ||||
| 				case Struct_Body: | ||||
| 				case Typename: | ||||
| 					fatal("gen::def_function_body: Entry type is not allowed: %s", entry->type_str() ); | ||||
|  | ||||
| 				default: | ||||
| 					break; | ||||
| 			} | ||||
|  | ||||
| 			result->add( entry ); | ||||
| 		}  | ||||
| 		while ( num--, num > 0 ); | ||||
| 		va_end(va); | ||||
| 		 | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code def_namespace( char const* name, Code body ) | ||||
| 	{ | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	Code def_namespace_body( u32 num, ... ) | ||||
| 	{ | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	Code def_specifiers( u32 num, ... ) | ||||
| 	{ | ||||
| 		if ( num <= 0 ) | ||||
| 			fatal("gen::make_specifier: num cannot be zero."); | ||||
| 		using namespace ECode; | ||||
|  | ||||
| 		Code  | ||||
| 		result         = make(); | ||||
| 		result.Type    = Code::Specifiers; | ||||
| 		result.Content = string_make( g_allocator, "" ); | ||||
| 		result       = make(); | ||||
| 		result->Type = Namespace; | ||||
|  | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
|  | ||||
| 		if ( body->Type != Namespace_Body || body->Type != Untyped ) | ||||
| 			fatal("gen::def_namespace: body is not of namespace or untyped type"); | ||||
|  | ||||
| 		result->add( body ); | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code def_namespace_body( s32 num, ... ) | ||||
| 	{ | ||||
| 		using namespace ECode; | ||||
|  | ||||
| 		if ( num <= 0 ) | ||||
| 			fatal("gen::make_specifier: num cannot be zero or less"); | ||||
|  | ||||
| 		Code | ||||
| 		result = make(); | ||||
| 		result->Type = Namespace_Body; | ||||
|  | ||||
| 		va_list va; | ||||
| 		va_start(va, num); | ||||
| 		do | ||||
| 		{ | ||||
| 			Code entry = va_arg(va, Code); | ||||
| 			 | ||||
| 			switch ( entry->Type ) | ||||
| 			{ | ||||
| 				case Namespace_Body: | ||||
| 				case Parameters: | ||||
| 				case Specifiers: | ||||
| 				case Struct_Body: | ||||
| 				case Typename: | ||||
| 					fatal("gen::def_function_body: Entry type is not allowed: %s", ECode::str(entry->Type) ); | ||||
|  | ||||
| 				default: | ||||
| 					break; | ||||
| 			} | ||||
|  | ||||
| 			result->add( entry ); | ||||
| 		}  | ||||
| 		while ( num--, num > 0 ); | ||||
| 		va_end(va); | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code def_specifiers( s32 num, ... ) | ||||
| 	{ | ||||
| 		if ( num <= 0 ) | ||||
| 			fatal("gen::make_specifier: num cannot be zero or less"); | ||||
|  | ||||
| 		Code  | ||||
| 		result          = make(); | ||||
| 		result->Type    = ECode::Specifiers; | ||||
| 		result->Content = string_make( g_allocator, "" ); | ||||
|  | ||||
| 		va_list va; | ||||
| 		va_start(va, num); | ||||
| @@ -152,13 +299,13 @@ namespace gen | ||||
| 			switch ( type ) | ||||
| 			{ | ||||
| 				case Alignas: | ||||
| 					result.Content = string_append_fmt( result.Content, "%s(%d)", specifier_str(type), va_arg(va, u32) ); | ||||
| 					result->Content = string_append_fmt( result->Content, "%s(%d)", specifier_str(type), va_arg(va, u32) ); | ||||
| 				break; | ||||
|  | ||||
| 				default: | ||||
| 					const char* str = specifier_str(type); | ||||
|  | ||||
| 					result.Content = string_append_fmt( result.Content, "%s", str ); | ||||
| 					result->Content = string_append_fmt( result->Content, "%s", str ); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| @@ -170,29 +317,125 @@ namespace gen | ||||
|  | ||||
| 	Code def_struct( char const* name, Code body, Code parent, Code specifiers ) | ||||
| 	{ | ||||
| 		using namespace ECode; | ||||
|  | ||||
| 		if ( specifiers && specifiers->Type != Specifiers ) | ||||
| 			fatal( "gen::def_struct: specifiers was not a `Specifiers` type" ); | ||||
|  | ||||
| 		if ( parent && parent->Type != Struct ) | ||||
| 			fatal( "gen::def_struct: parent was not a `Struct` type" ); | ||||
|  | ||||
| 		if ( body && body->Type != Struct_Body ) | ||||
| 			fatal( "gen::def_struct: body was not a Struct_Body type" ); | ||||
|  | ||||
| 		Code | ||||
| 		result      = make(); | ||||
| 		result->Type = Struct; | ||||
| 		result->Name = string_make( g_allocator, name ); | ||||
|  | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
|  | ||||
| 		if ( body ) | ||||
| 			result->add( body ); | ||||
|  | ||||
| 		if ( parent ) | ||||
| 			result->add( parent ); | ||||
|  | ||||
| 		if ( specifiers ) | ||||
| 			result->add( specifiers ); | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code def_struct_body( u32 num, ... ) | ||||
| 	Code def_struct_body( s32 num, ... ) | ||||
| 	{ | ||||
| 		using namespace ECode; | ||||
|  | ||||
| 		if ( num == 0 ) | ||||
| 			fatal("gen::def_struct_body: num cannot be zero"); | ||||
|  | ||||
| 		Code result = make(); | ||||
|  | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
|  | ||||
| 		va_list va; | ||||
| 		va_start(va, num); | ||||
| 		do | ||||
| 		{ | ||||
| 			Code entry = va_arg(va, Code); | ||||
|  | ||||
| 			switch ( entry->Type ) | ||||
| 			{ | ||||
| 				case Namespace: | ||||
| 				case Namespace_Body: | ||||
| 				case Parameters: | ||||
| 				case Specifiers: | ||||
| 				case Struct_Body: | ||||
| 				case Typename: | ||||
| 					fatal("gen::def_struct_body: Entry type is not allowed: %s", ECode::str(entry->Type) ); | ||||
| 			} | ||||
|  | ||||
| 			result->add( entry ); | ||||
| 		}  | ||||
| 		while ( num--, num > 0 ); | ||||
| 		va_end(va); | ||||
| 		 | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code def_variable( char const* name, Code type, Code value, Code specifiers ) | ||||
| 	{ | ||||
| 		if ( specifiers && specifiers->Type != ECode::Specifiers ) | ||||
| 			fatal( "gen::def_variable: specifiers was not a `Specifiers` type" ); | ||||
|  | ||||
| 		if ( type->Type != ECode::Typename ) | ||||
| 			fatal( "gen::def_variable: type was not a Typename" ); | ||||
|  | ||||
| 		if ( value && value->Type != ECode::Untyped ) | ||||
| 			fatal( "gen::def_variable: value was not a `Untyped` type" ); | ||||
|  | ||||
| 		Code  | ||||
| 		result       = make(); | ||||
| 		result->Name = string_make( g_allocator, name ); | ||||
| 		result->Type = ECode::Variable; | ||||
| 		 | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
|  | ||||
| 		if ( specifiers ) | ||||
| 			result->add( specifiers ); | ||||
|  | ||||
| 		result->add( type ); | ||||
|  | ||||
| 		if ( value ) | ||||
| 			result->add( value ); | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code def_type( char const* name ) | ||||
| 	{ | ||||
| 		Code  | ||||
| 		result      = make(); | ||||
| 		result.Name = string_make( g_allocator, name ); | ||||
| 		result.Type = Code::Typename; | ||||
| 		result       = make(); | ||||
| 		result->Name = string_make( g_allocator, name ); | ||||
| 		result->Type = ECode::Typename; | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code def_using( char const* name, Code type ) | ||||
| 	{ | ||||
| 		Code | ||||
| 		result       = make(); | ||||
| 		result->Name = string_make( g_allocator, name ); | ||||
| 		result->Type = ECode::Using; | ||||
|  | ||||
| 		array_init( result->Entries, g_allocator ); | ||||
|  | ||||
| 		type->Parent = result; | ||||
| 		result->add( type ); | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	Code untyped_fmt(char const* fmt, ...) | ||||
| 	{ | ||||
| @@ -205,22 +448,123 @@ namespace gen | ||||
| 		va_end(va); | ||||
|           | ||||
| 		Code  | ||||
| 		result         = make(); | ||||
| 		result.Name    = string_make( g_allocator, fmt ); | ||||
| 		result.Type    = Code::Untyped; | ||||
| 		result.Content = string_make( g_allocator, buf ); | ||||
| 		result          = make(); | ||||
| 		result->Name    = string_make( g_allocator, fmt ); | ||||
| 		result->Type    = ECode::Untyped; | ||||
| 		result->Content = string_make( g_allocator, buf ); | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	struct TokEntry | ||||
| 	{ | ||||
| 		char const* Str; | ||||
| 		s32         Length; | ||||
| 	}; | ||||
|  | ||||
| 	ZPL_TABLE( static, TokMap, tokmap_, TokEntry ) | ||||
|  | ||||
| 	sw token_fmt_va( char* buf, uw buf_size, char const* fmt, s32 num_tokens, va_list va ) | ||||
| 	{ | ||||
| 		char const* buf_begin = buf; | ||||
| 		sw          remaining = buf_size; | ||||
|  | ||||
| 		TokMap tok_map; | ||||
| 		{ | ||||
| 			tokmap_init( & tok_map, g_allocator ); | ||||
|  | ||||
| 			s32 left = num_tokens; | ||||
|  | ||||
| 			while ( left-- ) | ||||
| 			{ | ||||
| 				char const* token = va_arg( va, char const* ); | ||||
| 				char const* value = va_arg( va, char const* ); | ||||
|  | ||||
| 				TokEntry entry  | ||||
| 				{  | ||||
| 					value, | ||||
| 					zpl_strnlen(value, 128)  | ||||
| 				}; | ||||
|  | ||||
| 				u32 key = crc32( token, zpl_strnlen(token, 32) ); | ||||
|  | ||||
| 				tokmap_set( & tok_map, key, entry ); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		sw   result  = 0; | ||||
| 		char current = *fmt; | ||||
|  | ||||
| 		while ( current ) | ||||
| 		{ | ||||
| 			sw len = 0; | ||||
|  | ||||
| 			while ( current && current != '{' && remaining )  | ||||
| 			{ | ||||
| 				*buf = *fmt; | ||||
| 				buf++; | ||||
| 				fmt++; | ||||
|  | ||||
| 				current = *fmt; | ||||
| 			} | ||||
|  | ||||
| 			if ( current == '{' ) | ||||
| 			{ | ||||
| 				char const* scanner = fmt; | ||||
|  | ||||
| 				s32 tok_len = 0; | ||||
|  | ||||
| 				while ( *scanner != '}' ) | ||||
| 				{ | ||||
| 					tok_len++; | ||||
| 					scanner++; | ||||
| 				} | ||||
|  | ||||
| 				char const* token = fmt; | ||||
|  | ||||
| 				s32      key   = crc32( token, tok_len ); | ||||
| 				TokEntry value = *tokmap_get( & tok_map, key ); | ||||
| 				s32      left  = value.Length; | ||||
|  | ||||
| 				while ( left-- ) | ||||
| 				{ | ||||
| 					*buf = *value.Str; | ||||
| 					buf++; | ||||
| 					value.Str++; | ||||
| 				} | ||||
|  | ||||
| 				scanner++; | ||||
| 				fmt     = scanner;				 | ||||
| 				current = *fmt; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
| 	 | ||||
| 	Code token_fmt( char const* fmt, ... ) | ||||
| 	Code 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(); | ||||
| 		result->Name    = string_make( g_allocator, fmt ); | ||||
| 		result->Type    = ECode::Untyped; | ||||
| 		result->Content = string_make( g_allocator, buf ); | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
|  | ||||
|  | ||||
| 	string Code::to_string() | ||||
| 	string AST::to_string() | ||||
| 	{ | ||||
| 		string result = string_make( g_allocator, "" ); | ||||
|  | ||||
| @@ -229,6 +573,8 @@ namespace gen | ||||
|  | ||||
| 		switch ( Type ) | ||||
| 		{ | ||||
| 			using namespace ECode; | ||||
|  | ||||
| 			case Invalid: | ||||
| 				fatal("Attempted to serialize invalid code! - %s", Name); | ||||
| 			break; | ||||
| @@ -237,13 +583,6 @@ namespace gen | ||||
| 				result = string_append_length( result, Content, string_length(Content) ); | ||||
| 			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 Decl_Function: | ||||
| 			{ | ||||
| 				u32 index = 0; | ||||
| @@ -252,9 +591,9 @@ namespace gen | ||||
| 				if ( left <= 0 ) | ||||
| 					fatal( "Code::to_string - Name: %s Type: %s, expected definition", Name, Type ); | ||||
|  | ||||
| 				if ( Entries[index].Type == Specifiers ) | ||||
| 				if ( Entries[index]->Type == Specifiers ) | ||||
| 				{ | ||||
| 					result = string_append_fmt( result, "%s\n", Entries[index].to_string() ); | ||||
| 					result = string_append_fmt( result, "%s\n", Entries[index]->to_string() ); | ||||
| 					index++; | ||||
| 					left--; | ||||
| 				} | ||||
| @@ -262,13 +601,13 @@ namespace gen | ||||
| 				if ( left <= 0 ) | ||||
| 					fatal( "Code::to_string - Name: %s Type: %s, expected return type", Name, Type ); | ||||
|  | ||||
| 				result = string_append_fmt( result, "\n%s %s(", Entries[index].to_string(), Name ); | ||||
| 				result = string_append_fmt( result, "\n%s %s(", Entries[index]->to_string(), Name ); | ||||
| 				index++; | ||||
| 				left--; | ||||
|  | ||||
| 				if ( left && Entries[index].Type == Parameters ) | ||||
| 				if ( left && Entries[index]->Type == Parameters ) | ||||
| 				{ | ||||
| 					result = string_append_fmt( result, "%s", Entries[index].to_string() ); | ||||
| 					result = string_append_fmt( result, "%s", Entries[index]->to_string() ); | ||||
| 					index++; | ||||
| 					left--; | ||||
| 				} | ||||
| @@ -277,22 +616,11 @@ namespace gen | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 			case Function_Body: | ||||
| 			break; | ||||
| 			case Decl_Type: | ||||
| 				if ( Entries[0]->Type == Specifiers ) | ||||
| 					result = string_append_fmt( result, "%s\n", Entries[0]->to_string()); | ||||
|  | ||||
| 			case Parameters:  | ||||
| 			{ | ||||
| 				result = string_append_fmt( result, "%s %s", Entries[0].to_string(), Name ); | ||||
|  | ||||
| 				s32 index = 1; | ||||
| 				s32 left  = array_count( Entries ) - 1; | ||||
|  | ||||
| 				while ( left--, left > 0 ) | ||||
| 					result = string_append_fmt( result, ", %s %s" | ||||
| 						, Entries[index].Entries[0].to_string() | ||||
| 						, Entries[index].Name  | ||||
| 					); | ||||
| 			} | ||||
| 				result = string_append_fmt( result, "%s %s;\n", Entries[1]->to_string(), Name ); | ||||
| 			break; | ||||
|  | ||||
| 			case Function: | ||||
| @@ -303,9 +631,9 @@ namespace gen | ||||
| 				if ( left <= 0 ) | ||||
| 					fatal( "Code::to_string - Name: %s Type: %s, expected definition", Name, Type ); | ||||
|  | ||||
| 				if ( Entries[index].Type == Specifiers ) | ||||
| 				if ( Entries[index]->Type == Specifiers ) | ||||
| 				{ | ||||
| 					result = string_append_fmt( result, "%s", Entries[index].to_string() ); | ||||
| 					result = string_append_fmt( result, "%s", Entries[index]->to_string() ); | ||||
| 					index++; | ||||
| 					left--; | ||||
| 				} | ||||
| @@ -313,18 +641,45 @@ namespace gen | ||||
| 				if ( left <= 0 ) | ||||
| 					fatal( "Code::to_string - Name: %s Type: %s, expected return type", Name, Type ); | ||||
|  | ||||
| 				result = string_append_fmt( result, "\n%s %s(", Entries[index].to_string(), Name ); | ||||
| 				result = string_append_fmt( result, "\n%s %s(", Entries[index]->to_string(), Name ); | ||||
| 				index++; | ||||
| 				left--; | ||||
|  | ||||
| 				if ( left && Entries[index].Type == Parameters ) | ||||
| 				if ( left && Entries[index]->Type == Parameters ) | ||||
| 				{ | ||||
| 					result = string_append_fmt( result, "%s", Entries[index].to_string() ); | ||||
| 					result = string_append_fmt( result, "%s", Entries[index]->to_string() ); | ||||
| 					index++; | ||||
| 					left--; | ||||
| 				} | ||||
|  | ||||
| 				result = string_append_fmt( result, ")\n{\n%s\n}", Entries[index].to_string() ); | ||||
| 				result = string_append_fmt( result, ")\n{\n%s\n}", Entries[index]->to_string() ); | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| 			case Function_Body: | ||||
| 				fatal("NOT SUPPORTED YET"); | ||||
| 			break; | ||||
|  | ||||
| 			case Namespace: | ||||
| 				fatal("NOT SUPPORTED YET"); | ||||
| 			break; | ||||
|  | ||||
| 			case Namespace_Body: | ||||
| 				fatal("NOT SUPPORTED YET"); | ||||
| 			break; | ||||
|  | ||||
| 			case Parameters:  | ||||
| 			{ | ||||
| 				result = string_append_fmt( result, "%s %s", Entries[0]->to_string(), Name ); | ||||
|  | ||||
| 				s32 index = 1; | ||||
| 				s32 left  = array_count( Entries ) - 1; | ||||
|  | ||||
| 				while ( left--, left > 0 ) | ||||
| 					result = string_append_fmt( result, ", %s %s" | ||||
| 						, Entries[index]->Entries[0]->to_string() | ||||
| 						, Entries[index]->Name  | ||||
| 					); | ||||
| 			} | ||||
| 			break; | ||||
|  | ||||
| @@ -344,9 +699,17 @@ namespace gen | ||||
| 				fatal("NOT SUPPORTED YET"); | ||||
| 			break; | ||||
|  | ||||
| 			case Typedef: | ||||
| 				fatal("NOT SUPPORTED YET"); | ||||
| 			break; | ||||
|  | ||||
| 			case Typename: | ||||
| 				result = string_append_fmt( result, "%s", Name ); | ||||
| 			break; | ||||
|  | ||||
| 			case Using: | ||||
| 				fatal("NOT SUPPORTED YET"); | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		return result; | ||||
| @@ -356,7 +719,7 @@ namespace gen | ||||
|  | ||||
| 	void Builder::print( Code code ) | ||||
| 	{ | ||||
| 		Buffer = string_append_fmt( Buffer, "%s\n\n", code.to_string() ); | ||||
| 		Buffer = string_append_fmt( Buffer, "%s\n\n", code->to_string() ); | ||||
| 	} | ||||
|  | ||||
| 	bool Builder::open( char const* path ) | ||||
|   | ||||
							
								
								
									
										471
									
								
								project/gen.hpp
									
									
									
									
									
								
							
							
						
						
									
										471
									
								
								project/gen.hpp
									
									
									
									
									
								
							| @@ -1,20 +1,42 @@ | ||||
| /* | ||||
| 	gencpp: A simple staged metaprogramming library for C++. | ||||
|  | ||||
| 	This library is intended for small-to midsize projects that want rapid complation times  | ||||
| 	for fast debugging. | ||||
|  | ||||
| 	AST type checking supports only a small subset of c++.  | ||||
| 	See the 'ECode' namespace and 'gen API' region to see what is supported. | ||||
|  | ||||
| 	There is no support for accessability fields in structs. | ||||
| */ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "Bloat.hpp" | ||||
|  | ||||
| // Defined by default. | ||||
|  | ||||
| #define GEN_ENABLE_READONLY_AST | ||||
| // #define GEN_DEFINE_DSL | ||||
|  | ||||
| #define gen_time | ||||
| #ifdef gen_time | ||||
| namespace gen | ||||
| { | ||||
| 	#if 0 | ||||
| 	ct sw ColumnLimit = 256; | ||||
| 	ct sw MaxLines    = kilobytes(256); | ||||
|  | ||||
| 	using LineStr = char[ColumnLimit]; | ||||
| 	#endif | ||||
|  | ||||
| 	// Specifier Type | ||||
| 	enum Specifier : u8 | ||||
| 	{ | ||||
| 		Alignas,            // alignas(#) | ||||
| 		Constexpr,          // constexpr | ||||
| 		Inline,             // inline | ||||
|  | ||||
| 		C_Linkage,          // extern "C" | ||||
| 		API_Import,         // Vendor specific way dynamic import symbol | ||||
| 		API_Export,         // Vendor specific way to dynamic export | ||||
| @@ -27,12 +49,16 @@ namespace gen | ||||
| 		Num_Specifiers | ||||
| 	}; | ||||
|  | ||||
| 	// Specifier to string | ||||
| 	inline | ||||
| 	char const* specifier_str( Specifier specifier ) | ||||
| 	{ | ||||
| 		static char const* lookup[ Num_Specifiers ] = { | ||||
| 		static  | ||||
| 		char const* lookup[ Num_Specifiers ] = { | ||||
| 			"alignas", | ||||
| 			"constexpr", | ||||
| 			"inline", | ||||
|  | ||||
| 			"extern \"C\"", | ||||
| 		#if defined(ZPL_SYSTEM_WINDOWS) | ||||
| 			"__declspec(dllexport)", | ||||
| @@ -44,63 +70,93 @@ namespace gen | ||||
| 			"extern", | ||||
| 			"static", | ||||
| 			"static", | ||||
| 			"static", | ||||
| 			"thread_local" | ||||
| 		}; | ||||
|  | ||||
| 		return lookup[ specifier ]; | ||||
| 	} | ||||
|  | ||||
| 	struct Code | ||||
| 	// Code Type | ||||
| 	namespace ECode | ||||
| 	{ | ||||
| 		enum EType : u8 | ||||
| 		enum Type : u8 | ||||
| 		{ | ||||
| 			Invalid, | ||||
| 			Unused, | ||||
|  | ||||
| 			Untyped, // User provided raw string. | ||||
|  | ||||
| 			Decl_Type, | ||||
| 			Decl_Function, | ||||
| 			Decl_Function,  // Forward a function | ||||
| 			Decl_Type,      // Forward a type. | ||||
| 			Function,       // <type> <name>( <parameters> ) | ||||
| 			Function_Body,  // { <body> } | ||||
| 			Namespace, | ||||
| 			Namespace_Body,  | ||||
| 			Parameters,  // Used with functions. | ||||
| 			Specifiers, | ||||
| 			Struct,      | ||||
| 			Struct_Body, | ||||
| 			Function, | ||||
| 			Function_Body, | ||||
| 			Specifiers, | ||||
| 			Variable, | ||||
| 			Typedef, | ||||
| 			Typename, | ||||
| 			Using, | ||||
|  | ||||
| 			Num_Types | ||||
| 		}; | ||||
|  | ||||
| 	#pragma region Member API | ||||
| 		void comment( string value ) | ||||
| 		inline | ||||
| 		char const* str( Type type ) | ||||
| 		{ | ||||
| 			Comment = value; | ||||
| 		} | ||||
| 			static  | ||||
| 			char const* lookup[Num_Types] = { | ||||
| 				"Invalid", | ||||
|  | ||||
| 				"Untyped", | ||||
| 				 | ||||
| 				"Decl_Function", | ||||
| 				"Decl_type", | ||||
| 				"Function", | ||||
| 				"Function_Body", | ||||
| 				"Namespace", | ||||
| 				"Namespace_Body", | ||||
| 				"Parameters", | ||||
| 				"Specifiers", | ||||
| 				"Struct", | ||||
| 				"Struct_Body", | ||||
| 				"Variable", | ||||
| 				"Typedef", | ||||
| 				"Typename", | ||||
| 				"using" | ||||
| 			}; | ||||
|  | ||||
| 			return lookup[ type ]; | ||||
| 		} | ||||
| 	} | ||||
| 	using CodeT = ECode::Type; | ||||
|  | ||||
| 	// TODO: If perf needs it, convert layout an SOA format. | ||||
| 	/*  | ||||
| 		Simple AST POD with functionality to seralize into C++ syntax. | ||||
|  | ||||
| 		ASTs are currently stored as an AOS. They are always reconstructed on demand. | ||||
| 		Thus redundant AST can easily occur. | ||||
| 		Not sure if its better to store them in a hashmap. | ||||
| 	*/ | ||||
| 	struct AST | ||||
| 	{ | ||||
| 	#pragma region Member API | ||||
| 		forceinline | ||||
| 		void add( Code other ) | ||||
| 		void add( AST* other ) | ||||
| 		{ | ||||
| 			array_append( Entries, other ); | ||||
| 		} | ||||
|  | ||||
| 		forceinline | ||||
| 		void add( array(Code) other ) | ||||
| 		{ | ||||
| 			array_appendv( Entries, other, sizeof(other) ); | ||||
| 		} | ||||
|  | ||||
| 		forceinline | ||||
| 		void add( Code* entries, u32 num_entries ) | ||||
| 		{ | ||||
| 			array_appendv( Entries, entries, num_entries ); | ||||
| 			other->Parent = this; | ||||
| 		} | ||||
|  | ||||
| 		forceinline | ||||
| 		bool has_entries() | ||||
| 		{ | ||||
| 			static bool lookup[Num_Types] = { | ||||
| 			static bool lookup[ ECode::Num_Types] = { | ||||
| 				false, // Invalid | ||||
| 				false, // Unused | ||||
| 				false, // Untyped | ||||
| @@ -117,105 +173,310 @@ namespace gen | ||||
| 			return lookup[Type]; | ||||
| 		} | ||||
|  | ||||
| 		string to_string(); | ||||
| 		forceinline | ||||
| 		bool is_invalid() | ||||
| 		{ | ||||
| 			return Type != ECode::Invalid; | ||||
| 		} | ||||
|  | ||||
| 		forceinline | ||||
| 		operator bool() | ||||
| 		char const* type_str() | ||||
| 		{ | ||||
| 			return Type != Invalid; | ||||
| 			return ECode::str( Type ); | ||||
| 		} | ||||
|  | ||||
| 		operator char const*() | ||||
| 		{ | ||||
| 			return to_string(); | ||||
| 		} | ||||
| 		string to_string(); | ||||
|  | ||||
| 	#if 0 | ||||
| 		bool operator ==( Code& other ) | ||||
| 		{ | ||||
| 			bool children_equal = true; | ||||
|  | ||||
| 			#define is( Value_ ) Type == Value_ | ||||
|  | ||||
| 			if ( has_children() ) | ||||
| 			{ | ||||
| 				u32 left = array_count( Children ); | ||||
| 				do | ||||
| 				{ | ||||
| 					 | ||||
| 				} | ||||
| 				while ( left--, left > 0 ) | ||||
| 			} | ||||
|  | ||||
| 			return  | ||||
| 				Type == other.Type  | ||||
| 			&&	Name == other.Name | ||||
| 			&&  children_equal | ||||
| 			; | ||||
| 		} | ||||
| 	#endif | ||||
| 	#pragma endregion Member API | ||||
|  | ||||
| 	#define Using_Code_POD         \ | ||||
| 		Code::EType       Type;    \ | ||||
| 		string            Name;    \ | ||||
| 		string            Comment; \ | ||||
| 		union {                    \ | ||||
| 			array(Code)   Entries; \ | ||||
| 			string        Content; \ | ||||
| 	#define Using_Code_POD          \ | ||||
| 		CodeT             Type;     \ | ||||
| 		bool              Readonly; \ | ||||
| 		AST*              Parent;   \ | ||||
| 		string            Name;     \ | ||||
| 		string            Comment;  \ | ||||
| 		union {                     \ | ||||
| 			array(AST*)   Entries;  \ | ||||
| 			string        Content;  \ | ||||
| 		}; | ||||
|  | ||||
| 		Using_Code_POD; | ||||
| 	}; | ||||
|  | ||||
| 	using CodeType = Code::EType; | ||||
|  | ||||
| 	struct Code_POD | ||||
| 	struct CodePOD | ||||
| 	{ | ||||
| 		Using_Code_POD; | ||||
| 	}; | ||||
|  | ||||
| 	constexpr Code UnusedCode = { Code::Unused, nullptr, nullptr, { nullptr }  }; | ||||
| 	// Its intended for the AST to have equivalent size to its POD. | ||||
| 	// All extra functionality within the AST namespace should just be syntatic sugar. | ||||
| 	static_assert( sizeof(AST) == sizeof(CodePOD), "ERROR: AST IS NOT POD" ); | ||||
|  | ||||
| 	/* | ||||
| 		AST* typedef as to not constantly have to add the '*' as this is written often.. | ||||
|  | ||||
| 		If GEN_ENABLE_READONLY_AST is defined, readonly assertions will be done on any member dreference,  | ||||
| 		and the 'gen API' related functions. will set their created ASTs to readonly before returning. | ||||
|  | ||||
| 		Casting to AST* will bypass. | ||||
| 	*/ | ||||
| 	struct Code | ||||
| 	{ | ||||
| 		AST* ast; | ||||
|  | ||||
| 		forceinline | ||||
| 		operator bool() | ||||
| 		{ | ||||
| 			return ast->is_invalid(); | ||||
| 		} | ||||
|  | ||||
| 		bool operator ==( Code other ) | ||||
| 		{ | ||||
| 			return ast == other.ast; | ||||
| 		} | ||||
|  | ||||
| 		operator AST*() | ||||
| 		{ | ||||
| 			return ast; | ||||
| 		} | ||||
| 		 | ||||
| 		Code& operator =( Code other ) | ||||
| 		{ | ||||
| 			ast = other.ast; | ||||
|  | ||||
| 			return *this; | ||||
| 		} | ||||
|  | ||||
| 	#ifdef GEN_ENABLE_READONLY_AST | ||||
| 		forceinline | ||||
| 		AST* operator ->()  | ||||
| 		{ | ||||
| 			if ( ast == nullptr ) | ||||
| 				fatal("Attempt to dereference a nullptr!"); | ||||
|  | ||||
| 			if ( ast->Readonly ) | ||||
| 				fatal("Attempted to access a member from a readonly ast!");			 | ||||
|  | ||||
| 			return ast; | ||||
| 		} | ||||
|  | ||||
| 		Code& operator *() = delete; | ||||
| 	#endif | ||||
| 	}; | ||||
|  | ||||
| 	// Used when the its desired when omission is allowed in a definition. | ||||
| 	ct Code UnusedCode = { nullptr }; | ||||
|  | ||||
| 	// Used internally for the most part to identify invaidly generated code. | ||||
| 	ct CodePOD InvalidCode = { ECode::Invalid, false, nullptr, nullptr, nullptr, { nullptr } }; | ||||
|  | ||||
| 	/* | ||||
| 		Type registy: Used to store Typename ASTs. Types are registered by their string literal value. | ||||
|  | ||||
| 		Purely used as a memory optimization. | ||||
| 		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 ); | ||||
|  | ||||
| #pragma region gen API | ||||
| 	/* | ||||
| 		Initialize the library. | ||||
| 		This currently just initializes the CodePool. | ||||
| 	*/	 | ||||
| 	void init(); | ||||
|  | ||||
| 	/* | ||||
| 		Foward Declare a type: | ||||
| 		<specifiers> <type> <name>; | ||||
| 	*/ | ||||
| 	Code decl_type( char const* name, Code type, Code specifiers = UnusedCode ); | ||||
|  | ||||
| 	/* | ||||
| 		Foward Declare a function: | ||||
| 		<specifiers> <name> ( <params> ); | ||||
| 	*/ | ||||
| 	Code decl_fn( char const* name | ||||
| 		, Code specifiers | ||||
| 		, Code params | ||||
| 		, Code ret_type | ||||
| 	); | ||||
|  | ||||
| 	Code def_parameters( s32 num, ... ); | ||||
| 	/* | ||||
| 		Define an expression: | ||||
| 		< c/c++ expression > | ||||
| 	*/ | ||||
| 	Code def_expression( Code value ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a function: | ||||
| 		<specifiers> <name> ( <params> ) | ||||
| 		{ | ||||
| 			<body> | ||||
| 		} | ||||
| 	*/ | ||||
| 	Code def_function( char const* name | ||||
| 		, Code specifiers | ||||
| 		, Code params | ||||
| 		, Code ret_type | ||||
| 		, Code body  | ||||
| 	); | ||||
| 	Code def_function_body( u32 num, ... ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a fucntion body: | ||||
| 		{ | ||||
| 			<entry> | ||||
|  | ||||
| 			... | ||||
| 		} | ||||
|  | ||||
| 		Each entry is provided an empty line separation. | ||||
| 	*/ | ||||
| 	Code def_function_body( s32 num, ... ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a namespace; | ||||
| 		namespace <name> | ||||
| 		{ | ||||
| 			<body> | ||||
| 		} | ||||
| 	*/ | ||||
| 	Code def_namespace( char const* name, Code body ); | ||||
| 	Code def_namespace_body( u32 num, ... ); | ||||
|  | ||||
| 	Code def_specifiers( u32 num , ... ); | ||||
| 	/* | ||||
| 		Define a namespace body: | ||||
| 		{ | ||||
| 			<entry> | ||||
|  | ||||
| 			... | ||||
| 		} | ||||
|  | ||||
| 		Each entry is provided an empty line separation. | ||||
| 	*/ | ||||
| 	Code def_namespace_body( s32 num, ... ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a set of parameters for a function: | ||||
| 		<name> <type>, ... | ||||
| 	*/ | ||||
| 	Code def_parameters( s32 num, ... ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a set of specifiers for a function, struct, type, or varaible | ||||
| 	*/ | ||||
| 	Code def_specifiers( s32 num , ... ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a struct: | ||||
| 		struct <specifiers> <name> : <parent> | ||||
| 		{ | ||||
| 			<body> | ||||
| 		} | ||||
| 	*/ | ||||
| 	Code def_struct( char const* name, Code body, Code parent = UnusedCode, Code specifiers = UnusedCode ); | ||||
| 	Code def_struct_body( u32 num, ... ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a struct's body: | ||||
| 		{ | ||||
| 			<entry> | ||||
|  | ||||
| 			... | ||||
| 		} | ||||
|  | ||||
| 		Each entry is provided an empty line separation. | ||||
| 	*/ | ||||
| 	Code def_struct_body( s32 num, ... ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a variable: | ||||
| 		<specifiers> <type> <name> = <value>; | ||||
| 	*/ | ||||
| 	Code def_variable( char const* name, Code type, Code value = UnusedCode, Code specifiers = UnusedCode ); | ||||
|  | ||||
| 	/* | ||||
| 		Define a type AST value. | ||||
| 		Useless by itself, its intended to be used in conjunction with  | ||||
| 	*/ | ||||
| 	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_namespace( char const* name ); | ||||
|  | ||||
| 	/* | ||||
| 		Define an untyped code string. | ||||
|  | ||||
| 		Untyped code may be used in bodies of functions, namespaces, or structs | ||||
| 		or the in places where expressions may be placed. | ||||
|  | ||||
| 		Because the code within it is untyped, errors will naturally not be provided. | ||||
| 		Consider this an a preprocessor define. | ||||
| 	*/ | ||||
| 	Code untyped_str( char const* str ); | ||||
|  | ||||
| 	/* | ||||
| 		Define an untyped code string using traditional 'printf'. | ||||
|  | ||||
| 		Untyped code may be used in bodies of functions, namespaces, or structs | ||||
| 		or the in places where expressions may be placed. | ||||
|  | ||||
| 		Because the code within it is untyped, errors will naturally not be provided. | ||||
| 		Consider this an a preprocessor define. | ||||
| 	*/ | ||||
| 	Code untyped_fmt( char const* fmt, ... ); | ||||
|  | ||||
| 	Code token_fmt( char const* fmt, ... ); | ||||
| 	/* | ||||
| 		Define an untyped code string using token formatting: | ||||
| 		... { <ID> } ... Will be repalced with value of token ID. | ||||
|  | ||||
| 		Values are to provided as: <char const* ID>, <char const* Value>, ... | ||||
|  | ||||
| 		num_tokens : The number of ID-Value pairs provided. | ||||
|  | ||||
| 		Untyped code may be used in bodies of functions, namespaces, or structs | ||||
| 		or the in places where expressions may be placed. | ||||
|  | ||||
| 		Because the code within it is untyped, errors will naturally not be provided. | ||||
| 		Consider this an a preprocessor define. | ||||
| 	*/ | ||||
| 	Code token_fmt( char const* fmt, s32 num_tokens, ... ); | ||||
|  | ||||
|  | ||||
| 	/* | ||||
| 		Creates a unit file. | ||||
|  | ||||
| 		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. | ||||
|  | ||||
| 		The name provided is the name of the file. | ||||
| 	*/ | ||||
| 	Code create_Unit( char const* name ); | ||||
|  | ||||
| 	/*  | ||||
| 		Used to generate the files. | ||||
| 		This is inspired by jai's usage of the string_builder with #insert. | ||||
|  | ||||
| 		Its expected when using this library that Code ast will be serialized with the: | ||||
| 		Builder::print() proc | ||||
|  | ||||
| 		The seralized content of the Code ast will be appended to Buffer within an empty line | ||||
| 		prepared for a another definition or to add an empty newline to the end of the file.  | ||||
|  | ||||
| 		Builder::write() should be called when all Code has been seralized for that file. | ||||
|  | ||||
| 		The #insert directive is thus represented by an #include of the generated file at your desired line | ||||
| 		of any file in the target project. | ||||
| 	*/ | ||||
| 	struct Builder | ||||
| 	{ | ||||
| 		zpl_file File; | ||||
| @@ -226,7 +487,67 @@ namespace gen | ||||
| 		bool open( char const* path ); | ||||
| 		void write(); | ||||
| 	}; | ||||
| #pragma endregion gen API | ||||
| } | ||||
|  | ||||
| #define gen_main main | ||||
| #pragma region MACROS | ||||
| #	define gen_main main | ||||
|  | ||||
| #	define __ UnusedCode | ||||
|  | ||||
| /* | ||||
| 	gen's Domain Specific Langauge. | ||||
|  | ||||
| 	Completely optional, makes the code gen syntax less verbose.. | ||||
| */ | ||||
| #ifdef GEN_DEFINE_DSL | ||||
| #	define type( Name_, Value_ )        Code Name_ = gen::def_type( txt(Value_) ) | ||||
| #	define type_fmt( Name_, Fmt_, ... ) Code Name_ = gen::def_type( bprintf( Fmt_, __VA_ARGS__ ) ) | ||||
| #   define value( Name_, Value_ )       Code Name_ = gen::untyped_str( Value_ ) | ||||
| #	define specifiers( Name_, ... )     Code Name_ = gen::def_specifiers( VA_NARGS( __VA_ARGS__ ), __VA_ARGS__ ) | ||||
| #	define using( Name_, Type_ )		Code Name_ = gen::def_using( #Name_, Type_ ) | ||||
|  | ||||
| #	define var( Name_, Type_, Value_, Specifiers_ ) \ | ||||
| 		Code Name_ = gen::def_variable( #Name_, Type_, untyped_str( #Value_ ), Specifiers_ ) | ||||
|  | ||||
| // #   define def ( Name _ ) Code Name_; | ||||
|  | ||||
| #	define params( ... ) gen::def_parameters( VA_NARGS( __VA_ARGS__ ) / 2, __VA_ARGS__ ) | ||||
|  | ||||
| /* | ||||
| 	Defines scoped symbol. | ||||
|  | ||||
| 	Used with: | ||||
| 	- function | ||||
| 	- namespace | ||||
| 	- struct | ||||
| */ | ||||
| #	define def( Name_ ) Code Name_; | ||||
|  | ||||
| #	define function( Name_, Specifiers_, ReturnType_, Parameters_, Body_ ) \ | ||||
| 		Name_ = gen::def_function( #Name_, Specifiers_, Parameters_, ReturnType_, Body_ ) | ||||
|  | ||||
| #	define function_body( ... ) \ | ||||
| 		gen::def_function_body( VA_NARGS( __VA_ARS__ ), __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__ ) | ||||
| #endif | ||||
| #pragma endregion MACROS | ||||
|  | ||||
| #pragma region CONSTANTS | ||||
| namespace gen | ||||
| { | ||||
| 	// Predefined typename codes. | ||||
|  | ||||
| 	extern const Code t_bool; | ||||
| 	extern const Code t_sw; | ||||
| 	extern const Code t_uw; | ||||
|  | ||||
| 	extern const Code spec_inline; | ||||
| } | ||||
| #pragma endregion CONSTANTS | ||||
| #endif | ||||
|   | ||||
		Reference in New Issue
	
	Block a user