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:
		
							
								
								
									
										11
									
								
								Readme.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								Readme.md
									
									
									
									
									
								
							| @@ -2,9 +2,17 @@ | |||||||
|  |  | ||||||
| An attempt at simple staged metaprogramming for c/c++. | An attempt at simple staged metaprogramming for c/c++. | ||||||
|  |  | ||||||
|  | This library is intended for small-to midsize projects that want rapid complation times. | ||||||
|  | for fast debugging. | ||||||
|  |  | ||||||
|  | ## Notes | ||||||
|  |  | ||||||
| This project is not minimum feature complete yet.   | This project is not minimum feature complete yet.   | ||||||
| Version 1 will have c and a subset of c++ features available to it. | Version 1 will have c and a subset of c++ features available to it. | ||||||
|  |  | ||||||
|  | I will generate with this library a C99 or 11 variant when Version 1 is complete.   | ||||||
|  | A single-header version will also be genrated. | ||||||
|  |  | ||||||
| ## How it works | ## How it works | ||||||
|  |  | ||||||
| A metaprogram is built to generate files before the main program is built. We'll term runtime for this program as `gen_time`. The metaprogram's core implementation are within `gen.hpp` and `gen.cpp` in the project directory. | A metaprogram is built to generate files before the main program is built. We'll term runtime for this program as `gen_time`. The metaprogram's core implementation are within `gen.hpp` and `gen.cpp` in the project directory. | ||||||
| @@ -70,3 +78,6 @@ However, if the code being generated becomes complex, or from a datatable or dat | |||||||
|  |  | ||||||
| * Need problably a better name, I found a few repos with this same one... | * Need problably a better name, I found a few repos with this same one... | ||||||
| * Actually get to version 1. | * Actually get to version 1. | ||||||
|  | * Make a test suite made up of collections based of the ZPL library templated colllection macros and the memory module. | ||||||
|  | * Generate a single-header library. | ||||||
|  | * Generate a C-supported single-header library. | ||||||
|   | |||||||
| @@ -4,6 +4,28 @@ | |||||||
|  |  | ||||||
| #pragma once	 | #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 | #ifdef BLOAT_IMPL | ||||||
| #	define ZPL_IMPLEMENTATION | #	define ZPL_IMPLEMENTATION | ||||||
| #endif | #endif | ||||||
| @@ -21,7 +43,7 @@ | |||||||
| #		define ZPL_MODULE_ESSENTIALS | #		define ZPL_MODULE_ESSENTIALS | ||||||
| #		define ZPL_MODULE_CORE | #		define ZPL_MODULE_CORE | ||||||
| #		define ZPL_MODULE_TIMER | #		define ZPL_MODULE_TIMER | ||||||
| // #	define ZPL_MODULE_HASHING | #		define ZPL_MODULE_HASHING | ||||||
| // #	define ZPL_MODULE_REGEX | // #	define ZPL_MODULE_REGEX | ||||||
| // #	define ZPL_MODULE_EVENT | // #	define ZPL_MODULE_EVENT | ||||||
| // #	define ZPL_MODULE_DLL | // #	define ZPL_MODULE_DLL | ||||||
|   | |||||||
							
								
								
									
										549
									
								
								project/gen.cpp
									
									
									
									
									
								
							
							
						
						
									
										549
									
								
								project/gen.cpp
									
									
									
									
									
								
							| @@ -5,26 +5,48 @@ | |||||||
| #ifdef gen_time | #ifdef gen_time | ||||||
| namespace gen | 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 decl_type( char const* name, Code type, Code specifiers ) | ||||||
| 	{ | 	{ | ||||||
|  | 		using namespace ECode; | ||||||
|  |  | ||||||
|  | 		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  | 		Code  | ||||||
| 		result       = make(); | 		result       = make(); | ||||||
| 		result.Type = Code::Decl_Type; | 		result->Type = Decl_Type; | ||||||
| 		result.Name = string_make( g_allocator, name ); | 		result->Name = string_make( g_allocator, name ); | ||||||
|  |  | ||||||
| 		array_init( result.Entries, g_allocator ); | 		array_init( result->Entries, g_allocator ); | ||||||
| 		result.add( specifiers ); | 		result->add( specifiers ); | ||||||
| 		result.add( type ); | 		result->add( type ); | ||||||
|  |  | ||||||
| 		return result; | 		return result; | ||||||
| 	} | 	} | ||||||
| @@ -35,57 +57,77 @@ namespace gen | |||||||
| 		, Code ret_type | 		, Code ret_type | ||||||
| 	) | 	) | ||||||
| 	{ | 	{ | ||||||
|  | 		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 | 		Code | ||||||
| 		result       = make(); | 		result       = make(); | ||||||
| 		result.Type = Code::Decl_Function; | 		result->Type = Decl_Function; | ||||||
| 		result.Name = string_make( g_allocator, name ); | 		result->Name = string_make( g_allocator, name ); | ||||||
| 		 | 		 | ||||||
| 		array_init( result.Entries, g_allocator ); | 		array_init( result->Entries, g_allocator ); | ||||||
|  |  | ||||||
| 		if ( specifiers ) | 		if ( specifiers ) | ||||||
| 			result.add( specifiers ); | 			result->add( specifiers ); | ||||||
|  |  | ||||||
| 		result.add( ret_type ); | 		result->add( ret_type ); | ||||||
|  |  | ||||||
| 		if ( params ) | 		if ( params ) | ||||||
| 			result.add( params ); | 			result->add( params ); | ||||||
|  |  | ||||||
| 		return result; | 		return result; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Code def_parameters( s32 num, ... ) | 	Code def_parameters( s32 num, ... ) | ||||||
| 	{ | 	{ | ||||||
|  | 		using namespace ECode; | ||||||
|  |  | ||||||
| 		if (num <= 0) | 		if (num <= 0) | ||||||
| 			fatal("TT::make_paramters: num is %d", num); | 			fatal( "TT::make_paramters: num cannot be zero or neg" ); | ||||||
|  |  | ||||||
| 		Code | 		Code | ||||||
| 		result       = make(); | 		result       = make(); | ||||||
| 		result.Type = Code::Parameters; | 		result->Type = Parameters; | ||||||
|  |  | ||||||
| 		va_list va; | 		va_list va; | ||||||
| 		va_start(va, num); | 		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); | 		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 ) | 		while( num -= 2, num && num % 2 == 0 ) | ||||||
| 		{ | 		{ | ||||||
|  | 			type = va_arg(va, Code); | ||||||
|  |  | ||||||
| 			Code | 			Code | ||||||
| 			param       = make(); | 			param       = make(); | ||||||
| 			param.Name = string_make( g_allocator, va_arg(va, char const*) ); | 			param->Type = Parameters; | ||||||
|  | 			param->Name = string_make( g_allocator, va_arg(va, char const*) ); | ||||||
|  |  | ||||||
| 			array_init( param.Entries, g_allocator ); | 			array_init( param->Entries, g_allocator ); | ||||||
|  |  | ||||||
| 			type = va_arg(va, Code); | 			if ( type->Type != Typename ) | ||||||
| 			param.add( type ); | 				fatal( "gen::def_parameters: type of param %d is not a Typename", num - num + 1 ); | ||||||
|  |  | ||||||
| 			result.add(param); | 			param->add( type ); | ||||||
|  | 			result->add(param); | ||||||
| 		} | 		} | ||||||
| 		 |  | ||||||
| 		va_end(va); | 		va_end(va); | ||||||
|  |  | ||||||
| 		return result; | 		return result; | ||||||
| @@ -98,50 +140,155 @@ namespace gen | |||||||
| 		, Code body  | 		, 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  | 		Code  | ||||||
| 		result       = make(); | 		result       = make(); | ||||||
| 		result.Name = string_make( g_allocator, name ); | 		result->Name = string_make( g_allocator, name ); | ||||||
| 		result.Type = Code::Function; | 		result->Type = Function; | ||||||
| 		 | 		 | ||||||
| 		array_init( result.Entries, g_allocator ); | 		array_init( result->Entries, g_allocator ); | ||||||
|  |  | ||||||
| 		if ( specifiers ) | 		if ( specifiers ) | ||||||
| 			result.add( specifiers ); | 			result->add( specifiers ); | ||||||
|  |  | ||||||
| 		result.add( ret_type ); | 		result->add( ret_type ); | ||||||
|  |  | ||||||
| 		if ( params ) | 		if ( params ) | ||||||
| 			result.add( params ); | 			result->add( params ); | ||||||
|  |  | ||||||
| 		result.add( body ); | 		result->add( body ); | ||||||
|  |  | ||||||
|  | 		body->Parent = result; | ||||||
|  |  | ||||||
| 		return 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( char const* name, Code body ) | ||||||
| 	{ | 	{ | ||||||
|  | 		using namespace ECode; | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	Code def_namespace_body( u32 num, ... ) |  | ||||||
| 	{ |  | ||||||
|  |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	Code def_specifiers( u32 num, ... ) |  | ||||||
| 	{ |  | ||||||
| 		if ( num <= 0 ) |  | ||||||
| 			fatal("gen::make_specifier: num cannot be zero."); |  | ||||||
|  |  | ||||||
| 		Code  | 		Code  | ||||||
| 		result       = make(); | 		result       = make(); | ||||||
| 		result.Type    = Code::Specifiers; | 		result->Type = Namespace; | ||||||
| 		result.Content = string_make( g_allocator, "" ); |  | ||||||
|  | 		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_list va; | ||||||
| 		va_start(va, num); | 		va_start(va, num); | ||||||
| @@ -152,13 +299,13 @@ namespace gen | |||||||
| 			switch ( type ) | 			switch ( type ) | ||||||
| 			{ | 			{ | ||||||
| 				case Alignas: | 				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; | 				break; | ||||||
|  |  | ||||||
| 				default: | 				default: | ||||||
| 					const char* str = specifier_str(type); | 					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; | 				break; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -170,29 +317,125 @@ namespace gen | |||||||
|  |  | ||||||
| 	Code def_struct( char const* name, Code body, Code parent, Code specifiers ) | 	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 ) | 	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 def_type( char const* name ) | ||||||
| 	{ | 	{ | ||||||
| 		Code  | 		Code  | ||||||
| 		result       = make(); | 		result       = make(); | ||||||
| 		result.Name = string_make( g_allocator, name ); | 		result->Name = string_make( g_allocator, name ); | ||||||
| 		result.Type = Code::Typename; | 		result->Type = ECode::Typename; | ||||||
|  |  | ||||||
| 		return result; | 		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, ...) | 	Code untyped_fmt(char const* fmt, ...) | ||||||
| 	{ | 	{ | ||||||
| @@ -206,21 +449,122 @@ namespace gen | |||||||
|           |           | ||||||
| 		Code  | 		Code  | ||||||
| 		result          = make(); | 		result          = make(); | ||||||
| 		result.Name    = string_make( g_allocator, fmt ); | 		result->Name    = string_make( g_allocator, fmt ); | ||||||
| 		result.Type    = Code::Untyped; | 		result->Type    = ECode::Untyped; | ||||||
| 		result.Content = string_make( g_allocator, buf ); | 		result->Content = string_make( g_allocator, buf ); | ||||||
|  |  | ||||||
| 		return result; | 		return result; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Code token_fmt( char const* fmt, ... ) |  | ||||||
| 	{ |  | ||||||
|  |  | ||||||
|  | 	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, 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, "" ); | 		string result = string_make( g_allocator, "" ); | ||||||
|  |  | ||||||
| @@ -229,6 +573,8 @@ namespace gen | |||||||
|  |  | ||||||
| 		switch ( Type ) | 		switch ( Type ) | ||||||
| 		{ | 		{ | ||||||
|  | 			using namespace ECode; | ||||||
|  |  | ||||||
| 			case Invalid: | 			case Invalid: | ||||||
| 				fatal("Attempted to serialize invalid code! - %s", Name); | 				fatal("Attempted to serialize invalid code! - %s", Name); | ||||||
| 			break; | 			break; | ||||||
| @@ -237,13 +583,6 @@ namespace gen | |||||||
| 				result = string_append_length( result, Content, string_length(Content) ); | 				result = string_append_length( result, Content, string_length(Content) ); | ||||||
| 			break; | 			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: | 			case Decl_Function: | ||||||
| 			{ | 			{ | ||||||
| 				u32 index = 0; | 				u32 index = 0; | ||||||
| @@ -252,9 +591,9 @@ namespace gen | |||||||
| 				if ( left <= 0 ) | 				if ( left <= 0 ) | ||||||
| 					fatal( "Code::to_string - Name: %s Type: %s, expected definition", Name, Type ); | 					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++; | 					index++; | ||||||
| 					left--; | 					left--; | ||||||
| 				} | 				} | ||||||
| @@ -262,13 +601,13 @@ namespace gen | |||||||
| 				if ( left <= 0 ) | 				if ( left <= 0 ) | ||||||
| 					fatal( "Code::to_string - Name: %s Type: %s, expected return type", Name, Type ); | 					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++; | 				index++; | ||||||
| 				left--; | 				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++; | 					index++; | ||||||
| 					left--; | 					left--; | ||||||
| 				} | 				} | ||||||
| @@ -277,22 +616,11 @@ namespace gen | |||||||
| 			} | 			} | ||||||
| 			break; | 			break; | ||||||
|  |  | ||||||
| 			case Function_Body: | 			case Decl_Type: | ||||||
| 			break; | 				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;\n", Entries[1]->to_string(), Name ); | ||||||
| 			{ |  | ||||||
| 				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; | 			break; | ||||||
|  |  | ||||||
| 			case Function: | 			case Function: | ||||||
| @@ -303,9 +631,9 @@ namespace gen | |||||||
| 				if ( left <= 0 ) | 				if ( left <= 0 ) | ||||||
| 					fatal( "Code::to_string - Name: %s Type: %s, expected definition", Name, Type ); | 					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++; | 					index++; | ||||||
| 					left--; | 					left--; | ||||||
| 				} | 				} | ||||||
| @@ -313,18 +641,45 @@ namespace gen | |||||||
| 				if ( left <= 0 ) | 				if ( left <= 0 ) | ||||||
| 					fatal( "Code::to_string - Name: %s Type: %s, expected return type", Name, Type ); | 					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++; | 				index++; | ||||||
| 				left--; | 				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++; | 					index++; | ||||||
| 					left--; | 					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; | 			break; | ||||||
|  |  | ||||||
| @@ -344,9 +699,17 @@ namespace gen | |||||||
| 				fatal("NOT SUPPORTED YET"); | 				fatal("NOT SUPPORTED YET"); | ||||||
| 			break; | 			break; | ||||||
|  |  | ||||||
|  | 			case Typedef: | ||||||
|  | 				fatal("NOT SUPPORTED YET"); | ||||||
|  | 			break; | ||||||
|  |  | ||||||
| 			case Typename: | 			case Typename: | ||||||
| 				result = string_append_fmt( result, "%s", Name ); | 				result = string_append_fmt( result, "%s", Name ); | ||||||
| 			break; | 			break; | ||||||
|  |  | ||||||
|  | 			case Using: | ||||||
|  | 				fatal("NOT SUPPORTED YET"); | ||||||
|  | 			break; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		return result; | 		return result; | ||||||
| @@ -356,7 +719,7 @@ namespace gen | |||||||
|  |  | ||||||
| 	void Builder::print( Code code ) | 	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 ) | 	bool Builder::open( char const* path ) | ||||||
|   | |||||||
							
								
								
									
										461
									
								
								project/gen.hpp
									
									
									
									
									
								
							
							
						
						
									
										461
									
								
								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 | #pragma once | ||||||
|  |  | ||||||
| #include "Bloat.hpp" | #include "Bloat.hpp" | ||||||
|  |  | ||||||
|  | // Defined by default. | ||||||
|  |  | ||||||
|  | #define GEN_ENABLE_READONLY_AST | ||||||
|  | // #define GEN_DEFINE_DSL | ||||||
|  |  | ||||||
|  | #define gen_time | ||||||
| #ifdef gen_time | #ifdef gen_time | ||||||
| namespace gen | namespace gen | ||||||
| { | { | ||||||
|  | 	#if 0 | ||||||
| 	ct sw ColumnLimit = 256; | 	ct sw ColumnLimit = 256; | ||||||
| 	ct sw MaxLines    = kilobytes(256); | 	ct sw MaxLines    = kilobytes(256); | ||||||
|  |  | ||||||
| 	using LineStr = char[ColumnLimit]; | 	using LineStr = char[ColumnLimit]; | ||||||
|  | 	#endif | ||||||
|  |  | ||||||
|  | 	// Specifier Type | ||||||
| 	enum Specifier : u8 | 	enum Specifier : u8 | ||||||
| 	{ | 	{ | ||||||
| 		Alignas,            // alignas(#) | 		Alignas,            // alignas(#) | ||||||
| 		Constexpr,          // constexpr | 		Constexpr,          // constexpr | ||||||
| 		Inline,             // inline | 		Inline,             // inline | ||||||
|  |  | ||||||
| 		C_Linkage,          // extern "C" | 		C_Linkage,          // extern "C" | ||||||
| 		API_Import,         // Vendor specific way dynamic import symbol | 		API_Import,         // Vendor specific way dynamic import symbol | ||||||
| 		API_Export,         // Vendor specific way to dynamic export | 		API_Export,         // Vendor specific way to dynamic export | ||||||
| @@ -27,12 +49,16 @@ namespace gen | |||||||
| 		Num_Specifiers | 		Num_Specifiers | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	// Specifier to string | ||||||
|  | 	inline | ||||||
| 	char const* specifier_str( Specifier specifier ) | 	char const* specifier_str( Specifier specifier ) | ||||||
| 	{ | 	{ | ||||||
| 		static char const* lookup[ Num_Specifiers ] = { | 		static  | ||||||
|  | 		char const* lookup[ Num_Specifiers ] = { | ||||||
| 			"alignas", | 			"alignas", | ||||||
| 			"constexpr", | 			"constexpr", | ||||||
| 			"inline", | 			"inline", | ||||||
|  |  | ||||||
| 			"extern \"C\"", | 			"extern \"C\"", | ||||||
| 		#if defined(ZPL_SYSTEM_WINDOWS) | 		#if defined(ZPL_SYSTEM_WINDOWS) | ||||||
| 			"__declspec(dllexport)", | 			"__declspec(dllexport)", | ||||||
| @@ -44,63 +70,93 @@ namespace gen | |||||||
| 			"extern", | 			"extern", | ||||||
| 			"static", | 			"static", | ||||||
| 			"static", | 			"static", | ||||||
|  | 			"static", | ||||||
| 			"thread_local" | 			"thread_local" | ||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| 		return lookup[ specifier ]; | 		return lookup[ specifier ]; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	struct Code | 	// Code Type | ||||||
|  | 	namespace ECode | ||||||
| 	{ | 	{ | ||||||
| 		enum EType : u8 | 		enum Type : u8 | ||||||
| 		{ | 		{ | ||||||
| 			Invalid, | 			Invalid, | ||||||
| 			Unused, |  | ||||||
|  |  | ||||||
| 			Untyped, // User provided raw string. | 			Untyped, // User provided raw string. | ||||||
|  |  | ||||||
| 			Decl_Type, | 			Decl_Function,  // Forward a function | ||||||
| 			Decl_Function, | 			Decl_Type,      // Forward a type. | ||||||
|  | 			Function,       // <type> <name>( <parameters> ) | ||||||
|  | 			Function_Body,  // { <body> } | ||||||
|  | 			Namespace, | ||||||
|  | 			Namespace_Body,  | ||||||
| 			Parameters,  // Used with functions. | 			Parameters,  // Used with functions. | ||||||
|  | 			Specifiers, | ||||||
| 			Struct,      | 			Struct,      | ||||||
| 			Struct_Body, | 			Struct_Body, | ||||||
| 			Function, |  | ||||||
| 			Function_Body, |  | ||||||
| 			Specifiers, |  | ||||||
| 			Variable, | 			Variable, | ||||||
|  | 			Typedef, | ||||||
| 			Typename, | 			Typename, | ||||||
|  | 			Using, | ||||||
|  |  | ||||||
| 			Num_Types | 			Num_Types | ||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| 	#pragma region Member API | 		inline | ||||||
| 		void comment( string value ) | 		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 | 		forceinline | ||||||
| 		void add( Code other ) | 		void add( AST* other ) | ||||||
| 		{ | 		{ | ||||||
| 			array_append( Entries, other ); | 			array_append( Entries, other ); | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		forceinline | 			other->Parent = this; | ||||||
| 		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 ); |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		forceinline | 		forceinline | ||||||
| 		bool has_entries() | 		bool has_entries() | ||||||
| 		{ | 		{ | ||||||
| 			static bool lookup[Num_Types] = { | 			static bool lookup[ ECode::Num_Types] = { | ||||||
| 				false, // Invalid | 				false, // Invalid | ||||||
| 				false, // Unused | 				false, // Unused | ||||||
| 				false, // Untyped | 				false, // Untyped | ||||||
| @@ -117,105 +173,310 @@ namespace gen | |||||||
| 			return lookup[Type]; | 			return lookup[Type]; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		string to_string(); | 		forceinline | ||||||
|  | 		bool is_invalid() | ||||||
|  | 		{ | ||||||
|  | 			return Type != ECode::Invalid; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		forceinline | 		forceinline | ||||||
| 		operator bool() | 		char const* type_str() | ||||||
| 		{ | 		{ | ||||||
| 			return Type != Invalid; | 			return ECode::str( Type ); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		operator char const*() | 		string to_string(); | ||||||
| 		{ |  | ||||||
| 			return 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 | 	#pragma endregion Member API | ||||||
|  |  | ||||||
| 	#define Using_Code_POD          \ | 	#define Using_Code_POD          \ | ||||||
| 		Code::EType       Type;    \ | 		CodeT             Type;     \ | ||||||
|  | 		bool              Readonly; \ | ||||||
|  | 		AST*              Parent;   \ | ||||||
| 		string            Name;     \ | 		string            Name;     \ | ||||||
| 		string            Comment;  \ | 		string            Comment;  \ | ||||||
| 		union {                     \ | 		union {                     \ | ||||||
| 			array(Code)   Entries; \ | 			array(AST*)   Entries;  \ | ||||||
| 			string        Content;  \ | 			string        Content;  \ | ||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| 		Using_Code_POD; | 		Using_Code_POD; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	using CodeType = Code::EType; | 	struct CodePOD | ||||||
|  |  | ||||||
| 	struct Code_POD |  | ||||||
| 	{ | 	{ | ||||||
| 		Using_Code_POD; | 		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(); | 	void init(); | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 		Foward Declare a type: | ||||||
|  | 		<specifiers> <type> <name>; | ||||||
|  | 	*/ | ||||||
| 	Code decl_type( char const* name, Code type, Code specifiers = UnusedCode ); | 	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 decl_fn( char const* name | ||||||
| 		, Code specifiers | 		, Code specifiers | ||||||
| 		, Code params | 		, Code params | ||||||
| 		, Code ret_type | 		, 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 def_function( char const* name | ||||||
| 		, Code specifiers | 		, Code specifiers | ||||||
| 		, Code params | 		, Code params | ||||||
| 		, Code ret_type | 		, Code ret_type | ||||||
| 		, Code body  | 		, 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( 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( 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 ); | 	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 ); | 	Code def_type( char const* name ); | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 		Define a using typedef: | ||||||
|  | 		using <name> = <type>; | ||||||
|  | 	*/ | ||||||
| 	Code def_using( char const* name, Code 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 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 | 	struct Builder | ||||||
| 	{ | 	{ | ||||||
| 		zpl_file File; | 		zpl_file File; | ||||||
| @@ -226,7 +487,67 @@ namespace gen | |||||||
| 		bool open( char const* path ); | 		bool open( char const* path ); | ||||||
| 		void write(); | 		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 | #endif | ||||||
|   | |||||||
							
								
								
									
										499
									
								
								test/Array.hpp
									
									
									
									
									
								
							
							
						
						
									
										499
									
								
								test/Array.hpp
									
									
									
									
									
								
							| @@ -17,6 +17,7 @@ | |||||||
| 			Code t_uw        = def_type( txt(uw) ); | 			Code t_uw        = def_type( txt(uw) ); | ||||||
| 			Code t_allocator = def_type( txt(allocator) ); | 			Code t_allocator = def_type( txt(allocator) ); | ||||||
|  |  | ||||||
|  | 	#ifndef GEN_DEFINE_DSL | ||||||
| 		Code header; | 		Code header; | ||||||
| 		{ | 		{ | ||||||
| 			Code num           = def_variable( "Num",       t_uw ); | 			Code num           = def_variable( "Num",       t_uw ); | ||||||
| @@ -30,20 +31,44 @@ | |||||||
| 		Code grow_formula; | 		Code grow_formula; | ||||||
| 		{ | 		{ | ||||||
| 			Code spec   = def_specifiers(1, Specifier::Inline); | 			Code spec   = def_specifiers(1, Specifier::Inline); | ||||||
| 			Code params = def_parameters(1, "value", t_uw ); | 			Code params = def_parameters(1, t_uw, "value" ); | ||||||
| 			Code body   = untyped_fmt( "\t""return 2 * value * 8;" ); | 			Code body   = untyped_str( "return 2 * value * 8;" ); | ||||||
|  |  | ||||||
| 			grow_formula = def_function( "grow_formula", spec, params, t_sw, body ); | 			grow_formula = def_function( "grow_formula", spec, params, t_sw, body ); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		Code base_body = def_struct_body(2, header, grow_formula); | 		Code body       = def_struct_body(2, header, grow_formula); | ||||||
| 		Code base      = def_struct( "ArrayBase", base_body ); | 		Code ArrayBase = def_struct( "ArrayBase", body ); | ||||||
| 		return base; | 		 | ||||||
|  | 	#else | ||||||
|  | 		def( ArrayBase ) | ||||||
|  | 			def ( Header )  | ||||||
|  | 			{ | ||||||
|  | 				var( Num,       t_uw, __, __ ); | ||||||
|  | 				var( Capacity,  t_uw, __, __); | ||||||
|  | 				var( Allocator, t_allocator, __, __); | ||||||
|  |  | ||||||
|  | 				Code body = struct_body( Num, Capacity, Allocator ); | ||||||
|  |  | ||||||
|  | 				struct( Header, __, __, body ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			def( grow_formula ) | ||||||
|  | 			{ | ||||||
|  | 				function( grow_formula, spec_inline, t_uw, params( t_uw, "value" ), untyped_str("return 2 * value * 8") ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			Code body = struct_body( Header, grow_formula ); | ||||||
|  | 		struct( ArrayBase, __, __, body ); | ||||||
|  | 	#endif | ||||||
|  |  | ||||||
|  | 		return ArrayBase; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	#define gen_array( Type_ ) gen__array( #Type_, sizeof(Type_), a_base ) | 	#define gen_array( Type_ ) gen__array( #Type_, sizeof(Type_), a_base ) | ||||||
| 	Code gen__array( char const* type_str, s32 type_size, Code parent ) | 	Code gen__array( char const* type_str, s32 type_size, Code parent ) | ||||||
| 	{ | 	{ | ||||||
|  | 	#ifndef GEN_DEFINE_DSL | ||||||
| 		// Make these global consts to be accessed anywhere... | 		// Make these global consts to be accessed anywhere... | ||||||
| 			Code t_uw        = def_type( txt(uw) ); | 			Code t_uw        = def_type( txt(uw) ); | ||||||
| 			Code t_sw        = def_type( txt(sw) ); | 			Code t_sw        = def_type( txt(sw) ); | ||||||
| @@ -51,16 +76,14 @@ | |||||||
| 			Code t_allocator = def_type( txt(allocator) ); | 			Code t_allocator = def_type( txt(allocator) ); | ||||||
| 			Code t_void      = def_type( txt(void) ); | 			Code t_void      = def_type( txt(void) ); | ||||||
|  |  | ||||||
| 			Code v_nullptr = untyped_fmt( "nullptr" ); | 			Code v_nullptr = untyped_str( "nullptr" ); | ||||||
|  |  | ||||||
| 			Code spec_ct     = def_specifiers(1, Specifier::Constexpr ); | 			Code spec_ct     = def_specifiers(1, Specifier::Constexpr ); | ||||||
| 			Code spec_inline = def_specifiers(1, Specifier::Inline ); | 			Code spec_inline = def_specifiers(1, Specifier::Inline ); | ||||||
|  |  | ||||||
| 		Code type     = def_type( type_str ); | 		Code type     = def_type( type_str ); | ||||||
| 		Code ptr_type = def_type( string_sprintf_buf( g_allocator, "%s*", type_str ) ); | 		Code ptr_type = def_type( bprintf( "%s*", type_str ) ); | ||||||
| 		Code ref_type = def_type( string_sprintf_buf( g_allocator, "%s&", type_str ) ); | 		Code ref_type = def_type( bprintf( "%s&", type_str ) ); | ||||||
|  |  | ||||||
| 		string name = string_sprintf_buf( g_allocator, "Array_%s", type_str ); |  | ||||||
|  |  | ||||||
| 		// From ArrayBase | 		// From ArrayBase | ||||||
| 			Code t_header   = def_type( "Header" ); | 			Code t_header   = def_type( "Header" ); | ||||||
| @@ -69,43 +92,43 @@ | |||||||
|  |  | ||||||
| 		Code array_def; | 		Code array_def; | ||||||
| 		{ | 		{ | ||||||
| 			Code using_type = def_using( "type", type ); | 			Code using_type = def_using( "Type", type ); | ||||||
| 			Code data       = def_variable( "Data", ptr_type ); | 			Code data       = def_variable( "Data", ptr_type ); | ||||||
|  |  | ||||||
| 			Code init; | 			Code init; | ||||||
| 			{ | 			{ | ||||||
| 				Code params = def_parameters( 1, "mem_hanlder", t_allocator ); | 				Code params = def_parameters( 1, t_allocator, "mem_handler" ); | ||||||
| 				Code body   = untyped_fmt( "\t""return init_reserve( mem_handler, grow_formula(0) );" ); | 				Code body   = untyped_str( "return init_reserve( mem_handler, grow_formula(0) );" ); | ||||||
|  |  | ||||||
| 				init = def_function( "init", UnusedCode, params, t_bool, body ); | 				init = def_function( "init", UnusedCode, params, t_bool, body ); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			Code init_reserve; | 			Code init_reserve; | ||||||
| 			{ | 			{ | ||||||
| 				Code params = def_parameters( 2, "mem_handler", ref_type, "capacity", t_sw ); | 				Code params = def_parameters( 2, t_allocator, "mem_handler", t_sw, "capacity" ); | ||||||
| 				Code body; | 				Code body; | ||||||
| 				{ | 				{ | ||||||
| 					Code header_value = untyped_fmt(  | 					Code header_value = untyped_str(  | ||||||
| 						"rcast( Header*, alloc( mem_handler, sizeof( Header ) + sizeof(type) + capacity ))" | 						"rcast( Header*, alloc( mem_handler, sizeof( Header ) + sizeof(Type) + capacity ))" | ||||||
| 					); | 					); | ||||||
| 					Code header = def_variable( "", ptr_header, header_value ); | 					Code header = def_variable( "header", ptr_header, header_value ); | ||||||
|  |  | ||||||
| 					Code null_check = untyped_fmt( | 					Code null_check = untyped_str( | ||||||
| 						"\t"	"if (header == nullptr)" | 							"if (header == nullptr)" | ||||||
| 						"\n\t\t"	"return false;" | 						"\n"	"return false;" | ||||||
| 					); | 					); | ||||||
|  |  | ||||||
| 					Code header_init = untyped_fmt( | 					Code header_init = untyped_str( | ||||||
| 						"\n\t" "header->Num       = 0;" | 							"header->Num       = 0;" | ||||||
| 						"\n\t" "header->Capacity  = capacity;" | 						"\n""header->Capacity  = capacity;" | ||||||
| 						"\n\t" "header->Allocator = mem_handler;" | 						"\n""header->Allocator = mem_handler;" | ||||||
| 					); | 					); | ||||||
|  |  | ||||||
| 					Code assign_data = untyped_fmt( | 					Code assign_data = untyped_str( | ||||||
| 						"\t" "Data = rcast( %s, header + 1 );", ptr_type | 						"Data = rcast( %s, header + 1 );", ptr_type | ||||||
| 					); | 					); | ||||||
|  |  | ||||||
| 					Code ret_true = untyped_fmt( "\t""return true" ); | 					Code ret_true = untyped_str( "\t""return true" ); | ||||||
|  |  | ||||||
| 					body = def_function_body( 5 | 					body = def_function_body( 5 | ||||||
| 					,	header | 					,	header | ||||||
| @@ -121,9 +144,9 @@ | |||||||
|  |  | ||||||
| 			Code free; | 			Code free; | ||||||
| 			{ | 			{ | ||||||
| 				Code body = untyped_fmt(  | 				Code body = untyped_str(  | ||||||
| 					"\t"	"Header& header = get_header();" | 						"Header& header = get_header();" | ||||||
| 					"\n\t"	"::free( header.Allocator, & get_header() );" | 					"\n""::free( header.Allocator, & get_header() );" | ||||||
| 				); | 				); | ||||||
|  |  | ||||||
| 				free = def_function( "free", UnusedCode, UnusedCode, t_void, body ); | 				free = def_function( "free", UnusedCode, UnusedCode, t_void, body ); | ||||||
| @@ -131,22 +154,22 @@ | |||||||
|  |  | ||||||
| 			Code append; | 			Code append; | ||||||
| 			{ | 			{ | ||||||
| 				Code params = def_parameters( 1, "value", type ); | 				Code params = def_parameters( 1, type, "value" ); | ||||||
| 				Code body; | 				Code body; | ||||||
| 				{ | 				{ | ||||||
| 					Code header = def_variable( "", ref_header, untyped_fmt( "get_header()") ); | 					Code header = def_variable( "header", ref_header, untyped_str( "get_header()") ); | ||||||
|  |  | ||||||
| 					Code check_cap = untyped_fmt( | 					Code check_cap = untyped_str( | ||||||
| 						"\t"		"if ( header.Capacity < header.Num + 1 )" | 							"if ( header.Capacity < header.Num + 1 )" | ||||||
| 						"\n\t\t"		"if ( ! grow(0) )" | 						"\n"	"if ( ! grow(0) )" | ||||||
| 						"\n\t\t\t"			"return false;" | 						"\n"		"return false;" | ||||||
| 					); | 					); | ||||||
|  |  | ||||||
| 					Code assign = untyped_fmt( | 					Code assign = untyped_str( | ||||||
| 						"\t"   "Data[ header.Num ] = value;" | 							 "Data[ header.Num ] = value;" | ||||||
| 						"\t\n" "header.Num++;" | 						"\n" "header.Num++;" | ||||||
| 						"\n" | 						"\n" | ||||||
| 						"\n\t" "return true;" | 						"\n" "return true;" | ||||||
| 					); | 					); | ||||||
|  |  | ||||||
| 					body = def_function_body( 3, header, check_cap, assign ); | 					body = def_function_body( 3, header, check_cap, assign ); | ||||||
| @@ -157,9 +180,9 @@ | |||||||
|  |  | ||||||
| 			Code back; | 			Code back; | ||||||
| 			{ | 			{ | ||||||
| 				Code body = untyped_fmt( | 				Code body = untyped_str( | ||||||
| 					"\t"	"Header& header = get_header();" | 					     "Header& header = get_header();" | ||||||
| 					"\n\t"	"return data[ header.Num - 1 ];" | 					"\n" "return data[ header.Num - 1 ];" | ||||||
| 				); | 				); | ||||||
|  |  | ||||||
| 				back = def_function( "back", UnusedCode, UnusedCode, type, body ); | 				back = def_function( "back", UnusedCode, UnusedCode, type, body ); | ||||||
| @@ -167,26 +190,26 @@ | |||||||
|  |  | ||||||
| 			Code clear; | 			Code clear; | ||||||
| 			{ | 			{ | ||||||
| 				Code body = untyped_fmt( "\t""get_header().Num = 0;" ); | 				Code body = untyped_str( "get_header().Num = 0;" ); | ||||||
|  |  | ||||||
| 				clear = def_function( "clear", UnusedCode, UnusedCode, t_void, body ); | 				clear = def_function( "clear", UnusedCode, UnusedCode, t_void, body ); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			Code fill; | 			Code fill; | ||||||
| 			{ | 			{ | ||||||
| 				Code params = def_parameters( 3, "begin", t_uw, "end", t_uw, "value", type ); | 				Code params = def_parameters( 3, t_uw, "begin", t_uw, "end", type, "value" ); | ||||||
| 				Code body; | 				Code body; | ||||||
| 				{ | 				{ | ||||||
| 					Code header = def_variable( "", ref_header, untyped_fmt( "get_header()") ); | 					Code header = def_variable( "header", ref_header, untyped_str( "get_header()") ); | ||||||
|  |  | ||||||
| 					Code check = untyped_fmt( | 					Code check = untyped_str( | ||||||
| 						"\t"	"if ( begin < 0 || end >= header.Num )" | 							"if ( begin < 0 || end >= header.Num )" | ||||||
| 						"\n\t\t"	"fatal( \"Range out of bounds\" );" | 						"\n"	"fatal( \"Range out of bounds\" );" | ||||||
| 					); | 					); | ||||||
|  |  | ||||||
| 					Code iter = untyped_fmt( | 					Code iter = untyped_str( | ||||||
| 						"\t"	"for ( sw index = begin; index < end; index++ )" | 							"for ( sw index = begin; index < end; index++ )" | ||||||
| 						"\n\t\t"	"Data[index] = vallue;" | 						"\n"	"Data[index] = vallue;" | ||||||
| 					); | 					); | ||||||
|  |  | ||||||
| 					body = def_function_body( 3, header, check, iter ); | 					body = def_function_body( 3, header, check, iter ); | ||||||
| @@ -197,25 +220,25 @@ | |||||||
|  |  | ||||||
| 			Code get_header; | 			Code get_header; | ||||||
| 			{ | 			{ | ||||||
| 				Code body = untyped_fmt( "\t""return pcast( Header, Data - 1 );" ); | 				Code body = untyped_str( "return pcast( Header, Data - 1 );" ); | ||||||
|  |  | ||||||
| 				get_header = def_function( "get_header", spec_inline, UnusedCode, ref_header, body ); | 				get_header = def_function( "get_header", spec_inline, UnusedCode, ref_header, body ); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			Code grow; | 			Code grow; | ||||||
| 			{ | 			{ | ||||||
| 				Code param = def_parameters( 1, "min_capacity", t_uw ); | 				Code param = def_parameters( 1, t_uw, "min_capacity" ); | ||||||
| 				Code body; | 				Code body; | ||||||
| 				{ | 				{ | ||||||
| 					Code header       = def_variable( "header", ref_header, untyped_fmt("get_header") ); | 					Code header       = def_variable( "header",      ref_header, untyped_str("get_header()") ); | ||||||
| 					Code new_capacity = def_variable( "new_capacity", t_uw, untyped_fmt("grow_formula( header.Capacity )") ); | 					Code new_capacity = def_variable( "new_capacity", t_uw,      untyped_str("grow_formula( header.Capacity )") ); | ||||||
|  |  | ||||||
| 					Code check_n_set = untyped_fmt( | 					Code check_n_set = untyped_str( | ||||||
| 						"\t"	"if ( new_capacity < min_capacity )" | 							"if ( new_capacity < min_capacity )" | ||||||
| 						"\n\t\t"	"new_capacity = min_capacity;" | 						"\n"	"new_capacity = min_capacity;" | ||||||
| 					); | 					); | ||||||
|  |  | ||||||
| 					Code ret = untyped_fmt( "\t" "return set_capacity( new_capacity );" ); | 					Code ret = untyped_str( "return set_capacity( new_capacity );" ); | ||||||
|  |  | ||||||
| 					body = def_function_body( 4, header, new_capacity, check_n_set, ret ); | 					body = def_function_body( 4, header, new_capacity, check_n_set, ret ); | ||||||
| 				} | 				} | ||||||
| @@ -227,10 +250,10 @@ | |||||||
| 			{ | 			{ | ||||||
| 				Code body; | 				Code body; | ||||||
| 				{ | 				{ | ||||||
| 					Code header = def_variable( "header", ref_header, untyped_fmt("get_header()") ); | 					Code header = def_variable( "header", ref_header, untyped_str("get_header()") ); | ||||||
|  |  | ||||||
| 					Code assertion = untyped_fmt( "\t" "assert( header.Num > 0 );" ); | 					Code assertion = untyped_str( "assert( header.Num > 0 );" ); | ||||||
| 					Code decrement = untyped_fmt( "\t" "header.Num--; " ); | 					Code decrement = untyped_str( "header.Num--; " ); | ||||||
|  |  | ||||||
| 					body = def_function_body( 3, header, assertion, decrement ); | 					body = def_function_body( 3, header, assertion, decrement ); | ||||||
| 				} | 				} | ||||||
| @@ -240,17 +263,17 @@ | |||||||
|  |  | ||||||
| 			Code reserve; | 			Code reserve; | ||||||
| 			{ | 			{ | ||||||
| 				Code params = def_parameters( 1, "new_capacity", t_uw ); | 				Code params = def_parameters( 1, t_uw, "new_capacity" ); | ||||||
| 				Code body; | 				Code body; | ||||||
| 				{ | 				{ | ||||||
| 					Code header = def_variable( "header", ref_header, untyped_fmt("get_header()") ); | 					Code header = def_variable( "header", ref_header, untyped_str("get_header()") ); | ||||||
|  |  | ||||||
| 					Code check_n_set = untyped_fmt( | 					Code check_n_set = untyped_str( | ||||||
| 						"\t" 	"if ( header.Capacity < new_capacity )" | 							"if ( header.Capacity < new_capacity )" | ||||||
| 						"\n\t\t"	"return set_capacity( new_capacity );" | 						"\n"	"return set_capacity( new_capacity );" | ||||||
| 					); | 					); | ||||||
|  |  | ||||||
| 					Code ret = untyped_fmt( "\t" "return true" ); | 					Code ret = untyped_str( "\t" "return true" ); | ||||||
|  |  | ||||||
| 					body = def_function_body( 3, header, check_n_set, ret ); | 					body = def_function_body( 3, header, check_n_set, ret ); | ||||||
| 				} | 				} | ||||||
| @@ -260,21 +283,21 @@ | |||||||
|  |  | ||||||
| 			Code resize; | 			Code resize; | ||||||
| 			{ | 			{ | ||||||
| 				Code param = def_parameters( 1, "new_num", t_uw ); | 				Code param = def_parameters( 1, t_uw, "new_num" ); | ||||||
|  |  | ||||||
| 				Code body; | 				Code body; | ||||||
| 				{ | 				{ | ||||||
| 					Code header = def_variable( "header", ref_header, untyped_fmt("get_header()") ); | 					Code header = def_variable( "header", ref_header, untyped_str("get_header()") ); | ||||||
|  |  | ||||||
| 					Code check_n_grow = untyped_fmt( | 					Code check_n_grow = untyped_str( | ||||||
| 						"\t"	"if ( header.Capacity < new_num )" | 							"if ( header.Capacity < new_num )" | ||||||
| 						"\n\t\t"	"if ( ! grow( new_num) )" | 						"\n"	"if ( ! grow( new_num) )" | ||||||
| 						"\n\t\t\t"		"return false;" | 						"\n"		"return false;" | ||||||
| 					); | 					); | ||||||
|  |  | ||||||
| 					Code set_n_ret = untyped_fmt( | 					Code set_n_ret = untyped_str( | ||||||
| 						"\t"	"header.Count = new_num;" | 							"header.Count = new_num;" | ||||||
| 						"\n\t"	"return true;" | 						"\n""return true;" | ||||||
| 					); | 					); | ||||||
|  |  | ||||||
| 					body = def_function_body( 3, header, check_n_grow, set_n_ret ); | 					body = def_function_body( 3, header, check_n_grow, set_n_ret ); | ||||||
| @@ -285,40 +308,40 @@ | |||||||
|  |  | ||||||
| 			Code set_capacity; | 			Code set_capacity; | ||||||
| 			{ | 			{ | ||||||
| 				Code param = def_parameters( 1, "capacity", t_uw ); | 				Code param = def_parameters( 1, t_uw, "capacity" ); | ||||||
|  |  | ||||||
| 				Code body; | 				Code body; | ||||||
| 				{ | 				{ | ||||||
| 					Code header = def_variable( "header", ref_header, untyped_fmt("get_header()") ); | 					Code header = def_variable( "header", ref_header, untyped_str("get_header()") ); | ||||||
|  |  | ||||||
| 					Code checks = untyped_fmt( | 					Code checks = untyped_str( | ||||||
| 						"\t"	"if ( capacity == header.Capacity )" | 						"if ( capacity == header.Capacity )" | ||||||
| 						"\n\t\t" "return true;" | 					"\n"	"return true;" | ||||||
| 						"\n" | 					 | ||||||
| 						"\n\t" "if ( capacity < header.Num )" | 						"if ( capacity < header.Num )" | ||||||
| 						"\n\t\t" "header.Num = capacity;" | 					"\n"	"header.Num = capacity;" | ||||||
| 					); | 					); | ||||||
|  |  | ||||||
| 					Code size       = def_variable( "size", t_uw, untyped_fmt("sizeof(Header) + sizeof(type) * capacity")); | 					Code size       = def_variable( "size", t_uw, untyped_str("sizeof(Header) + sizeof(Type) * capacity")); | ||||||
| 					Code new_header = def_variable( "new_header", ptr_header, untyped_fmt("rcast( Header*, alloc( header.Allocator, size ));")); | 					Code new_header = def_variable( "new_header", ptr_header, untyped_str("rcast( Header*, alloc( header.Allocator, size ));")); | ||||||
|  |  | ||||||
| 					Code check_n_move = untyped_fmt( | 					Code check_n_move = untyped_str( | ||||||
| 						"\t""if ( new_header == nullptr )" | 							"if ( new_header == nullptr )" | ||||||
| 						"\n\t\t""return false;" | 					"\n"		"return false;" | ||||||
| 					"\n" | 					"\n" | ||||||
| 						"\n\t""memmove( new_header, & header, sizeof(Header) + sizeof(type) * header.Num );" | 					"\n"	"memmove( new_header, & header, sizeof(Header) + sizeof(Type) * header.Num );" | ||||||
| 					); | 					); | ||||||
|  |  | ||||||
| 					Code set_free_ret = untyped_fmt( | 					Code set_free_ret = untyped_str( | ||||||
| 						"\t"	"new_header->Allocator = header.Allocator;" | 							"new_header->Allocator = header.Allocator;" | ||||||
| 						"\n\t"	"new_header->Num       = header.Num;" | 					"\n"	"new_header->Num       = header.Num;" | ||||||
| 						"\n\t"	"new_header->Capacity  = header.Capacity;" | 					"\n"	"new_header->Capacity  = header.Capacity;" | ||||||
| 					"\n" | 					"\n" | ||||||
| 						"\n\t"	"zpl_free( header );" | 					"\n"	"zpl_free( header );" | ||||||
| 					"\n" | 					"\n" | ||||||
| 						"\n\t"	"*Data = new_header + 1;" | 					"\n"	"*Data = new_header + 1;" | ||||||
| 					"\n" | 					"\n" | ||||||
| 						"\n\t"	"return true;" | 					"\n"	"return true;" | ||||||
| 					);				 | 					);				 | ||||||
|  |  | ||||||
| 					body = def_function_body( 6, header, checks, size, new_header, check_n_move, set_free_ret ); | 					body = def_function_body( 6, header, checks, size, new_header, check_n_move, set_free_ret ); | ||||||
| @@ -327,6 +350,8 @@ | |||||||
| 				set_capacity = def_function( "set_capacity", UnusedCode, param, t_bool, body ); | 				set_capacity = def_function( "set_capacity", UnusedCode, param, t_bool, body ); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | 			string name = bprintf( "Array_%s", type_str ); | ||||||
|  |  | ||||||
| 			Code body = def_struct_body( 15 | 			Code body = def_struct_body( 15 | ||||||
| 				, using_type | 				, using_type | ||||||
| 				, data | 				, data | ||||||
| @@ -348,6 +373,282 @@ | |||||||
|  |  | ||||||
| 			array_def = def_struct( name, body, parent ); | 			array_def = def_struct( name, body, parent ); | ||||||
| 		} | 		} | ||||||
|  | 	#else | ||||||
|  | 		type( t_uw, uw ); | ||||||
|  | 		type( t_sw, sw ); | ||||||
|  | 		type( t_bool, bool ); | ||||||
|  | 		type( t_allocator, allocator ); | ||||||
|  | 		type( t_void, void ); | ||||||
|  | 		 | ||||||
|  | 		value( v_nullptr, nullptr ); | ||||||
|  |  | ||||||
|  | 		specifiers( spec_ct, Specifier::Constexpr ); | ||||||
|  | 		specifiers( spec_inline, Specifier::Inline ); | ||||||
|  |  | ||||||
|  | 		type_fmt( type, type_str, __); | ||||||
|  | 		type_fmt( ptr_type, "%s*", type_str ); | ||||||
|  | 		type_fmt( ref_type, "%&", type_str ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		// From ArrayBase | ||||||
|  | 			type( t_header, Header ); | ||||||
|  | 			type( ptr_header, Header* ); | ||||||
|  | 			type( ref_header, Header& ); | ||||||
|  |  | ||||||
|  | 		def( array_def ) | ||||||
|  | 		{ | ||||||
|  | 			using( Type, type ); | ||||||
|  | 			var( Data, ptr_type, __, __ ); | ||||||
|  |  | ||||||
|  | 			def( init ) | ||||||
|  | 			{ | ||||||
|  | 				Code body = function_body( untyped_str("return init_reserve( mem_handler, grow_formula(0) );" )); | ||||||
|  |  | ||||||
|  | 				function( init, __, t_bool, params( t_allocator, "mem_handler" ), body ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			def( init_reserve ) | ||||||
|  | 			{ | ||||||
|  | 				def( body ) | ||||||
|  | 				{ | ||||||
|  | 					var(header, ptr_header, untyped_str("rcast( Header*, alloc( mem_handler, sizeof(Header) + sizeof(Type) + capacity))" ), __); | ||||||
|  |  | ||||||
|  | 					Code null_check = untyped_str( | ||||||
|  | 							"if (header == nullptr)" | ||||||
|  | 						"\n"	"return false;" | ||||||
|  | 					); | ||||||
|  |  | ||||||
|  | 					Code header_init = untyped_str( | ||||||
|  | 							"header->Num       = 0;" | ||||||
|  | 						"\n""header->Capacity  = capacity;" | ||||||
|  | 						"\n""header->Allocator = mem_handler;" | ||||||
|  | 					); | ||||||
|  |  | ||||||
|  | 					Code assign_data = untyped_str( "Data = rcast( Type*, header + 1 );" ); | ||||||
|  | 					Code ret_true    = untyped_str( "return true" ); | ||||||
|  |  | ||||||
|  | 					Code body = function_body( header, null_check, header_init, assign_data, ret_true ); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				function( init_reserve, __, t_bool, params( ref_type, "mem_handler" ) , body); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			def( free ) | ||||||
|  | 			{ | ||||||
|  | 				Code body = untyped_str(  | ||||||
|  | 						"Header& header = get_header();" | ||||||
|  | 					"\n""free( header.Allocator, & get_header() );" | ||||||
|  | 				); | ||||||
|  |  | ||||||
|  | 				function( free, __, t_void, __, body ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			def( append ) | ||||||
|  | 			{ | ||||||
|  | 				def( body ) | ||||||
|  | 				{ | ||||||
|  | 					var( header, ref_header, untyped_str("get_header()"), __ ); | ||||||
|  |  | ||||||
|  | 					Code check_cap = untyped_str( | ||||||
|  | 							"if ( header.Capacity < header.Num + 1 )" | ||||||
|  | 						"\n"	"if ( ! grow(0) )" | ||||||
|  | 						"\n"		"return false;" | ||||||
|  | 					); | ||||||
|  |  | ||||||
|  | 					Code assign = untyped_str( | ||||||
|  | 							 "Data[ header.Num ] = value;" | ||||||
|  | 						"\n" "header.Num++;" | ||||||
|  | 						"\n" | ||||||
|  | 						"\n" "return true;" | ||||||
|  | 					); | ||||||
|  |  | ||||||
|  | 					body = function_body( header, check_cap, assign ); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				function( append, __, t_void, params( type, "value" ), body ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			def( back ); | ||||||
|  | 			{ | ||||||
|  | 				Code body = untyped_str( | ||||||
|  | 					     "Header& header = get_header();" | ||||||
|  | 					"\n" "return data[ header.Num - 1 ];" | ||||||
|  | 				); | ||||||
|  |  | ||||||
|  | 				function( back, __, type, __, body ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			def( clear ) | ||||||
|  | 			function( clear, __, t_void, __, untyped_str("get_header().Num = 0;") ); | ||||||
|  |  | ||||||
|  | 			def( fill ); | ||||||
|  | 			{ | ||||||
|  | 				def( body ) | ||||||
|  | 				{ | ||||||
|  | 					var( header, ref_header, untyped_str("get_header()"), __ ); | ||||||
|  |  | ||||||
|  | 					Code check = untyped_str( | ||||||
|  | 							"if ( begin < 0 || end >= header.Num )" | ||||||
|  | 						"\n"	"fatal( \"Range out of bounds\" );" | ||||||
|  | 					); | ||||||
|  |  | ||||||
|  | 					Code iter = untyped_str( | ||||||
|  | 							"for ( sw index = begin; index < end; index++ )" | ||||||
|  | 						"\n"	"Data[index] = vallue;" | ||||||
|  | 					); | ||||||
|  |  | ||||||
|  | 					function_body( header, check, iter ); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				function( fill, __, t_void, params( t_uw, "begin", t_uw, "end", type, "value" ), body ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			def( get_header ) | ||||||
|  | 			function( get_header, spec_inline, ref_header, __, untyped_str("return pcast( Header, Data - 1);") ); | ||||||
|  |  | ||||||
|  | 			def( grow ) | ||||||
|  | 			{ | ||||||
|  | 				def( body ) | ||||||
|  | 				{ | ||||||
|  | 					var( header, ref_header, untyped_str("get_header()"), __ ); | ||||||
|  | 					var( new_capacity, t_uw, untyped_str("grow_formula( header.Capacity)"), __); | ||||||
|  |  | ||||||
|  | 					Code check_n_set = untyped_str( | ||||||
|  | 						"if ( new_capacity < min_capacity )" | ||||||
|  | 							"new_capacity = min_capacity;" | ||||||
|  | 					); | ||||||
|  |  | ||||||
|  | 					Code ret = untyped_str( "return set_capacity( new_capacity );" ); | ||||||
|  |  | ||||||
|  | 					body = function_body( header, new_capacity, check_n_set, ret ); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				function( grow, __, t_bool, params( t_uw, "min_capacity" ), body ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			def( pop ) | ||||||
|  | 			{ | ||||||
|  | 				def( body ) | ||||||
|  | 				{ | ||||||
|  | 					var( header, ref_header, get_header(), UnusedCode ); | ||||||
|  |  | ||||||
|  | 					Code assertion = untyped_str( "assert( header.Num > 0 );" ); | ||||||
|  | 					Code decrement = untyped_str( "header.Num--; " ); | ||||||
|  |  | ||||||
|  | 					body = function_body( header, assertion, decrement ); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				function( pop, __, t_void, __, body ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			def( reserve ) | ||||||
|  | 			{ | ||||||
|  | 				def( body ) | ||||||
|  | 				{ | ||||||
|  | 					var( header, ref_header, untyped_str("get_header()"), __ ); | ||||||
|  |  | ||||||
|  | 					Code check_n_set = untyped_str( | ||||||
|  | 						"if ( header.Capacity < new_capacity )" | ||||||
|  | 							"return set_capacity( new_capacity );" | ||||||
|  | 					); | ||||||
|  |  | ||||||
|  | 					Code ret = untyped_str("return true"); | ||||||
|  |  | ||||||
|  | 					body = function_body( header, check_n_set, ret ); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				function( reserve, __, t_bool, params( t_uw, "new_capacity" ), body ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			def( resize ) | ||||||
|  | 			{ | ||||||
|  | 				def( body ) | ||||||
|  | 				{ | ||||||
|  | 					var( header, ref_header, untyped_str("get_header()"), __ ); | ||||||
|  |  | ||||||
|  | 					Code check_n_grow = untyped_str( | ||||||
|  | 						"if ( header.Capacity < new_num )" | ||||||
|  | 							"if ( ! grow( new_num) )" | ||||||
|  | 								"return false;" | ||||||
|  | 					); | ||||||
|  |  | ||||||
|  | 					Code set_n_ret = untyped_str( | ||||||
|  | 						"header.Count = new_num;" | ||||||
|  | 						"return true;" | ||||||
|  | 					); | ||||||
|  |  | ||||||
|  | 					body = function_body( header, check_n_grow, set_n_ret ); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				function( resize, __, t_bool, params( t_uw, "new_num" ), body ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			def( set_capacity ) | ||||||
|  | 			{ | ||||||
|  | 				def( body ) | ||||||
|  | 				{ | ||||||
|  | 					var( header, ref_header, untyped_str("get_header()"), __ ); | ||||||
|  |  | ||||||
|  | 					Code checks = untyped_str( | ||||||
|  | 						"if ( capacity == header.Capacity )" | ||||||
|  | 							"return true;" | ||||||
|  | 					"\n\n" | ||||||
|  | 						"if ( capacity < header.Num )" | ||||||
|  | 							"header.Num = capacity;" | ||||||
|  | 					); | ||||||
|  |  | ||||||
|  | 					var( size,       t_uw,       untyped_str("sizeof(Header) + sizeof(Type) * capacity"), __ ); | ||||||
|  | 					var( new_header, ptr_header, untyped_str("rcast( Header*, alloc( header.Allocator, size ))"), __ ); | ||||||
|  |  | ||||||
|  | 					Code check_n_move = untyped_str( | ||||||
|  | 						"if ( new_header == nullptr )" | ||||||
|  | 							"return false;" | ||||||
|  | 					"\n\n" | ||||||
|  | 						"memmove( new_header, & header, sizeof(Header) + sizeof(Type) * header.Num );" | ||||||
|  | 					); | ||||||
|  |  | ||||||
|  | 					Code set_free_ret = untyped_str( | ||||||
|  | 						"new_header->Allocator = header.Allocator;" | ||||||
|  | 						"new_header->Num       = header.Num;" | ||||||
|  | 						"new_header->Capacity  = header.Capacity;" | ||||||
|  | 					"\n\n" | ||||||
|  | 						"zpl_free( header );" | ||||||
|  | 					"\n\n" | ||||||
|  | 						"*Data = new_header + 1;" | ||||||
|  | 					"\n\n" | ||||||
|  | 						"return true;" | ||||||
|  | 					);				 | ||||||
|  |  | ||||||
|  | 					body = function_body( header, checks, size, new_header, check_n_move, set_free_ret ); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				function( set_capacity, __, t_bool, params( t_uw, "capacity" ), body ); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			char const* name = bprintf( "Array_%s", type_str ); | ||||||
|  |  | ||||||
|  | 			Code body = struct_body( | ||||||
|  | 				  Type  | ||||||
|  | 				, Data | ||||||
|  |  | ||||||
|  | 				, init | ||||||
|  | 				, init_reserve | ||||||
|  | 				, append | ||||||
|  | 				, back | ||||||
|  | 				, clear | ||||||
|  | 				, fill | ||||||
|  | 				, free | ||||||
|  | 				, get_header | ||||||
|  | 				, grow | ||||||
|  | 				, pop | ||||||
|  | 				, reserve | ||||||
|  | 				, resize | ||||||
|  | 				, set_capacity | ||||||
|  | 			); | ||||||
|  |  | ||||||
|  | 			array_def = def_struct( name, body, parent ); | ||||||
|  | 		} | ||||||
|  | 	#endif | ||||||
|  |  | ||||||
| 		return array_def; | 		return array_def; | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -22,21 +22,27 @@ | |||||||
| 	{ | 	{ | ||||||
| 		Code integral_type = def_type( type ); | 		Code integral_type = def_type( type ); | ||||||
|  |  | ||||||
|  | 	#ifndef GEN_DEFINE_DSL | ||||||
| 		string name = string_sprintf( g_allocator, (char*)sprintf_buf, ZPL_PRINTF_MAXLEN, "square", type ); | 		string name = string_sprintf( g_allocator, (char*)sprintf_buf, ZPL_PRINTF_MAXLEN, "square", type ); | ||||||
|  |  | ||||||
| 		Code result; | 		Code square; | ||||||
| 		{ | 		{ | ||||||
| 			Code params     = def_parameters( 1, "value", integral_type ); | 			Code params     = def_parameters( 1, integral_type, "value" ); | ||||||
| 			Code specifiers = def_specifiers( 1, Specifier::Inline ); | 			Code specifiers = def_specifiers( 1, Specifier::Inline ); | ||||||
| 			Code ret_stmt   = untyped_fmt( "\treturn value * value;" ); | 			Code ret_stmt   = untyped_fmt( "return value * value;" ); | ||||||
|  |  | ||||||
| 			result = def_function( name, specifiers, params, integral_type, ret_stmt ); | 			square = def_function( name, specifiers, params, integral_type, ret_stmt ); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if ( ! result ) | 	#else  | ||||||
|  | 		def( square ) | ||||||
|  | 		function( square, __, integral_type, params( integral_type, "value" ), untyped_str("return value * value") ); | ||||||
|  | 	#endif | ||||||
|  | 	 | ||||||
|  | 		if ( ! square ) | ||||||
| 			fatal( "Failed to generate square function for: %s", type ); | 			fatal( "Failed to generate square function for: %s", type ); | ||||||
|  |  | ||||||
| 		return result; | 		return square; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	u32 gen_math() | 	u32 gen_math() | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| #include "Bloat.cpp" | #include "Bloat.cpp" | ||||||
| #include "math.hpp" | #include "math.hpp" | ||||||
|  | #include "Array.hpp" | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifdef gen_time | #ifdef gen_time | ||||||
| @@ -12,9 +13,11 @@ int gen_main() | |||||||
| 	zpl_printf("\nPress any key after attaching to process\n"); | 	zpl_printf("\nPress any key after attaching to process\n"); | ||||||
| 	getchar(); | 	getchar(); | ||||||
|  |  | ||||||
| 	gen::init() | 	gen::init(); | ||||||
|  |  | ||||||
| 	int result = gen_math(); | 	int  | ||||||
|  | 	result = gen_math(); | ||||||
|  | 	result = gen_array_file(); | ||||||
|  |  | ||||||
| 	Memory::cleanup(); | 	Memory::cleanup(); | ||||||
| 	return result; | 	return result; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user