mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-10-30 14:30:53 -07:00 
			
		
		
		
	Compare commits
	
		
			24 Commits
		
	
	
		
			v0.19-Alph
			...
			9e88cb8724
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 9e88cb8724 | |||
| f61c1c560d | |||
| 8ef982003a | |||
| 31691b1466 | |||
| ed0c0422ad | |||
| e5acac1d18 | |||
| c7b072266f | |||
| a96d03eaed | |||
| 0b4ccac8f9 | |||
| 31a3609b28 | |||
| fbdb870986 | |||
| 6d04165b96 | |||
| cc245cc263 | |||
| 06deb1e836 | |||
| 5527a27f7b | |||
| a67fdef20a | |||
| 056a5863b8 | |||
| 79eb5f1f76 | |||
| c6cb583518 | |||
| 34eec66f35 | |||
| 4137ebfbd8 | |||
| 5958dd2055 | |||
| 163ad0a511 | |||
| e3c2a577ba | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -31,3 +31,4 @@ project/auxillary/vis_ast/dependencies/temp | ||||
| test/gen/original | ||||
| singleheader/gen/scratch.hpp | ||||
| test/gen/scratch.cpp | ||||
| gen_c_library/gen | ||||
|   | ||||
							
								
								
									
										5
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @@ -37,7 +37,10 @@ | ||||
| 		"propidl.h": "c", | ||||
| 		"android_native_app_glue.h": "c", | ||||
| 		"raylib.h": "c", | ||||
| 		"*.m": "cpp" | ||||
| 		"*.m": "cpp", | ||||
| 		"atomic": "cpp", | ||||
| 		"gen.h": "c", | ||||
| 		"string_ops.hpp": "c" | ||||
| 	}, | ||||
| 	"C_Cpp.intelliSenseEngineFallback": "disabled", | ||||
| 	"mesonbuild.configureOnOpen": true, | ||||
|   | ||||
							
								
								
									
										358
									
								
								gen_c_library/c_library.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										358
									
								
								gen_c_library/c_library.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,358 @@ | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_SUPPORT_CPP_MEMBER_FEATURES 1 | ||||
| #include "../project/gen.cpp" | ||||
|  | ||||
| #include "helpers/push_ignores.inline.hpp" | ||||
| #include "helpers/helper.hpp" | ||||
|  | ||||
| GEN_NS_BEGIN | ||||
| #include "dependencies/parsing.cpp" | ||||
| GEN_NS_END | ||||
|  | ||||
| #include "auxillary/builder.hpp" | ||||
| #include "auxillary/builder.cpp" | ||||
| #include "auxillary/scanner.hpp" | ||||
|  | ||||
| #include <cstdlib>   // for system() | ||||
|  | ||||
| #include "components/memory.fixed_arena.hpp" | ||||
| #include "components/misc.hpp" | ||||
| #include "components/containers.array.hpp" | ||||
| #include "components/containers.hashtable.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| constexpr char const* generation_notice = | ||||
| "// This file was generated automatially by gencpp's c_library.cpp" | ||||
| "(See: https://github.com/Ed94/gencpp)\n\n"; | ||||
|  | ||||
| constexpr StrC roll_own_dependencies_guard_start = txt(R"( | ||||
| //! If its desired to roll your own dependencies, define GEN_ROLL_OWN_DEPENDENCIES before including this file. | ||||
| // Dependencies are derived from the c-zpl library: https://github.com/zpl-c/zpl | ||||
| #ifndef GEN_ROLL_OWN_DEPENDENCIES | ||||
| )"); | ||||
|  | ||||
| constexpr StrC roll_own_dependencies_guard_end = txt(R"( | ||||
| // GEN_ROLL_OWN_DEPENDENCIES | ||||
| #endif | ||||
| )"); | ||||
|  | ||||
| constexpr StrC implementation_guard_start = txt(R"( | ||||
| #pragma region GENCPP IMPLEMENTATION GUARD | ||||
| #if defined(GEN_IMPLEMENTATION) && ! defined(GEN_IMPLEMENTED) | ||||
| #	define GEN_IMPLEMENTED | ||||
| )"); | ||||
|  | ||||
| constexpr StrC implementation_guard_end = txt(R"( | ||||
| #endif | ||||
| #pragma endregion GENCPP IMPLEMENTATION GUARD | ||||
| )"); | ||||
|  | ||||
| void format_file( char const* path ) | ||||
| { | ||||
| 	String resolved_path = String::make(GlobalAllocator, to_str(path)); | ||||
|  | ||||
| 	String style_arg = String::make(GlobalAllocator, txt("-style=file:")); | ||||
| 	style_arg.append("../scripts/.clang-format "); | ||||
|  | ||||
| 	// Need to execute clang format on the generated file to get it to match the original. | ||||
| 	#define clang_format      "clang-format " | ||||
| 	#define cf_format_inplace "-i " | ||||
| 	#define cf_verbose        "-verbose " | ||||
| 	String command = String::make( GlobalAllocator, clang_format ); | ||||
| 	command.append( cf_format_inplace ); | ||||
| 	command.append( cf_verbose ); | ||||
| 	command.append( style_arg ); | ||||
| 	command.append( resolved_path ); | ||||
| 		log_fmt("\tRunning clang-format on file:\n"); | ||||
| 		system( command ); | ||||
| 		log_fmt("\tclang-format finished reformatting.\n"); | ||||
| 	#undef cf_cmd | ||||
| 	#undef cf_format_inplace | ||||
| 	#undef cf_style | ||||
| 	#undef cf_verbse | ||||
| } | ||||
|  | ||||
| Code dump_to_scratch_and_retireve( Code code ) | ||||
| { | ||||
| 	Builder ecode_file_temp = Builder::open("gen/scratch.hpp"); | ||||
| 	ecode_file_temp.print(code); | ||||
| 	ecode_file_temp.write(); | ||||
| 	format_file("gen/scratch.hpp"); | ||||
| 	Code result = scan_file( "gen/scratch.hpp" ); | ||||
| 	remove("gen/scratch.hpp"); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| CodeBody parse_file( const char* path ) | ||||
| { | ||||
| 	FileContents file = file_read_contents( GlobalAllocator, true, path ); | ||||
| 	CodeBody     code = parse_global_body( { file.size, (char const*)file.data } ); | ||||
| 	log_fmt("\nParsed: %s\n", path); | ||||
| 	return code; | ||||
| } | ||||
|  | ||||
| int gen_main() | ||||
| { | ||||
| #define project_dir "../project/" | ||||
| 	gen::init(); | ||||
|  | ||||
| 	Code push_ignores           = scan_file( project_dir "helpers/push_ignores.inline.hpp" ); | ||||
| 	Code pop_ignores            = scan_file( project_dir "helpers/pop_ignores.inline.hpp" ); | ||||
| 	Code c_library_header_start = scan_file( "components/header_start.hpp" ); | ||||
|  | ||||
| 	Builder | ||||
| 	header = Builder::open( "gen/gen.h" ); | ||||
| 	header.print_fmt( generation_notice ); | ||||
| 	header.print_fmt("#pragma once\n\n"); | ||||
| 	header.print( push_ignores ); | ||||
|  | ||||
| 	// Headers | ||||
| 	{ | ||||
| 		header.print( c_library_header_start ); | ||||
|  | ||||
| 		Code platform     = scan_file( project_dir "dependencies/platform.hpp" ); | ||||
| 		Code macros       = scan_file( project_dir "dependencies/macros.hpp" ); | ||||
| 		Code basic_types  = scan_file( project_dir "dependencies/basic_types.hpp" ); | ||||
| 		Code debug        = scan_file( project_dir "dependencies/debug.hpp" ); | ||||
|  | ||||
| 		header.print_fmt( roll_own_dependencies_guard_start ); | ||||
| 		header.print( platform ); | ||||
| 		header.print_fmt( "\nGEN_NS_BEGIN\n" ); | ||||
|  | ||||
| 		header.print( macros ); | ||||
| 		header.print( basic_types ); | ||||
| 		header.print( debug ); | ||||
|  | ||||
| 		CodeBody parsed_memory = parse_file( project_dir "dependencies/memory.hpp" ); | ||||
| 		CodeBody memory        = def_body(ECode::Global_Body); | ||||
| 		for ( Code entry = parsed_memory.begin(); entry != parsed_memory.end(); ++ entry ) | ||||
| 		{ | ||||
| 			switch (entry->Type) | ||||
| 			{ | ||||
| 				case ECode::Using: | ||||
| 				{ | ||||
| 					log_fmt("REPLACE THIS MANUALLY: %S\n", entry->Name); | ||||
| 					CodeUsing   using_ver   = entry.cast<CodeUsing>(); | ||||
| 					CodeTypedef typedef_ver = def_typedef(using_ver->Name, using_ver->UnderlyingType); | ||||
|  | ||||
| 					memory.append(typedef_ver); | ||||
| 				} | ||||
| 				break; | ||||
| 				case ECode::Function: | ||||
| 				{ | ||||
| 					CodeFn fn = entry.cast<CodeFn>(); | ||||
| 					s32 constexpr_found = fn->Specs.remove( ESpecifier::Constexpr ); | ||||
| 					if (constexpr_found > -1) { | ||||
| 						log_fmt("Found constexpr: %S\n", entry->to_string()); | ||||
| 						fn->Specs.append(ESpecifier::Inline); | ||||
| 					} | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				case ECode::Template: | ||||
| 				{ | ||||
| 					CodeTemplate tmpl = entry.cast<CodeTemplate>(); | ||||
| 					if ( tmpl->Declaration->Name.contains(txt("swap"))) | ||||
| 					{ | ||||
| 						CodeBody macro_swap = parse_global_body( txt(R"( | ||||
| #define swap( a, b )              \ | ||||
| 	do                            \ | ||||
| 	{                             \ | ||||
| 		typeof( a ) temp = ( a ); \ | ||||
| 		( a )            = ( b ); \ | ||||
| 		( b )            = temp;  \ | ||||
| 	} while ( 0 ) | ||||
| )" | ||||
| 						)); | ||||
| 						memory.append(macro_swap); | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 				case ECode::Class: | ||||
| 				case ECode::Struct: | ||||
| 				{ | ||||
| 					CodeBody body     = entry->Body->operator CodeBody(); | ||||
| 					CodeBody new_body = def_body( entry->Body->Type ); | ||||
| 					for ( Code body_entry = body.begin(); body_entry != body.end(); ++ body_entry ) switch | ||||
| 					(body_entry->Type) { | ||||
| 						case ECode::Preprocess_If: | ||||
| 						{ | ||||
| 							ignore_preprocess_cond_block(txt("GEN_SUPPORT_CPP_MEMBER_FEATURES"), body_entry, body ); | ||||
| 						} | ||||
| 						break; | ||||
|  | ||||
| 						default: | ||||
| 							new_body.append(body_entry); | ||||
| 						break; | ||||
| 					} | ||||
|  | ||||
| 					entry->Body = rcast(AST*, new_body.ast); | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				case ECode::Preprocess_If: | ||||
| 				{ | ||||
| 					b32 found = ignore_preprocess_cond_block(txt("GEN_SUPPORT_CPP_MEMBER_FEATURES"), entry, parsed_memory ); | ||||
| 					if (found) break; | ||||
|  | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				case ECode::Preprocess_IfDef: | ||||
| 				{ | ||||
| 					b32 found = ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, parsed_memory ); | ||||
| 					if (found) break; | ||||
|  | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				case ECode::Preprocess_Pragma: | ||||
| 				{ | ||||
| 					b32 found = swap_pragma_region_implementation( txt("FixedArena"), gen_fixed_arenas, entry, memory); | ||||
| 					if (found) break; | ||||
|  | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				default: { | ||||
| 					memory.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		header.print( dump_to_scratch_and_retireve(memory) ); | ||||
|  | ||||
| 		Code string_ops = scan_file( project_dir "dependencies/string_ops.hpp" ); | ||||
| 		header.print( string_ops ); | ||||
|  | ||||
| 		CodeBody printing_parsed = parse_file( project_dir "dependencies/printing.hpp" ); | ||||
| 		CodeBody printing        = def_body(ECode::Global_Body); | ||||
| 		for ( Code entry = printing_parsed.begin(); entry != printing_parsed.end(); ++ entry ) | ||||
| 		{ | ||||
| 			switch (entry->Type) | ||||
| 			{ | ||||
| 				case ECode::Preprocess_IfDef: | ||||
| 				{ | ||||
| 					b32 found = ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, printing_parsed ); | ||||
| 					if (found) break; | ||||
|  | ||||
| 					printing.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				case ECode::Variable: | ||||
| 				{ | ||||
| 					if (contains(entry->Name, txt("Msg_Invalid_Value"))) | ||||
| 					{ | ||||
| 						CodeDefine define = def_define(entry->Name, entry->Value->Content); | ||||
| 						printing.append(define); | ||||
| 						continue; | ||||
| 					} | ||||
| 					printing.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
| 				default: | ||||
| 					printing.append(entry); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		header.print(dump_to_scratch_and_retireve(printing)); | ||||
|  | ||||
| 		CodeBody containers = def_body(ECode::Global_Body); | ||||
| 		{ | ||||
| 			containers.append( def_pragma(code(region Containers))); | ||||
|  | ||||
| 			containers.append( gen_array_base() ); | ||||
| 			containers.append( gen_hashtable_base() ); | ||||
|  | ||||
| 			containers.append( def_pragma(code(endregion Containers))); | ||||
| 		} | ||||
| 		header.print(fmt_newline); | ||||
| 		header.print(dump_to_scratch_and_retireve(containers)); | ||||
|  | ||||
| 		Code hashing = scan_file( project_dir "dependencies/hashing.hpp" ); | ||||
| 		header.print( hashing ); | ||||
|  | ||||
| 		CodeBody parsed_strings = parse_file( project_dir "dependencies/strings.hpp" ); | ||||
| 		CodeBody strings        = def_body(ECode::Global_Body); | ||||
| 		for ( Code entry = parsed_strings.begin(); entry != parsed_strings.end(); ++ entry ) | ||||
| 		{ | ||||
| 			switch (entry->Type) | ||||
| 			{ | ||||
| 				case ECode::Preprocess_If: | ||||
| 				{ | ||||
| 					ignore_preprocess_cond_block(txt("! GEN_COMPILER_C"), entry, parsed_strings); | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 				case ECode::Preprocess_IfDef: | ||||
| 				{ | ||||
| 					ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, parsed_strings ); | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 				case ECode::Struct_Fwd: | ||||
| 				{ | ||||
| 					if ( entry->Name.is_equal(txt("String")) ) | ||||
| 					{ | ||||
| 						CodeTypedef c_def = parse_typedef(code( typedef Type* String; )); | ||||
| 						strings.append(c_def); | ||||
| 						strings.append(fmt_newline); | ||||
| 						++ entry; | ||||
| 						continue; | ||||
| 					} | ||||
| 					strings.append(entry); | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 				default: | ||||
| 					strings.append(entry); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		header.print(dump_to_scratch_and_retireve(strings)); | ||||
|  | ||||
| 		Code filesystem = scan_file( project_dir "dependencies/filesystem.hpp" ); | ||||
| 		Code timing = scan_file( project_dir "dependencies/timing.hpp" ); | ||||
| 		header.print( filesystem ); | ||||
| 		header.print( timing ); | ||||
|  | ||||
| 		header.print_fmt( "\nGEN_NS_END\n" ); | ||||
| 		header.print_fmt( roll_own_dependencies_guard_end ); | ||||
|  | ||||
| 		Code types      = scan_file( project_dir "components/types.hpp" ); | ||||
| 		Code ast        = scan_file( project_dir "components/ast.hpp" ); | ||||
| 		Code ast_types  = scan_file( project_dir "components/ast_types.hpp" ); | ||||
| 		Code code_types = scan_file( project_dir "components/code_types.hpp" ); | ||||
| 		Code interface  = scan_file( project_dir "components/interface.hpp" ); | ||||
| 		Code inlines 	= scan_file( project_dir "components/inlines.hpp" ); | ||||
| 		Code header_end = scan_file( project_dir "components/header_end.hpp" ); | ||||
|  | ||||
| 		CodeBody ecode       = gen_ecode     ( project_dir "enums/ECode.csv" ); | ||||
| 		CodeBody eoperator   = gen_eoperator ( project_dir "enums/EOperator.csv" ); | ||||
| 		CodeBody especifier  = gen_especifier( project_dir "enums/ESpecifier.csv" ); | ||||
| 		CodeBody ast_inlines = gen_ast_inlines(); | ||||
|  | ||||
| 		header.print_fmt("#pragma region Types\n"); | ||||
| 		header.print( types ); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print( dump_to_scratch_and_retireve( ecode )); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print( dump_to_scratch_and_retireve( eoperator )); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print( dump_to_scratch_and_retireve( especifier )); | ||||
| 		header.print( fmt_newline ); | ||||
| 		header.print_fmt("#pragma endregion Types\n\n"); | ||||
| 	} | ||||
|  | ||||
| 	header.print( pop_ignores ); | ||||
| 	header.write(); | ||||
|  | ||||
| 	// format_file( "gen/gen.h" ); | ||||
|  | ||||
| 	gen::deinit(); | ||||
| 	return 0; | ||||
| #undef project_dir | ||||
| } | ||||
							
								
								
									
										295
									
								
								gen_c_library/components/containers.array.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								gen_c_library/components/containers.array.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,295 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "../project/gen.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| CodeBody gen_array_base() | ||||
| { | ||||
| 	CodeTypedef td_header = parse_typedef( code( typedef struct ArrayHeader ArrayHeader; )); | ||||
| 	CodeStruct  header    = parse_struct( code( | ||||
| 		struct ArrayHeader | ||||
| 		{ | ||||
| 			AllocatorInfo Allocator; | ||||
| 			usize         Capacity; | ||||
| 			usize         Num; | ||||
| 		}; | ||||
| 	)); | ||||
|  | ||||
| 	// Code grow_formula = untyped_str( txt( "#define gen_array_grow_formula( value ) ( 2 * value + 8 )\n" )); | ||||
| 	Code get_header   = untyped_str( txt( "#define array_get_header( Type, self ) ( (ArrayHeader*)( self ) - 1)\n" )); | ||||
|  | ||||
| 	return def_global_body( args( fmt_newline, td_header, header, get_header, fmt_newline ) ); | ||||
| }; | ||||
|  | ||||
| CodeBody gen_array( StrC type, StrC array_name ) | ||||
| { | ||||
| 	String array_type = String::fmt_buf( GlobalAllocator, "%.*s", array_name.Len, array_name.Ptr ); | ||||
| 	String fn         = String::fmt_buf( GlobalAllocator, "%.*s", array_name.Len, array_name.Ptr ); | ||||
| 	str_to_lower(fn.Data); | ||||
|  | ||||
| #pragma push_macro( "GEN_ASSERT" ) | ||||
| #undef GEN_ASSERT | ||||
| 	CodeBody result = parse_global_body( token_fmt( "array_type", (StrC)array_type, "fn", (StrC)fn, "type", (StrC)type | ||||
| 	, stringize( | ||||
| 		typedef <type>* <array_type>; | ||||
|  | ||||
| 		<array_type> <fn>_init           ( AllocatorInfo allocator ); | ||||
| 		<array_type> <fn>_init_reserve   ( AllocatorInfo allocator, usize capacity ); | ||||
| 		bool         <fn>_append         ( <array_type>*  self, <type> value ); | ||||
| 		bool         <fn>_append_items   ( <array_type>*  self, <type>* items, usize item_num ); | ||||
| 		bool         <fn>_append_at      ( <array_type>*  self, <type> item, usize idx ); | ||||
| 		bool         <fn>_append_items_at( <array_type>*  self, <type>* items, usize item_num, usize idx ); | ||||
| 		<type>*      <fn>_back           ( <array_type>  self ); | ||||
| 		void         <fn>_clear          ( <array_type>  self ); | ||||
| 		bool         <fn>_fill		     ( <array_type>  self, usize begin, usize end, <type> value ); | ||||
| 		void         <fn>_free           ( <array_type>  self ); | ||||
| 		bool         <fn>_grow           ( <array_type>* self, usize min_capacity ); | ||||
| 		usize        <fn>_num            ( <array_type>  self ); | ||||
| 		<type>       <fn>_pop 	         ( <array_type>  self ); | ||||
| 		bool         <fn>_reserve        ( <array_type>* self, usize new_capacity ); | ||||
| 		bool         <fn>_resize         ( <array_type>* self, usize num ); | ||||
| 		bool         <fn>_set_capacity   ( <array_type>* self, usize new_capacity ); | ||||
|  | ||||
| 		<array_type> <fn>_init( AllocatorInfo allocator ) | ||||
| 		{ | ||||
| 			return <fn>_init_reserve( allocator, array_grow_formula( 0 ) ); | ||||
| 		} | ||||
|  | ||||
| 		<array_type> <fn>_init_reserve( AllocatorInfo allocator, usize capacity ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = cast(ArrayHeader*, alloc( allocator, sizeof(ArrayHeader) + sizeof(<type>) * capacity ) ); | ||||
|  | ||||
| 			if ( header == NULL ) | ||||
| 				return NULL; | ||||
|  | ||||
| 			header->Allocator = allocator; | ||||
| 			header->Capacity  = capacity; | ||||
| 			header->Num       = 0; | ||||
|  | ||||
| 			return cast( <type>*, header + 1 ); | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_append( <array_type>* self, <type> value ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = get_header( * self ); | ||||
|  | ||||
| 			if ( header->Num == header->Capacity ) | ||||
| 			{ | ||||
| 				if ( ! <fn>_grow( self, header->Capacity)) | ||||
| 					return false; | ||||
|  | ||||
| 				header = get_header( * self ); | ||||
| 			} | ||||
|  | ||||
| 			(* self)[ header->Num ] = value; | ||||
| 			header->Num++; | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_append_items( <array_type>* self, <type>* items, usize item_num ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = get_header( * self ); | ||||
|  | ||||
| 			if ( header->Num + item_num > header->Capacity ) | ||||
| 			{ | ||||
| 				if ( ! <fn>_grow( self, header->Capacity + item_num )) | ||||
| 					return false; | ||||
|  | ||||
| 				header = get_header( * self ); | ||||
| 			} | ||||
|  | ||||
| 			mem_copy( (* self) + header->Num, items, sizeof(<type>) * item_num ); | ||||
| 			header->Num += item_num; | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_append_at( <array_type>* self, <type> item, usize idx ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = get_header( * self ); | ||||
|  | ||||
| 			if ( idx >= header->Num ) | ||||
| 				idx = header->Num - 1; | ||||
|  | ||||
| 			if ( idx < 0 ) | ||||
| 				idx = 0; | ||||
|  | ||||
| 			if ( header->Capacity < header->Num + 1 ) | ||||
| 			{ | ||||
| 				if ( ! <fn>_grow( self, header->Capacity + 1 ) ) | ||||
| 					return false; | ||||
|  | ||||
| 				header = get_header( * self ); | ||||
| 			} | ||||
|  | ||||
| 			<array_type> target = (* self) + idx; | ||||
|  | ||||
| 			mem_move( target + 1, target, (header->Num - idx) * sizeof(<type>) ); | ||||
| 			header->Num++; | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_append_items_at( <array_type>* self, <type>* items, usize item_num, usize idx ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = get_header( * self ); | ||||
|  | ||||
| 			if ( idx >= header->Num ) | ||||
| 			{ | ||||
| 				return <fn>_append_items( self, items, item_num ); | ||||
| 			} | ||||
|  | ||||
| 			if ( item_num > header->Capacity ) | ||||
| 			{ | ||||
| 				if ( ! <fn>_grow( self, item_num + header->Capacity ) ) | ||||
| 					return false; | ||||
|  | ||||
| 				header = get_header( * self ); | ||||
| 			} | ||||
|  | ||||
| 			<type>* target = (* self) + idx + item_num; | ||||
| 			<type>* src    = (* self) + idx; | ||||
|  | ||||
| 			mem_move( target, src, (header->Num - idx) * sizeof(<type>) ); | ||||
| 			mem_copy( src, items, item_num * sizeof(<type>) ); | ||||
| 			header->Num += item_num; | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		<type>* <fn>_back( <array_type> self ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = get_header( self ); | ||||
|  | ||||
| 			if ( header->Num == 0 ) | ||||
| 				return NULL; | ||||
|  | ||||
| 			return self + header->Num - 1; | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_clear( <array_type> self ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = get_header( self ); | ||||
| 			header->Num = 0; | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_fill( <array_type> self, usize begin, usize end, <type> value ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = get_header( self ); | ||||
|  | ||||
| 			if ( begin < 0 || end >= header->Num ) | ||||
| 				return false; | ||||
|  | ||||
| 			for ( ssize idx = begin; idx < end; idx ++ ) | ||||
| 				self[ idx ] = value; | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_free( <array_type> self ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = get_header( self ); | ||||
| 			free( header->Allocator, header ); | ||||
| 			self = NULL; | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_grow( <array_type>* self, usize min_capacity ) | ||||
| 		{ | ||||
| 			ArrayHeader* header      = get_header( *self ); | ||||
| 			usize       new_capacity = array_grow_formula( header->Capacity ); | ||||
|  | ||||
| 			if ( new_capacity < min_capacity ) | ||||
| 				new_capacity = min_capacity; | ||||
|  | ||||
| 			return <fn>_set_capacity( self, new_capacity ); | ||||
| 		} | ||||
|  | ||||
| 		usize <fn>_num( <array_type> self ) | ||||
| 		{ | ||||
| 			return get_header(self)->Num; | ||||
| 		} | ||||
|  | ||||
| 		<type> <fn>_pop( <array_type> self ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = get_header( self ); | ||||
| 			GEN_ASSERT( header->Num > 0 ); | ||||
|  | ||||
| 			<type> result = self[ header->Num - 1 ]; | ||||
| 			header->Num--; | ||||
| 			return result; | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_remove_at( <array_type> self, usize idx ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = get_header( self ); | ||||
| 			GEN_ASSERT( idx < header->Num ); | ||||
|  | ||||
| 			mem_move( self + idx, self + idx + 1, sizeof( <type> ) * ( header->Num - idx - 1 ) ); | ||||
| 			header->Num--; | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_reserve( <array_type>* self, usize new_capacity ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = get_header( * self ); | ||||
|  | ||||
| 			if ( header->Capacity < new_capacity ) | ||||
| 				return <fn>_set_capacity( self, new_capacity ); | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_resize( <array_type>* self, usize num ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = get_header( * self ); | ||||
|  | ||||
| 			if ( header->Capacity < num ) | ||||
| 			{ | ||||
| 				if ( ! <fn>_grow( self, num ) ) | ||||
| 					return false; | ||||
|  | ||||
| 				header = get_header( * self ); | ||||
| 			} | ||||
|  | ||||
| 			header->Num = num; | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		bool <fn>_set_capacity( <array_type>* self, usize new_capacity ) | ||||
| 		{ | ||||
| 			ArrayHeader* header = get_header( * self ); | ||||
|  | ||||
| 			if ( new_capacity == header->Capacity ) | ||||
| 				return true; | ||||
|  | ||||
| 			if ( new_capacity < header->Num ) | ||||
| 				header->Num = new_capacity; | ||||
|  | ||||
| 			usize       size       = sizeof( ArrayHeader ) + sizeof( <type> ) * new_capacity; | ||||
| 			ArrayHeader* new_header = cast( ArrayHeader*, alloc( header->Allocator, size )); | ||||
|  | ||||
| 			if ( new_header == NULL ) | ||||
| 				return false; | ||||
|  | ||||
| 			mem_move( new_header, header, sizeof( ArrayHeader ) + sizeof( <type> ) * header->Num ); | ||||
| 			free( header->Allocator, & header ); | ||||
|  | ||||
| 			new_header->Capacity = new_capacity; | ||||
| 			* self = cast( <type>*, new_header + 1 ); | ||||
| 			return true; | ||||
| 		} | ||||
| 	))); | ||||
| #pragma pop_macro( "GEN_ASSERT" ) | ||||
|  | ||||
| 	return def_global_body( args( | ||||
| 		def_pragma( to_str( str_fmt_buf( "region %S", array_type ))), | ||||
| 		fmt_newline, | ||||
| 		result, | ||||
| 		fmt_newline, | ||||
| 		def_pragma( to_str( str_fmt_buf( "endregion %S", array_type ))), | ||||
| 		fmt_newline | ||||
| 	)); | ||||
| }; | ||||
|  | ||||
| // CodeBody gen_ | ||||
							
								
								
									
										354
									
								
								gen_c_library/components/containers.hashtable.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								gen_c_library/components/containers.hashtable.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,354 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "../project/gen.hpp" | ||||
| #include "containers.array.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| CodeBody gen_hashtable_base() | ||||
| { | ||||
| 	return parse_global_body( code( | ||||
| 		typedef struct HT_FindResult HT_FindResult; | ||||
| 		struct HT_FindResult | ||||
| 		{ | ||||
| 			ssize HashIndex; | ||||
| 			ssize PrevIndex; | ||||
| 			ssize EntryIndex; | ||||
| 		}; | ||||
| 	)); | ||||
| } | ||||
|  | ||||
| CodeBody gen_hashtable( StrC type, StrC hashtable_name ) | ||||
| { | ||||
| 	String | ||||
| 	fn = String::make_reserve( GlobalAllocator, hashtable_name.Len + sizeof("gen") ); | ||||
| 	fn.append_fmt( "%.*s", hashtable_name.Len, hashtable_name.Ptr ); | ||||
| 	str_to_lower(fn.Data); | ||||
|  | ||||
| 	String | ||||
| 	tbl_type = String::make_reserve( GlobalAllocator, hashtable_name.Len + sizeof("gen") ); | ||||
| 	tbl_type.append_fmt( "%.*s", hashtable_name.Len, hashtable_name.Ptr ); | ||||
|  | ||||
| 	String name_lower = String::make( GlobalAllocator, hashtable_name ); | ||||
| 	str_to_lower( name_lower.Data ); | ||||
|  | ||||
| 	String hashtable_entry   = String::fmt_buf( GlobalAllocator, "HTE_%.*s",     hashtable_name.Len, hashtable_name.Ptr ); | ||||
| 	String entry_array_name  = String::fmt_buf( GlobalAllocator, "Arr_HTE_%.*s", hashtable_name.Len, hashtable_name.Ptr ); | ||||
| 	String entry_array_fn_ns = String::fmt_buf( GlobalAllocator, "arr_hte_%.*s", name_lower.length(), name_lower.Data ); | ||||
|  | ||||
| 	CodeBody hashtable_types = parse_global_body( token_fmt( | ||||
| 		"type",        (StrC) type, | ||||
| 		"tbl_name",    (StrC) hashtable_name, | ||||
| 		"tbl_type",    (StrC) tbl_type, | ||||
| 	stringize( | ||||
| 		typedef struct HTE_<tbl_name> HTE_<tbl_name>; | ||||
| 		struct HTE_<tbl_name> | ||||
| 		{ | ||||
| 			u64    Key; | ||||
| 			ssize  Next; | ||||
| 			<type> Value; | ||||
| 		}; | ||||
|  | ||||
| 		typedef void (* <tbl_type>_MapProc)    ( <tbl_type> self, u64 key, <type> value ); | ||||
| 		typedef void (* <tbl_type>_MapMutProc) ( <tbl_type> self, u64 key, <type>* value ); | ||||
| 	))); | ||||
|  | ||||
| 	CodeBody entry_array = gen_array( hashtable_entry, entry_array_name ); | ||||
|  | ||||
| #pragma push_macro( "GEN_ASSERT" ) | ||||
| #pragma push_macro( "GEN_ASSERT_NOT_NULL" ) | ||||
| #undef GEN_ASSERT | ||||
| #undef GEN_ASSERT_NOT_NULL | ||||
| 	CodeBody hashtable_def = parse_global_body( token_fmt( | ||||
| 		"type",           (StrC) type, | ||||
| 		"tbl_name",       (StrC) hashtable_name, | ||||
| 		"tbl_type",       (StrC) tbl_type, | ||||
| 		"fn",             (StrC) fn, | ||||
| 		"entry_type",     (StrC) hashtable_entry, | ||||
| 		"array_entry",    (StrC) entry_array_name, | ||||
| 		"fn_array",       (StrC) entry_array_fn_ns, | ||||
| 	stringize( | ||||
| 		typedef struct <tbl_type> <tbl_type>; | ||||
| 		struct <tbl_type> | ||||
| 		{ | ||||
| 			Array_ssize   Hashes; | ||||
| 			<array_entry> Entries; | ||||
| 		}; | ||||
|  | ||||
| 		<tbl_type> <fn>_make        ( AllocatorInfo allocator ); | ||||
| 		<tbl_type> <fn>_make_reserve( AllocatorInfo allocator, ssize num ); | ||||
| 		void       <fn>_clear       ( <tbl_type> self ); | ||||
| 		void       <fn>_destroy     ( <tbl_type> self ); | ||||
| 		<type>*    <fn>_get         ( <tbl_type> self, u64 key ); | ||||
| 		void       <fn>_map         ( <tbl_type> self, <tbl_type>_MapProc map_proc ); | ||||
| 		void       <fn>_map_mut     ( <tbl_type> self, <tbl_type>_MapMutProc map_proc ); | ||||
| 		void       <fn>_grow        ( <tbl_type>* self ); | ||||
| 		void       <fn>_rehash      ( <tbl_type>* self, ssize new_num ); | ||||
| 		void       <fn>_rehash_fast ( <tbl_type> self ); | ||||
| 		void       <fn>_remove      ( <tbl_type> self, u64 key ); | ||||
| 		void       <fn>_remove_entry( <tbl_type> self, ssize idx ); | ||||
| 		void       <fn>_set         ( <tbl_type>* self, u64 key, <type> value ); | ||||
| 		ssize         <fn>_slot        ( <tbl_type> self, u64 key ); | ||||
|  | ||||
| 		ssize            <fn>__add_entry( <tbl_type> self, u64 key ); | ||||
| 		HT_FindResult <fn>__find     ( <tbl_type> self, u64 key ); | ||||
| 		b32           <fn>__full     ( <tbl_type> self ); | ||||
|  | ||||
| 		<tbl_type> <fn>_make( AllocatorInfo allocator ) | ||||
| 		{ | ||||
| 			<tbl_type> | ||||
| 			result        = { NULL, NULL }; | ||||
| 			result.Hashes  = array_ssize_make( allocator ); | ||||
| 			result.Entries = <fn_array>_make( allocator ); | ||||
|  | ||||
| 			return result; | ||||
| 		} | ||||
|  | ||||
| 		<tbl_type> <fn>_make_reserve( AllocatorInfo allocator, ssize num ) | ||||
| 		{ | ||||
| 			<tbl_type> | ||||
| 			result         = { NULL, NULL }; | ||||
| 			result.Hashes  = array_ssize_make_reserve( allocator, num ); | ||||
| 			result.Entries = <fn_array>_make_reserve( allocator, num ); | ||||
|  | ||||
| 			return result; | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_clear( <tbl_type> self ) | ||||
| 		{ | ||||
| 			for ( ssize idx = 0; idx < array_header( self.Hashes )->Num; idx++ ) | ||||
| 				self.Hashes[idx] = -1; | ||||
|  | ||||
| 			array_ssize_clear( self.Hashes ); | ||||
| 			<fn_array>_clear( self.Entries ); | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_destroy( <tbl_type> self ) | ||||
| 		{ | ||||
| 			if ( self.Hashes && self.Entries ) | ||||
| 			{ | ||||
| 				array_ssize_free( self.Hashes ); | ||||
| 				<fn_array>_free( self.Entries ); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		<type>* <fn>_get( <tbl_type> self, u64 key ) | ||||
| 		{ | ||||
| 			ssize idx = <fn>__find( self, key ).EntryIndex; | ||||
| 			if ( idx > 0 ) | ||||
| 				return & self.Entries[idx].Value; | ||||
|  | ||||
| 			return NULL; | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_map( <tbl_type> self, <tbl_type>_MapProc map_proc ) | ||||
| 		{ | ||||
| 			GEN_ASSERT_NOT_NULL( map_proc ); | ||||
|  | ||||
| 			for ( ssize idx = 0; idx < array_header( self.Entries )->Num; idx++ ) | ||||
| 			{ | ||||
| 				map_proc( self, self.Entries[idx].Key, self.Entries[idx].Value ); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_map_mut( <tbl_type> self, <tbl_type>_MapMutProc map_proc ) | ||||
| 		{ | ||||
| 			GEN_ASSERT_NOT_NULL( map_proc ); | ||||
|  | ||||
| 			for ( ssize idx = 0; idx < array_header( self.Entries )->Num; idx++ ) | ||||
| 			{ | ||||
| 				map_proc( self, self.Entries[idx].Key, & self.Entries[idx].Value ); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_grow( <tbl_type>* self ) | ||||
| 		{ | ||||
| 			ssize new_num = array_grow_formula( array_header( self->Entries )->Num ); | ||||
| 			<fn>_rehash( self, new_num ); | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_rehash( <tbl_type>* self, ssize new_num ) | ||||
| 		{ | ||||
| 			ssize idx; | ||||
| 			ssize last_added_index; | ||||
|  | ||||
| 			ArrayHeader* old_hash_header    = array_header( self->Hashes ); | ||||
| 			ArrayHeader* old_entries_header = array_header( self->Entries ); | ||||
|  | ||||
| 			<tbl_type> new_tbl = <fn>_make_reserve( old_hash_header->Allocator, old_hash_header->Num ); | ||||
|  | ||||
| 			ArrayHeader* new_hash_header = array_header( new_tbl.Hashes ); | ||||
|  | ||||
| 			for ( idx = 0; idx < new_hash_header->Num; idx++ ) | ||||
| 				new_tbl.Hashes[idx] = -1; | ||||
|  | ||||
| 			for ( idx = 0; idx < old_entries_header->Num; idx++ ) | ||||
| 			{ | ||||
| 				<entry_type>*  entry; | ||||
| 				HT_FindResult  find_result; | ||||
|  | ||||
| 				if ( new_hash_header->Num == 0 ) | ||||
| 					<fn>_grow( & new_tbl ); | ||||
|  | ||||
| 				entry            = & self->Entries[ idx ]; | ||||
| 				find_result      = <fn>__find( new_tbl, entry->Key ); | ||||
| 				last_added_index = <fn>__add_entry( new_tbl, entry->Key ); | ||||
|  | ||||
| 				if ( find_result.PrevIndex < 0 ) | ||||
| 					new_tbl.Hashes[ find_result.HashIndex ] = last_added_index; | ||||
| 				else | ||||
| 					new_tbl.Entries[ find_result.PrevIndex ].Next = last_added_index; | ||||
|  | ||||
| 				new_tbl.Entries[ last_added_index ].Next  = find_result.EntryIndex; | ||||
| 				new_tbl.Entries[ last_added_index ].Value = entry->Value; | ||||
| 			} | ||||
|  | ||||
| 			<fn>_destroy( *self ); | ||||
| 			* self = new_tbl; | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_rehash_fast( <tbl_type> self ) | ||||
| 		{ | ||||
| 			ssize idx; | ||||
|  | ||||
| 			for ( idx = 0; idx < array_header( self.Entries )->Num; idx++ ) | ||||
| 				self.Entries[ idx ].Next = -1; | ||||
|  | ||||
| 			for ( idx = 0; idx < array_header( self.Hashes )->Num; idx++ ) | ||||
| 				self.Hashes[ idx ] = -1; | ||||
|  | ||||
| 			for ( idx = 0; idx < array_header( self.Entries )->Num; idx++ ) | ||||
| 			{ | ||||
| 				<entry_type>*     entry; | ||||
| 				HT_FindResult find_result; | ||||
|  | ||||
| 				entry       = & self.Entries[ idx ]; | ||||
| 				find_result = <fn>__find( self, entry->Key ); | ||||
|  | ||||
| 				if ( find_result.PrevIndex < 0 ) | ||||
| 					self.Hashes[ find_result.HashIndex ] = idx; | ||||
| 				else | ||||
| 					self.Entries[ find_result.PrevIndex ].Next = idx; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_remove( <tbl_type> self, u64 key ) | ||||
| 		{ | ||||
| 			HT_FindResult find_result = <fn>__find( self, key ); | ||||
|  | ||||
| 			if ( find_result.EntryIndex >= 0 ) | ||||
| 			{ | ||||
| 				<fn_array>_remove_at( self.Entries, find_result.EntryIndex ); | ||||
| 				<fn>_rehash_fast( self ); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_remove_entry( <tbl_type> self, ssize idx ) | ||||
| 		{ | ||||
| 			<fn_array>_remove_at( self.Entries, idx ); | ||||
| 		} | ||||
|  | ||||
| 		void <fn>_set( <tbl_type>* self, u64 key, <type> value ) | ||||
| 		{ | ||||
| 			ssize            idx; | ||||
| 			HT_FindResult find_result; | ||||
|  | ||||
| 			if ( array_header( self->Hashes )->Num == 0 ) | ||||
| 				<fn>_grow( self ); | ||||
|  | ||||
| 			find_result = <fn>__find( * self, key ); | ||||
|  | ||||
| 			if ( find_result.EntryIndex >= 0 ) | ||||
| 			{ | ||||
| 				idx = find_result.EntryIndex; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				idx = <fn>__add_entry( * self, key ); | ||||
|  | ||||
| 				if ( find_result.PrevIndex >= 0 ) | ||||
| 				{ | ||||
| 					self->Entries[ find_result.PrevIndex ].Next = idx; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					self->Hashes[ find_result.HashIndex ] = idx; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			self->Entries[ idx ].Value = value; | ||||
|  | ||||
| 			if ( <fn>__full( * self ) ) | ||||
| 				<fn>_grow( self ); | ||||
| 		} | ||||
|  | ||||
| 		ssize <fn>_slot( <tbl_type> self, u64 key ) | ||||
| 		{ | ||||
| 			for ( ssize idx = 0; idx < array_header( self.Hashes )->Num; ++idx ) | ||||
| 				if ( self.Hashes[ idx ] == key ) | ||||
| 					return idx; | ||||
|  | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		ssize <fn>__add_entry( <tbl_type> self, u64 key ) | ||||
| 		{ | ||||
| 			ssize idx; | ||||
| 			<entry_type> entry = { key, -1 }; | ||||
|  | ||||
| 			idx = array_header( self.Entries )->Num; | ||||
| 			<fn_array>_append( & self.Entries, entry ); | ||||
| 			return idx; | ||||
| 		} | ||||
|  | ||||
| 		HT_FindResult <fn>__find( <tbl_type> self, u64 key ) | ||||
| 		{ | ||||
| 			HT_FindResult result = { -1, -1, -1 }; | ||||
|  | ||||
| 			ArrayHeader* hash_header = array_header( self.Hashes ); | ||||
|  | ||||
| 			if ( hash_header->Num > 0 ) | ||||
| 			{ | ||||
| 				result.HashIndex  = key % hash_header->Num; | ||||
| 				result.EntryIndex = self.Hashes[ result.HashIndex ]; | ||||
|  | ||||
| 				while ( result.EntryIndex >= 0 ) | ||||
| 				{ | ||||
| 					if ( self.Entries[ result.EntryIndex ].Key == key ) | ||||
| 						break; | ||||
|  | ||||
| 					result.PrevIndex  = result.EntryIndex; | ||||
| 					result.EntryIndex = self.Entries[ result.EntryIndex ].Next; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			return result; | ||||
| 		} | ||||
|  | ||||
| 		b32 <fn>__full( <tbl_type> self ) | ||||
| 		{ | ||||
| 			ArrayHeader* hash_header    = array_header( self.Hashes ); | ||||
| 			ArrayHeader* entries_header = array_header( self.Entries ); | ||||
|  | ||||
| 			return 0.75f * hash_header->Num < entries_header->Num; | ||||
| 		} | ||||
| 	))); | ||||
| #pragma pop_macro( "GEN_ASSERT" ) | ||||
| #pragma pop_macro( "GEN_ASSERT_NOT_NULL" ) | ||||
|  | ||||
| 	char const* cmt_str = str_fmt_buf( "Name: %.*s Type: %.*s" | ||||
| 		, tbl_type.length(), tbl_type.Data | ||||
| 		, type.Len, type.Ptr ); | ||||
|  | ||||
| 	return def_global_body(args( | ||||
| 		def_pragma( to_str( str_fmt_buf( "region %S", tbl_type ))), | ||||
| 		fmt_newline, | ||||
| 		hashtable_types, | ||||
| 		fmt_newline, | ||||
| 		entry_array, | ||||
| 		hashtable_def, | ||||
| 		fmt_newline, | ||||
| 		def_pragma( to_str( str_fmt_buf( "endregion %S", tbl_type ))), | ||||
| 		fmt_newline | ||||
| 	)); | ||||
| } | ||||
							
								
								
									
										14
									
								
								gen_c_library/components/header_start.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								gen_c_library/components/header_start.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| /* | ||||
| 	gencpp: An attempt at "simple" staged metaprogramming for c/c++. | ||||
|  | ||||
| 	See Readme.md for more information from the project repository. | ||||
|  | ||||
| 	Public Address: | ||||
| 	https://github.com/Ed94/gencpp | ||||
|  | ||||
| 	This is a single header C-Library variant. | ||||
| 	Define GEN_IMPLEMENTATION before including this file in a single compilation unit. | ||||
| */ | ||||
| #if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME) | ||||
| #	error Gen.hpp : GEN_TIME not defined | ||||
| #endif | ||||
							
								
								
									
										122
									
								
								gen_c_library/components/memory.fixed_arena.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								gen_c_library/components/memory.fixed_arena.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | ||||
| #pragma once | ||||
| #include "../project/gen.hpp" | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| CodeBody gen_fixed_arenas() | ||||
| { | ||||
| 	CodeBody result = def_body(ECode::Global_Body); | ||||
| 	result.append(def_pragma(txt("region FixedArena"))); | ||||
|  | ||||
| 	char const* template_struct = stringize( | ||||
| 		struct FixedArena_<Name> | ||||
| 		{ | ||||
| 			char  memory[<Size>]; | ||||
| 			Arena arena; | ||||
| 		}; | ||||
| 	); | ||||
|  | ||||
| 	char const* template_interface = stringize( | ||||
| 		inline | ||||
| 		void fixed_arena_init_<Name>(FixedArena_<Name>* result) { | ||||
| 			zero_size(& result->memory[0], <Size>); | ||||
| 			result.arena = arena_init_from_memory(& result->memory[0], <Size>); | ||||
| 		} | ||||
|  | ||||
| 		inline | ||||
| 		ssize fixed_arena_size_remaining_<Name>(FixedArena_<Name>* fixed_arena, ssize alignment) { | ||||
| 			return size_remaining(fixed_arena->arena, alignment); | ||||
| 		} | ||||
| 	); | ||||
|  | ||||
| 	CodeStruct arena_struct_1kb   = parse_struct( token_fmt_impl( 3, "Name", txt("1KB"),   "Size", txt("kilobytes(1)"),   template_struct )); | ||||
| 	CodeStruct arena_struct_4kb   = parse_struct( token_fmt_impl( 3, "Name", txt("4KB"),   "Size", txt("kilobytes(4)"),   template_struct )); | ||||
| 	CodeStruct arena_struct_8kb   = parse_struct( token_fmt_impl( 3, "Name", txt("8KB"),   "Size", txt("kilobytes(8)"),   template_struct )); | ||||
| 	CodeStruct arena_struct_16kb  = parse_struct( token_fmt_impl( 3, "Name", txt("16KB"),  "Size", txt("kilobytes(16)"),  template_struct )); | ||||
| 	CodeStruct arena_struct_32kb  = parse_struct( token_fmt_impl( 3, "Name", txt("32KB"),  "Size", txt("kilobytes(32)"),  template_struct )); | ||||
| 	CodeStruct arena_struct_64kb  = parse_struct( token_fmt_impl( 3, "Name", txt("64KB"),  "Size", txt("kilobytes(64)"),  template_struct )); | ||||
| 	CodeStruct arena_struct_128kb = parse_struct( token_fmt_impl( 3, "Name", txt("128KB"), "Size", txt("kilobytes(128)"), template_struct )); | ||||
| 	CodeStruct arena_struct_256kb = parse_struct( token_fmt_impl( 3, "Name", txt("256KB"), "Size", txt("kilobytes(256)"), template_struct )); | ||||
| 	CodeStruct arena_struct_512kb = parse_struct( token_fmt_impl( 3, "Name", txt("512KB"), "Size", txt("kilobytes(512)"), template_struct )); | ||||
| 	CodeStruct arena_struct_1mb   = parse_struct( token_fmt_impl( 3, "Name", txt("1MB"),   "Size", txt("megabytes(1)"),   template_struct )); | ||||
| 	CodeStruct arena_struct_2mb   = parse_struct( token_fmt_impl( 3, "Name", txt("2MB"),   "Size", txt("megabytes(2)"),   template_struct )); | ||||
| 	CodeStruct arena_struct_4mb   = parse_struct( token_fmt_impl( 3, "Name", txt("4MB"),   "Size", txt("megabytes(4)"),   template_struct )); | ||||
|  | ||||
|  | ||||
| 	CodeBody arena_interface_1kb   = parse_global_body( token_fmt_impl( 3, "Name", txt("1KB"),   "Size", txt("kilobytes(1)"),    template_interface )); | ||||
| 	CodeBody arena_interface_4kb   = parse_global_body( token_fmt_impl( 3, "Name", txt("4KB"),   "Size", txt("kilobytes(4)"),    template_interface )); | ||||
| 	CodeBody arena_interface_8kb   = parse_global_body( token_fmt_impl( 3, "Name", txt("8KB"),   "Size", txt("kilobytes(8)"),    template_interface )); | ||||
| 	CodeBody arena_interface_16kb  = parse_global_body( token_fmt_impl( 3, "Name", txt("16KB"),  "Size", txt("kilobytes(16)"),   template_interface )); | ||||
| 	CodeBody arena_interface_32kb  = parse_global_body( token_fmt_impl( 3, "Name", txt("32KB"),  "Size", txt("kilobytes(32)"),   template_interface )); | ||||
| 	CodeBody arena_interface_64kb  = parse_global_body( token_fmt_impl( 3, "Name", txt("64KB"),  "Size", txt("kilobytes(64)"),   template_interface )); | ||||
| 	CodeBody arena_interface_128kb = parse_global_body( token_fmt_impl( 3, "Name", txt("128KB"), "Size", txt("kilobytes(128)"), template_interface )); | ||||
| 	CodeBody arena_interface_256kb = parse_global_body( token_fmt_impl( 3, "Name", txt("256KB"), "Size", txt("kilobytes(256)"), template_interface )); | ||||
| 	CodeBody arena_interface_512kb = parse_global_body( token_fmt_impl( 3, "Name", txt("512KB"), "Size", txt("kilobytes(512)"), template_interface )); | ||||
| 	CodeBody arena_interface_1mb   = parse_global_body( token_fmt_impl( 3, "Name", txt("1MB"),   "Size", txt("megabytes(1)"),   template_interface )); | ||||
| 	CodeBody arena_interface_2mb   = parse_global_body( token_fmt_impl( 3, "Name", txt("2MB"),   "Size", txt("megabytes(2)"),   template_interface )); | ||||
| 	CodeBody arena_interface_4mb   = parse_global_body( token_fmt_impl( 3, "Name", txt("4MB"),   "Size", txt("megabytes(4)"),   template_interface )); | ||||
|  | ||||
| 	result.append(arena_struct_1kb); | ||||
| 	result.append(arena_struct_4kb); | ||||
| 	result.append(arena_struct_8kb); | ||||
| 	result.append(arena_struct_16kb); | ||||
| 	result.append(arena_struct_32kb); | ||||
| 	result.append(arena_struct_128kb); | ||||
| 	result.append(arena_struct_256kb); | ||||
| 	result.append(arena_struct_512kb); | ||||
| 	result.append(arena_struct_1mb); | ||||
| 	result.append(arena_struct_2mb); | ||||
| 	result.append(arena_struct_4mb); | ||||
|  | ||||
| 	result.append(arena_interface_1kb); | ||||
| 	result.append(arena_interface_4kb); | ||||
| 	result.append(arena_interface_8kb); | ||||
| 	result.append(arena_interface_16kb); | ||||
| 	result.append(arena_interface_32kb); | ||||
| 	result.append(arena_interface_128kb); | ||||
| 	result.append(arena_interface_256kb); | ||||
| 	result.append(arena_interface_512kb); | ||||
| 	result.append(arena_interface_1mb); | ||||
| 	result.append(arena_interface_2mb); | ||||
| 	result.append(arena_interface_4mb); | ||||
|  | ||||
| 	CodeDefine def = def_define(txt("fixed_arena_allocator_info(fixed_arena)"), code({ arena_allocator_proc, & fixed_arena.arena }) ); | ||||
| 	result.append(def); | ||||
|  | ||||
| 	result.append(parse_global_body(txt(R"( | ||||
| #define fixed_arena_init(expr) _Generic((expr), \ | ||||
|     FixedArena_1KB*   : fixed_arena_init_1KB,   \ | ||||
|     FixedArena_4KB*   : fixed_arena_init_4KB,   \ | ||||
|     FixedArena_8KB*   : fixed_arena_init_8KB,   \ | ||||
|     FixedArena_16KB*  : fixed_arena_init_16KB,  \ | ||||
|     FixedArena_32KB*  : fixed_arena_init_32KB,  \ | ||||
|     FixedArena_64KB*  : fixed_arena_init_64KB,  \ | ||||
|     FixedArena_128KB* : fixed_arena_init_128KB, \ | ||||
|     FixedArena_256KB* : fixed_arena_init_256KB, \ | ||||
|     FixedArena_512KB* : fixed_arena_init_512KB, \ | ||||
|     FixedArena_1MB*   : fixed_arena_init_1MB,   \ | ||||
|     FixedArena_2MB*   : fixed_arena_init_2MB,   \ | ||||
|     FixedArena_4MB*   : fixed_arena_init_4MB    \ | ||||
| )(expr) | ||||
|  | ||||
| #define fixed_arena_size_remaining(expr, alignment) _Generic((expr), \ | ||||
|     FixedArena_1KB*   : fixed_arena_size_remaining_1KB,              \ | ||||
|     FixedArena_4KB*   : fixed_arena_size_remaining_4KB,              \ | ||||
|     FixedArena_8KB*   : fixed_arena_size_remaining_8KB,              \ | ||||
|     FixedArena_16KB*  : fixed_arena_size_remaining_16KB,             \ | ||||
|     FixedArena_32KB*  : fixed_arena_size_remaining_32KB,             \ | ||||
|     FixedArena_64KB*  : fixed_arena_size_remaining_64KB,             \ | ||||
|     FixedArena_128KB* : fixed_arena_size_remaining_128KB,            \ | ||||
|     FixedArena_256KB* : fixed_arena_size_remaining_256KB,            \ | ||||
|     FixedArena_512KB* : fixed_arena_size_remaining_512KB,            \ | ||||
|     FixedArena_1MB*   : fixed_arena_size_remaining_1MB,              \ | ||||
|     FixedArena_2MB*   : fixed_arena_size_remaining_2MB,              \ | ||||
|     FixedArena_4MB*   : fixed_arena_size_remaining_4MB               \ | ||||
| )(expr, alignment) | ||||
| )" | ||||
| 	))); | ||||
|  | ||||
| 	result.append(def_pragma(txt("endregion FixedArena"))); | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
							
								
								
									
										72
									
								
								gen_c_library/components/misc.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								gen_c_library/components/misc.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| // #pragma once | ||||
| // #include "../project/gen.hpp" | ||||
|  | ||||
| // using namespace gen; | ||||
|  | ||||
| using SwapContentProc = CodeBody(void); | ||||
|  | ||||
| b32 ignore_preprocess_cond_block( StrC cond_sig, Code& entry_iter, CodeBody& body ) | ||||
| { | ||||
| 	b32 found = false; | ||||
| 	CodePreprocessCond cond = entry_iter.cast<CodePreprocessCond>(); | ||||
| 	if ( cond->Content.contains(cond_sig) ) | ||||
| 	{ | ||||
| 		log_fmt("Preprocess cond found: %S\n", cond->Content); | ||||
| 		found = true; | ||||
|  | ||||
| 		s32 depth = 1; | ||||
| 		++ entry_iter; for(b32 continue_for = true; continue_for && entry_iter != body.end(); ) switch | ||||
| 		(entry_iter->Type) { | ||||
| 			case ECode::Preprocess_If: | ||||
| 			case ECode::Preprocess_IfDef: | ||||
| 			case ECode::Preprocess_IfNotDef: | ||||
| 				depth ++; | ||||
| 			break; | ||||
|  | ||||
| 			case ECode::Preprocess_EndIf: | ||||
| 			{ | ||||
| 				depth --; | ||||
| 				if (depth == 0) { | ||||
| 					continue_for = false; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
| 			default: | ||||
| 				++ entry_iter; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return found; | ||||
| } | ||||
|  | ||||
| bool swap_pragma_region_implementation( StrC region_name, SwapContentProc* swap_content, Code& entry_iter, CodeBody& body ) | ||||
| { | ||||
| 	bool found = false; | ||||
| 	CodePragma possible_region = entry_iter.cast<CodePragma>(); | ||||
|  | ||||
| 	String region_sig    = string_fmt_buf(GlobalAllocator, "region %s",    region_name.Ptr); | ||||
| 	String endregion_sig = string_fmt_buf(GlobalAllocator, "endregion %s", region_name.Ptr); | ||||
| 	if ( possible_region->Content.contains(region_sig)) | ||||
| 	{ | ||||
| 		found = true; | ||||
| 		// body.append(possible_region); | ||||
| 		body.append(swap_content()); | ||||
|  | ||||
| 		++ entry_iter; for(b32 continue_for = true; continue_for; ++entry_iter) switch | ||||
| 		(entry_iter->Type) { | ||||
| 			case ECode::Preprocess_Pragma: | ||||
| 			{ | ||||
| 				CodePragma possible_end_region = entry_iter.cast<CodePragma>(); | ||||
| 				if ( possible_end_region->Content.contains(endregion_sig) ) { | ||||
| 					// body.append(possible_end_region); | ||||
| 					continue_for = false; | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		body.append(entry_iter); | ||||
| 	} | ||||
| 	return found; | ||||
| } | ||||
| @@ -1,4 +1,4 @@ | ||||
| # Singleheader | ||||
| 
 | ||||
| Creates a single header file version of the library using `gen.singleheader.cpp`. | ||||
| Creates a single header file version of the library using `singleheader.cpp`. | ||||
| Follows the same convention seen in the gb, stb, and zpl libraries. | ||||
| @@ -12,12 +12,3 @@ | ||||
| #if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME) | ||||
| #	error Gen.hpp : GEN_TIME not defined | ||||
| #endif | ||||
| 
 | ||||
| #ifdef GEN_DONT_USE_NAMESPACE | ||||
| #	define GEN_NS_BEGIN | ||||
| #	define GEN_NS_END | ||||
| #else | ||||
| #	define GEN_NS_BEGIN namespace gen { | ||||
| #	define GEN_NS_END   } | ||||
| #endif | ||||
| 
 | ||||
| @@ -13,7 +13,7 @@ Builder Builder::open( char const* path ) | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	result.Buffer = String::make_reserve( GlobalAllocator, Builder_StrBufferReserve ); | ||||
| 	result.Buffer = string_make_reserve( GlobalAllocator, Builder_StrBufferReserve ); | ||||
|  | ||||
| 	// log_fmt("$Builder - Opened file: %s\n", result.File.filename ); | ||||
| 	return result; | ||||
| @@ -21,7 +21,7 @@ Builder Builder::open( char const* path ) | ||||
|  | ||||
| void Builder::pad_lines( s32 num ) | ||||
| { | ||||
| 	Buffer.append( "\n" ); | ||||
| 	append( Buffer,  "\n" ); | ||||
| } | ||||
|  | ||||
| void Builder::print( Code code ) | ||||
| @@ -29,7 +29,7 @@ void Builder::print( Code code ) | ||||
| 	String   str = code->to_string(); | ||||
| 	// const ssize len = str.length(); | ||||
| 	// log_fmt( "%s - print: %.*s\n", File.filename, len > 80 ? 80 : len, str.Data ); | ||||
| 	Buffer.append( str ); | ||||
| 	append( Buffer, str ); | ||||
| } | ||||
|  | ||||
| void Builder::print_fmt( char const* fmt, ... ) | ||||
| @@ -43,17 +43,17 @@ void Builder::print_fmt( char const* fmt, ... ) | ||||
| 	va_end( va ); | ||||
|  | ||||
| 	// log_fmt( "$%s - print_fmt: %.*s\n", File.filename, res > 80 ? 80 : res, buf ); | ||||
| 	Buffer.append( buf, res ); | ||||
| 	append( Buffer, buf, res ); | ||||
| } | ||||
|  | ||||
| void Builder::write() | ||||
| { | ||||
| 	b32 result = file_write( & File, Buffer, Buffer.length() ); | ||||
| 	b32 result = file_write( & File, Buffer, length(Buffer) ); | ||||
|  | ||||
| 	if ( result == false ) | ||||
| 		log_failure("gen::File::write - Failed to write to file: %s\n", file_name( & File ) ); | ||||
|  | ||||
| 	log_fmt( "Generated: %s\n", File.filename ); | ||||
| 	file_close( & File ); | ||||
| 	Buffer.free(); | ||||
| 	free(Buffer); | ||||
| } | ||||
|   | ||||
							
								
								
									
										23
									
								
								project/auxillary/gen_template.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								project/auxillary/gen_template.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "../gen.hpp" | ||||
| #endif | ||||
|  | ||||
| /* | ||||
| 	Explicitly generates a resolved definition of a cpp template definition. | ||||
|  | ||||
| 	TODO(Ed): Needs implementing for the C-library variant. | ||||
| 	TODO(Ed): We need a non <token> syntax subst implemtnation for Strings for this to work. It must subst keywords directly based on template parameter names. | ||||
|  | ||||
| 	This is only meant to be used on relatively trivial templates, where the type or numeric is mostly a 'duck' type. | ||||
| 	It cannot parse complex template parameters. | ||||
|  | ||||
| 	The varadic args should correspond 1:1 with the type of objects the generator expects from the template's parameters.alignas. | ||||
| */ | ||||
|  | ||||
| CodeOperator gen_operator_template( CodeTemplate template, ... ); | ||||
| CodeFn       gen_func_template( CodeTemplate template, ...  ); | ||||
| Code         gen_class_struct_template( CodeTemplate template, ... ); | ||||
|  | ||||
| Code gen_template( CodeTemplate template, ... ); | ||||
| Code gen_template( StrC template, StrC instantiation ); | ||||
| @@ -23,9 +23,9 @@ Code scan_file( char const* path ) | ||||
| 		GEN_FATAL("scan_file: %s is empty", path ); | ||||
| 	} | ||||
|  | ||||
| 	String str = String::make_reserve( GlobalAllocator, fsize ); | ||||
| 	String str = string_make_reserve( GlobalAllocator, fsize ); | ||||
| 		file_read( & file, str, fsize ); | ||||
| 		str.get_header().Length = fsize; | ||||
| 		get_header(str).Length = fsize; | ||||
|  | ||||
| 	// Skip GEN_INTELLISENSE_DIRECTIVES preprocessor blocks | ||||
| 	// Its designed so that the directive should be the first thing in the file. | ||||
| @@ -97,12 +97,12 @@ Code scan_file( char const* path ) | ||||
| 					if ( (scanner + 2) >= ( str.Data + fsize ) ) | ||||
| 					{ | ||||
| 						mem_move( str, scanner, left ); | ||||
| 						str.get_header().Length = left; | ||||
| 						get_header(str).Length = left; | ||||
| 						break; | ||||
| 					} | ||||
|  | ||||
| 					mem_move( str, scanner, left ); | ||||
| 					str.get_header().Length = left; | ||||
| 					get_header(str).Length = left; | ||||
|  | ||||
| 					break; | ||||
| 				} | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS | ||||
| #define GEN_ENFORCE_STRONG_CODE_TYPES | ||||
| #define GEN_EXPOSE_BACKEND | ||||
| #define GEN_SUPPORT_CPP_MEMBER_FEATURES 0 | ||||
| #include "gen.cpp" | ||||
|  | ||||
| #include "helpers/push_ignores.inline.hpp" | ||||
| @@ -24,20 +25,20 @@ constexpr char const* generation_notice = | ||||
|  | ||||
| void format_file( char const* path ) | ||||
| { | ||||
| 	String resolved_path = String::make(GlobalAllocator, to_str(path)); | ||||
| 	String resolved_path = string_make(GlobalAllocator, to_str(path)); | ||||
|  | ||||
| 	String style_arg = String::make(GlobalAllocator, txt("-style=file:")); | ||||
| 	style_arg.append("../scripts/.clang-format "); | ||||
| 	String style_arg = string_make(GlobalAllocator, txt("-style=file:")); | ||||
| 	append( style_arg, "../scripts/.clang-format "); | ||||
|  | ||||
| 	// Need to execute clang format on the generated file to get it to match the original. | ||||
| 	#define clang_format      "clang-format " | ||||
| 	#define cf_format_inplace "-i " | ||||
| 	#define cf_verbose        "-verbose " | ||||
| 	String command = String::make( GlobalAllocator, clang_format ); | ||||
| 	command.append( cf_format_inplace ); | ||||
| 	command.append( cf_verbose ); | ||||
| 	command.append( style_arg ); | ||||
| 	command.append( resolved_path ); | ||||
| 	String command = string_make( GlobalAllocator, clang_format ); | ||||
| 	append( command, cf_format_inplace ); | ||||
| 	append( command, cf_verbose ); | ||||
| 	append( command, style_arg ); | ||||
| 	append( command, resolved_path ); | ||||
| 		log_fmt("\tRunning clang-format on file:\n"); | ||||
| 		system( command ); | ||||
| 		log_fmt("\tclang-format finished reformatting.\n"); | ||||
|   | ||||
| @@ -9,16 +9,16 @@ Code Code::Invalid; | ||||
| // This serializes all the data-members in a "debug" format, where each member is printed with its associated value. | ||||
| char const* AST::debug_str() | ||||
| { | ||||
| 	String result = String::make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String result = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
|  | ||||
| 	if ( Parent ) | ||||
| 		result.append_fmt( "\n\tParent       : %S %S", Parent->type_str(), Name ? Name : "" ); | ||||
| 		append_fmt( result, "\n\tParent       : %S %S", Parent->type_str(), Name ? Name : "" ); | ||||
| 	else | ||||
| 		result.append_fmt( "\n\tParent       : %S", "Null" ); | ||||
| 		append_fmt( result, "\n\tParent       : %S", "Null" ); | ||||
|  | ||||
| 	result.append_fmt( "\n\tName         : %S", Name ? Name : "Null" ); | ||||
| 	result.append_fmt( "\n\tType         : %S", type_str() ); | ||||
| 	result.append_fmt( "\n\tModule Flags : %S", to_str( ModuleFlags ) ); | ||||
| 	append_fmt( result, "\n\tName         : %S", Name ? Name : "Null" ); | ||||
| 	append_fmt( result, "\n\tType         : %S", type_str() ); | ||||
| 	append_fmt( result, "\n\tModule Flags : %S", to_str( ModuleFlags ) ); | ||||
|  | ||||
| 	switch ( Type ) | ||||
| 	{ | ||||
| @@ -30,9 +30,9 @@ char const* AST::debug_str() | ||||
| 		case Access_Protected: | ||||
| 		case Access_Public: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Untyped: | ||||
| @@ -48,74 +48,74 @@ char const* AST::debug_str() | ||||
| 		case Preprocess_IfDef: | ||||
| 		case Preprocess_IfNotDef: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tContent: %S", Content ); | ||||
| 			append_fmt( result, "\n\tContent: %S", Content ); | ||||
| 		break; | ||||
|  | ||||
| 		case Class: | ||||
| 		case Struct: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmd   : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||
| 			result.append_fmt( "\n\tAttributes  : %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tParentAccess: %s", ParentType ? to_str( ParentAccess )  : "No Parent" ); | ||||
| 			result.append_fmt( "\n\tParentType  : %s", ParentType ? ParentType->type_str()  : "Null" ); | ||||
| 			result.append_fmt( "\n\tBody        : %S", Body       ? Body->debug_str()       : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmd   : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||
| 			append_fmt( result, "\n\tAttributes  : %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tParentAccess: %s", ParentType ? to_str( ParentAccess )  : "No Parent" ); | ||||
| 			append_fmt( result, "\n\tParentType  : %s", ParentType ? ParentType->type_str()  : "Null" ); | ||||
| 			append_fmt( result, "\n\tBody        : %S", Body       ? Body->debug_str()       : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Class_Fwd: | ||||
| 		case Struct_Fwd: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmd   : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||
| 			result.append_fmt( "\n\tAttributes  : %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tParentAccess: %s", ParentType ? to_str( ParentAccess )  : "No Parent" ); | ||||
| 			result.append_fmt( "\n\tParentType  : %s", ParentType ? ParentType->type_str()  : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmd   : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||
| 			append_fmt( result, "\n\tAttributes  : %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tParentAccess: %s", ParentType ? to_str( ParentAccess )  : "No Parent" ); | ||||
| 			append_fmt( result, "\n\tParentType  : %s", ParentType ? ParentType->type_str()  : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Constructor: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt      : %S", InlineCmt       ? InlineCmt->Content           : "Null" ); | ||||
| 			result.append_fmt( "\n\tSpecs          : %S", Specs           ? Specs->to_string()           : "Null" ); | ||||
| 			result.append_fmt( "\n\tInitializerList: %S", InitializerList ? InitializerList->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tParams         : %S", Params          ? Params->to_string()          : "Null" ); | ||||
| 			result.append_fmt( "\n\tBody           : %S", Body            ? Body->debug_str()            : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmt      : %S", InlineCmt       ? InlineCmt->Content           : "Null" ); | ||||
| 			append_fmt( result, "\n\tSpecs          : %S", Specs           ? Specs->to_string()           : "Null" ); | ||||
| 			append_fmt( result, "\n\tInitializerList: %S", InitializerList ? InitializerList->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tParams         : %S", Params          ? Params->to_string()          : "Null" ); | ||||
| 			append_fmt( result, "\n\tBody           : %S", Body            ? Body->debug_str()            : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Constructor_Fwd: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt      : %S", InlineCmt       ? InlineCmt->Content           : "Null" ); | ||||
| 			result.append_fmt( "\n\tSpecs          : %S", Specs           ? Specs->to_string()           : "Null" ); | ||||
| 			result.append_fmt( "\n\tInitializerList: %S", InitializerList ? InitializerList->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tParams         : %S", Params          ? Params->to_string()          : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmt      : %S", InlineCmt       ? InlineCmt->Content           : "Null" ); | ||||
| 			append_fmt( result, "\n\tSpecs          : %S", Specs           ? Specs->to_string()           : "Null" ); | ||||
| 			append_fmt( result, "\n\tInitializerList: %S", InitializerList ? InitializerList->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tParams         : %S", Params          ? Params->to_string()          : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Destructor: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt      : %S", InlineCmt ? InlineCmt->Content : "Null" ); | ||||
| 			result.append_fmt( "\n\tSpecs          : %S", Specs     ? Specs->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tBody           : %S", Body      ? Body->debug_str()  : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmt      : %S", InlineCmt ? InlineCmt->Content : "Null" ); | ||||
| 			append_fmt( result, "\n\tSpecs          : %S", Specs     ? Specs->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tBody           : %S", Body      ? Body->debug_str()  : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Destructor_Fwd: | ||||
| @@ -124,208 +124,208 @@ char const* AST::debug_str() | ||||
| 		case Enum: | ||||
| 		case Enum_Class: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt       : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | ||||
| 			result.append_fmt( "\n\tAttributes      : %S", Attributes     ? Attributes->to_string()     : "Null" ); | ||||
| 			result.append_fmt( "\n\tUnderlying Type : %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tBody            : %S", Body           ? Body->debug_str()           : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmt       : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | ||||
| 			append_fmt( result, "\n\tAttributes      : %S", Attributes     ? Attributes->to_string()     : "Null" ); | ||||
| 			append_fmt( result, "\n\tUnderlying Type : %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tBody            : %S", Body           ? Body->debug_str()           : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Enum_Fwd: | ||||
| 		case Enum_Class_Fwd: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt       : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | ||||
| 			result.append_fmt( "\n\tAttributes      : %S", Attributes     ? Attributes->to_string()     : "Null" ); | ||||
| 			result.append_fmt( "\n\tUnderlying Type : %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmt       : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | ||||
| 			append_fmt( result, "\n\tAttributes      : %S", Attributes     ? Attributes->to_string()     : "Null" ); | ||||
| 			append_fmt( result, "\n\tUnderlying Type : %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Extern_Linkage: | ||||
| 		case Namespace: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tBody: %S", Body ? Body->debug_str() : "Null" ); | ||||
| 			append_fmt( result, "\n\tBody: %S", Body ? Body->debug_str() : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Friend: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt  : %S", InlineCmt   ? InlineCmt->Content       : "Null" ); | ||||
| 			result.append_fmt( "\n\tDeclaration: %S", Declaration ? Declaration->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmt  : %S", InlineCmt   ? InlineCmt->Content       : "Null" ); | ||||
| 			append_fmt( result, "\n\tDeclaration: %S", Declaration ? Declaration->to_string() : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Function: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||
| 			result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||
| 			result.append_fmt( "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | ||||
| 			result.append_fmt( "\n\tBody      : %S", Body       ? Body->debug_str()       : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||
| 			append_fmt( result, "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||
| 			append_fmt( result, "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | ||||
| 			append_fmt( result, "\n\tBody      : %S", Body       ? Body->debug_str()       : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Function_Fwd: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||
| 			result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||
| 			result.append_fmt( "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||
| 			append_fmt( result, "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||
| 			append_fmt( result, "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Module: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Operator: | ||||
| 		case Operator_Member: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||
| 			result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||
| 			result.append_fmt( "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | ||||
| 			result.append_fmt( "\n\tBody      : %S", Body       ? Body->debug_str()       : "Null" ); | ||||
| 			result.append_fmt( "\n\tOp        : %S", to_str( Op ) ); | ||||
| 			append_fmt( result, "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||
| 			append_fmt( result, "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||
| 			append_fmt( result, "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | ||||
| 			append_fmt( result, "\n\tBody      : %S", Body       ? Body->debug_str()       : "Null" ); | ||||
| 			append_fmt( result, "\n\tOp        : %S", to_str( Op ) ); | ||||
| 		break; | ||||
|  | ||||
| 		case Operator_Fwd: | ||||
| 		case Operator_Member_Fwd: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||
| 			result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||
| 			result.append_fmt( "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | ||||
| 			result.append_fmt( "\n\tOp        : %S", to_str( Op ) ); | ||||
| 			append_fmt( result, "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content      : "Null" ); | ||||
| 			append_fmt( result, "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tSpecs     : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||
| 			append_fmt( result, "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tParams    : %S", Params     ? Params->to_string()     : "Null" ); | ||||
| 			append_fmt( result, "\n\tOp        : %S", to_str( Op ) ); | ||||
| 		break; | ||||
|  | ||||
| 		case Operator_Cast: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content     : "Null" ); | ||||
| 			result.append_fmt( "\n\tSpecs     : %S", Specs      ? Specs->to_string()     : "Null" ); | ||||
| 			result.append_fmt( "\n\tValueType : %S", ValueType  ? ValueType->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tBody      : %S", Body       ? Body->debug_str()      : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content     : "Null" ); | ||||
| 			append_fmt( result, "\n\tSpecs     : %S", Specs      ? Specs->to_string()     : "Null" ); | ||||
| 			append_fmt( result, "\n\tValueType : %S", ValueType  ? ValueType->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tBody      : %S", Body       ? Body->debug_str()      : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Operator_Cast_Fwd: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content     : "Null" ); | ||||
| 			result.append_fmt( "\n\tSpecs     : %S", Specs      ? Specs->to_string()     : "Null" ); | ||||
| 			result.append_fmt( "\n\tValueType : %S", ValueType  ? ValueType->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmt : %S", InlineCmt  ? InlineCmt->Content     : "Null" ); | ||||
| 			append_fmt( result, "\n\tSpecs     : %S", Specs      ? Specs->to_string()     : "Null" ); | ||||
| 			append_fmt( result, "\n\tValueType : %S", ValueType  ? ValueType->to_string() : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Parameters: | ||||
| 			result.append_fmt( "\n\tNumEntries: %d", NumEntries ); | ||||
| 			result.append_fmt( "\n\tLast      : %S", Last->Name ); | ||||
| 			result.append_fmt( "\n\tNext      : %S", Next->Name ); | ||||
| 			result.append_fmt( "\n\tValueType : %S", ValueType ? ValueType->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tValue     : %S", Value     ? Value->to_string()     : "Null" ); | ||||
| 			append_fmt( result, "\n\tNumEntries: %d", NumEntries ); | ||||
| 			append_fmt( result, "\n\tLast      : %S", Last->Name ); | ||||
| 			append_fmt( result, "\n\tNext      : %S", Next->Name ); | ||||
| 			append_fmt( result, "\n\tValueType : %S", ValueType ? ValueType->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tValue     : %S", Value     ? Value->to_string()     : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Specifiers: | ||||
| 		{ | ||||
| 			result.append_fmt( "\n\tNumEntries: %d", NumEntries ); | ||||
| 			result.append( "\n\tArrSpecs: " ); | ||||
| 			append_fmt( result, "\n\tNumEntries: %d", NumEntries ); | ||||
| 			GEN_NS append( result, "\n\tArrSpecs: " ); | ||||
|  | ||||
| 			s32 idx  = 0; | ||||
| 			s32 left = NumEntries; | ||||
| 			while ( left-- ) | ||||
| 			{ | ||||
| 				StrC spec = ESpecifier::to_str( ArrSpecs[idx] ); | ||||
| 				result.append_fmt( "%.*s, ", spec.Len, spec.Ptr ); | ||||
| 				append_fmt( result, "%.*s, ", spec.Len, spec.Ptr ); | ||||
| 				idx++; | ||||
| 			} | ||||
| 			result.append_fmt( "\n\tNextSpecs: %S", NextSpecs ? NextSpecs->debug_str() : "Null" ); | ||||
| 			append_fmt( result, "\n\tNextSpecs: %S", NextSpecs ? NextSpecs->debug_str() : "Null" ); | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 		case Template: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tParams     : %S", Params      ? Params->to_string()      : "Null" ); | ||||
| 			result.append_fmt( "\n\tDeclaration: %S", Declaration ? Declaration->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tParams     : %S", Params      ? Params->to_string()      : "Null" ); | ||||
| 			append_fmt( result, "\n\tDeclaration: %S", Declaration ? Declaration->to_string() : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Typedef: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt     : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | ||||
| 			result.append_fmt( "\n\tUnderlyingType: %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmt     : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | ||||
| 			append_fmt( result, "\n\tUnderlyingType: %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Typename: | ||||
| 			result.append_fmt( "\n\tAttributes     : %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tSpecs          : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||
| 			result.append_fmt( "\n\tReturnType     : %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tParams         : %S", Params     ? Params->to_string()     : "Null" ); | ||||
| 			result.append_fmt( "\n\tArrExpr        : %S", ArrExpr    ? ArrExpr->to_string()    : "Null" ); | ||||
| 			append_fmt( result, "\n\tAttributes     : %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tSpecs          : %S", Specs      ? Specs->to_string()      : "Null" ); | ||||
| 			append_fmt( result, "\n\tReturnType     : %S", ReturnType ? ReturnType->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tParams         : %S", Params     ? Params->to_string()     : "Null" ); | ||||
| 			append_fmt( result, "\n\tArrExpr        : %S", ArrExpr    ? ArrExpr->to_string()    : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Union: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tBody      : %S", Body       ? Body->debug_str()       : "Null" ); | ||||
| 			append_fmt( result, "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tBody      : %S", Body       ? Body->debug_str()       : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Using: | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt     : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | ||||
| 			result.append_fmt( "\n\tAttributes    : %S", Attributes     ? Attributes->to_string()     : "Null" ); | ||||
| 			result.append_fmt( "\n\tUnderlyingType: %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmt     : %S", InlineCmt      ? InlineCmt->Content          : "Null" ); | ||||
| 			append_fmt( result, "\n\tAttributes    : %S", Attributes     ? Attributes->to_string()     : "Null" ); | ||||
| 			append_fmt( result, "\n\tUnderlyingType: %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); | ||||
| 		break; | ||||
|  | ||||
| 		case Variable: | ||||
| @@ -333,25 +333,25 @@ char const* AST::debug_str() | ||||
| 			if ( Parent && Parent->Type == Variable ) | ||||
| 			{ | ||||
| 				// Its a NextVar | ||||
| 				result.append_fmt( "\n\tSpecs       : %S", Specs        ? Specs->to_string()        : "Null" ); | ||||
| 				result.append_fmt( "\n\tValue       : %S", Value        ? Value->to_string()        : "Null" ); | ||||
| 				result.append_fmt( "\n\tBitfieldSize: %S", BitfieldSize ? BitfieldSize->to_string() : "Null" ); | ||||
| 				result.append_fmt( "\n\tNextVar     : %S", NextVar      ? NextVar->debug_str()      : "Null" ); | ||||
| 				append_fmt( result, "\n\tSpecs       : %S", Specs        ? Specs->to_string()        : "Null" ); | ||||
| 				append_fmt( result, "\n\tValue       : %S", Value        ? Value->to_string()        : "Null" ); | ||||
| 				append_fmt( result, "\n\tBitfieldSize: %S", BitfieldSize ? BitfieldSize->to_string() : "Null" ); | ||||
| 				append_fmt( result, "\n\tNextVar     : %S", NextVar      ? NextVar->debug_str()      : "Null" ); | ||||
| 				break; | ||||
| 			} | ||||
|  | ||||
| 			if ( Prev ) | ||||
| 				result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 			if ( Next ) | ||||
| 				result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
| 				append_fmt( result, "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); | ||||
|  | ||||
| 			result.append_fmt( "\n\tInlineCmt   : %S", InlineCmt    ? InlineCmt->Content        : "Null" ); | ||||
| 			result.append_fmt( "\n\tAttributes  : %S", Attributes   ? Attributes->to_string()   : "Null" ); | ||||
| 			result.append_fmt( "\n\tSpecs       : %S", Specs        ? Specs->to_string()        : "Null" ); | ||||
| 			result.append_fmt( "\n\tValueType   : %S", ValueType    ? ValueType->to_string()    : "Null" ); | ||||
| 			result.append_fmt( "\n\tBitfieldSize: %S", BitfieldSize ? BitfieldSize->to_string() : "Null" ); | ||||
| 			result.append_fmt( "\n\tValue       : %S", Value        ? Value->to_string()        : "Null" ); | ||||
| 			result.append_fmt( "\n\tNextVar     : %S", NextVar      ? NextVar->debug_str()      : "Null" ); | ||||
| 			append_fmt( result, "\n\tInlineCmt   : %S", InlineCmt    ? InlineCmt->Content        : "Null" ); | ||||
| 			append_fmt( result, "\n\tAttributes  : %S", Attributes   ? Attributes->to_string()   : "Null" ); | ||||
| 			append_fmt( result, "\n\tSpecs       : %S", Specs        ? Specs->to_string()        : "Null" ); | ||||
| 			append_fmt( result, "\n\tValueType   : %S", ValueType    ? ValueType->to_string()    : "Null" ); | ||||
| 			append_fmt( result, "\n\tBitfieldSize: %S", BitfieldSize ? BitfieldSize->to_string() : "Null" ); | ||||
| 			append_fmt( result, "\n\tValue       : %S", Value        ? Value->to_string()        : "Null" ); | ||||
| 			append_fmt( result, "\n\tNextVar     : %S", NextVar      ? NextVar->debug_str()      : "Null" ); | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| @@ -372,7 +372,7 @@ AST* AST::duplicate() | ||||
|  | ||||
| String AST::to_string() | ||||
| { | ||||
| 	String result = String::make( GlobalAllocator, "" ); | ||||
| 	String result = string_make( GlobalAllocator, "" ); | ||||
| 	to_string( result ); | ||||
| 	return result; | ||||
| } | ||||
| @@ -390,25 +390,25 @@ void AST::to_string( String& result ) | ||||
| 		#ifdef GEN_DONT_ALLOW_INVALID_CODE | ||||
| 			log_failure("Attempted to serialize invalid code! - %S", Parent ? Parent->debug_str() : Name ); | ||||
| 		#else | ||||
| 			result.append_fmt( "Invalid Code!" ); | ||||
| 			append_fmt( result, "Invalid Code!" ); | ||||
| 		#endif | ||||
| 		break; | ||||
|  | ||||
| 		case NewLine: | ||||
| 			result.append("\n"); | ||||
| 			GEN_NS append( result,"\n"); | ||||
| 		break; | ||||
|  | ||||
| 		case Untyped: | ||||
| 		case Execution: | ||||
| 		case Comment: | ||||
| 		case PlatformAttributes: | ||||
| 			result.append( Content ); | ||||
| 			GEN_NS append( result, Content ); | ||||
| 		break; | ||||
|  | ||||
| 		case Access_Private: | ||||
| 		case Access_Protected: | ||||
| 		case Access_Public: | ||||
| 			result.append( Name ); | ||||
| 			GEN_NS append( result, Name ); | ||||
| 		break; | ||||
|  | ||||
| 		case Class: | ||||
| @@ -659,8 +659,8 @@ bool AST::is_equal( AST* other ) | ||||
| 			"so it must be verified by eye for now\n"                     \ | ||||
| 			"AST   Content:\n%S\n"                                        \ | ||||
| 			"Other Content:\n%S\n"                                        \ | ||||
| 			, content.visualize_whitespace()                              \ | ||||
| 			, other->content.visualize_whitespace()                       \ | ||||
| 			, visualize_whitespace(content)                               \ | ||||
| 			, visualize_whitespace(other->content)                        \ | ||||
| 		);                                                                \ | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -165,6 +165,7 @@ struct Code | ||||
| 	char const* debug_str();               \ | ||||
| 	Code        duplicate();			   \ | ||||
| 	bool        is_equal( Code other );    \ | ||||
| 	bool        is_body();                 \ | ||||
| 	bool        is_valid();                \ | ||||
| 	void        set_global();              \ | ||||
| 	String      to_string();               \ | ||||
| @@ -259,6 +260,7 @@ struct AST | ||||
| 	Code&       entry      ( u32 idx ); | ||||
| 	bool        has_entries(); | ||||
| 	bool        is_equal   ( AST* other ); | ||||
| 	bool        is_body(); | ||||
| 	char const* type_str(); | ||||
| 	bool        validate_body(); | ||||
|  | ||||
| @@ -376,7 +378,8 @@ struct AST | ||||
| 		OperatorT     Op; | ||||
| 		AccessSpec    ParentAccess; | ||||
| 		s32           NumEntries; | ||||
| 		s32           VarConstructorInit; // Used by variables to know that initialization is using a constructor expression instead of an assignment expression. | ||||
| 		s32           VarConstructorInit;  // Used by variables to know that initialization is using a constructor expression instead of an assignment expression. | ||||
| 		b32           EnumUnderlyingMacro; // Used by enums incase the user wants to wrap underlying type specification in a macro | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -174,7 +174,7 @@ struct AST_Enum | ||||
| 			CodeAttributes Attributes; | ||||
| 			char           _PAD_SPEC_  [ sizeof(AST*) ]; | ||||
| 			CodeType       UnderlyingType; | ||||
| 			char	       _PAD_PARAMS_[ sizeof(AST*) ]; | ||||
| 			Code           UnderlyingTypeMacro; | ||||
| 			CodeBody       Body; | ||||
| 			char 	       _PAD_PROPERTIES_2_[ sizeof(AST*) ]; | ||||
| 		}; | ||||
| @@ -186,7 +186,7 @@ struct AST_Enum | ||||
| 	StringCached           Name; | ||||
| 	CodeT                  Type; | ||||
| 	ModuleFlag             ModuleFlags; | ||||
| 	char 			       _PAD_UNUSED_[ sizeof(u32) ]; | ||||
| 	b32                    EnumUnderlyingMacro; | ||||
| }; | ||||
| static_assert( sizeof(AST_Enum) == sizeof(AST), "ERROR: AST_Enum is not the same size as AST"); | ||||
|  | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -11,6 +11,10 @@ struct CodeBody | ||||
|  | ||||
| 	void append( Code other ) | ||||
| 	{ | ||||
| 		if (other.is_body()) | ||||
| 		{ | ||||
| 			append( other.cast<CodeBody>() ); | ||||
| 		} | ||||
| 		raw()->append( other.ast ); | ||||
| 	} | ||||
| 	void append( CodeBody body ) | ||||
| @@ -165,6 +169,46 @@ struct CodeSpecifiers | ||||
|  | ||||
| 		return -1; | ||||
| 	} | ||||
| 	s32 remove( SpecifierT to_remove ) | ||||
| 	{ | ||||
| 		if ( ast == nullptr ) | ||||
| 		{ | ||||
| 			log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!"); | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		if ( raw()->NumEntries == AST::ArrSpecs_Cap ) | ||||
| 		{ | ||||
| 			log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST::ArrSpecs_Cap ); | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		s32 result = -1; | ||||
|  | ||||
| 		s32 curr = 0; | ||||
| 		s32 next = 0; | ||||
| 		for(; next < raw()->NumEntries; ++ curr, ++ next) | ||||
| 		{ | ||||
| 			SpecifierT spec = raw()->ArrSpecs[next]; | ||||
| 			if (spec == to_remove) | ||||
| 			{ | ||||
| 				result = next; | ||||
|  | ||||
| 				next ++; | ||||
| 				if (next >= raw()->NumEntries) | ||||
| 					break; | ||||
|  | ||||
| 				spec = raw()->ArrSpecs[next]; | ||||
| 			} | ||||
|  | ||||
| 			raw()->ArrSpecs[ curr ] = spec; | ||||
| 		} | ||||
|  | ||||
| 		if (result > -1) { | ||||
| 			raw()->NumEntries --; | ||||
| 		} | ||||
| 		return result; | ||||
| 	} | ||||
| 	void to_string( String& result ); | ||||
| 	AST* raw() | ||||
| 	{ | ||||
|   | ||||
| @@ -24,6 +24,15 @@ inline Code Code::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool Code::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool Code::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -91,6 +100,15 @@ inline Code CodeBody::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeBody::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeBody::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -158,6 +176,15 @@ inline Code CodeAttributes::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeAttributes::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeAttributes::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -245,6 +272,15 @@ inline Code CodeComment::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeComment::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeComment::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -332,6 +368,15 @@ inline Code CodeConstructor::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeConstructor::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeConstructor::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -419,6 +464,15 @@ inline Code CodeClass::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeClass::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeClass::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -486,6 +540,15 @@ inline Code CodeDefine::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeDefine::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeDefine::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -573,6 +636,15 @@ inline Code CodeDestructor::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeDestructor::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeDestructor::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -660,6 +732,15 @@ inline Code CodeEnum::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeEnum::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeEnum::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -747,6 +828,15 @@ inline Code CodeExec::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeExec::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeExec::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -834,6 +924,15 @@ inline Code CodeExtern::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeExtern::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeExtern::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -921,6 +1020,15 @@ inline Code CodeFriend::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeFriend::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeFriend::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -1008,6 +1116,15 @@ inline Code CodeFn::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeFn::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeFn::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -1095,6 +1212,15 @@ inline Code CodeInclude::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeInclude::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeInclude::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -1182,6 +1308,15 @@ inline Code CodeModule::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeModule::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeModule::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -1269,6 +1404,15 @@ inline Code CodeNS::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeNS::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeNS::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -1356,6 +1500,15 @@ inline Code CodeOperator::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeOperator::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeOperator::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -1443,6 +1596,15 @@ inline Code CodeOpCast::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeOpCast::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeOpCast::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -1530,6 +1692,15 @@ inline Code CodeParam::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeParam::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeParam::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -1597,6 +1768,15 @@ inline Code CodePragma::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodePragma::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodePragma::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -1684,6 +1864,15 @@ inline Code CodePreprocessCond::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodePreprocessCond::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodePreprocessCond::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -1771,6 +1960,15 @@ inline Code CodeSpecifiers::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeSpecifiers::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeSpecifiers::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -1838,6 +2036,15 @@ inline Code CodeStruct::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeStruct::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeStruct::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -1905,6 +2112,15 @@ inline Code CodeTemplate::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeTemplate::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeTemplate::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -1992,6 +2208,15 @@ inline Code CodeType::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeType::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeType::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -2079,6 +2304,15 @@ inline Code CodeTypedef::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeTypedef::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeTypedef::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -2166,6 +2400,15 @@ inline Code CodeUnion::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeUnion::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeUnion::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -2253,6 +2496,15 @@ inline Code CodeUsing::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeUsing::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeUsing::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
| @@ -2340,6 +2592,15 @@ inline Code CodeVar::duplicate() | ||||
| 	return { rcast( AST*, ast )->duplicate() }; | ||||
| } | ||||
|  | ||||
| inline bool CodeVar::is_body() | ||||
| { | ||||
| 	if ( ast == nullptr ) | ||||
| 	{ | ||||
| 		return rcast( AST*, ast )->is_body(); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline bool CodeVar::is_equal( Code other ) | ||||
| { | ||||
| 	if ( ast == nullptr || other.ast == nullptr ) | ||||
|   | ||||
| @@ -133,6 +133,7 @@ extern CodeType t_typename; | ||||
|  | ||||
| #pragma region Macros | ||||
|  | ||||
| #ifndef token_fmt | ||||
| #	define gen_main main | ||||
|  | ||||
| #	define __ NoCode | ||||
| @@ -151,6 +152,7 @@ extern CodeType t_typename; | ||||
|  | ||||
| 	// Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string. | ||||
| #	define token_fmt( ... ) GEN_NS token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ ) | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Macros | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,7 @@ void AST::append( AST* other ) | ||||
| 	} | ||||
|  | ||||
| 	AST* | ||||
| 		Current       = Back; | ||||
| 	Current       = Back; | ||||
| 	Current->Next = other; | ||||
| 	other->Prev   = Current; | ||||
| 	Back          = other; | ||||
| @@ -50,6 +50,25 @@ bool AST::has_entries() | ||||
| 	return NumEntries > 0; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool AST::is_body() | ||||
| { | ||||
| 	switch (Type) | ||||
| 	{ | ||||
| 		case ECode::Enum_Body: | ||||
| 		case ECode::Class_Body: | ||||
| 		case ECode::Union_Body: | ||||
| 		case ECode::Export_Body: | ||||
| 		case ECode::Global_Body: | ||||
| 		case ECode::Struct_Body: | ||||
| 		case ECode::Function_Body: | ||||
| 		case ECode::Namespace_Body: | ||||
| 		case ECode::Extern_Linkage_Body: | ||||
| 			return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline | ||||
| char const* AST::type_str() | ||||
| { | ||||
| @@ -78,7 +97,7 @@ void CodeClass::add_interface( CodeType type ) | ||||
| 	if ( possible_slot.ast ) | ||||
| 	{ | ||||
| 		// Were adding an interface to parent type, so we need to make sure the parent type is public. | ||||
| 		ast->ParentAccess = AccessSpec::Public; | ||||
| 		ast->ParentAccess = AccessSpec_Public; | ||||
| 		// If your planning on adding a proper parent, | ||||
| 		// then you'll need to move this over to ParentType->next and update ParentAccess accordingly. | ||||
| 	} | ||||
| @@ -151,7 +170,7 @@ void CodeStruct::add_interface( CodeType type ) | ||||
| 	if ( possible_slot.ast ) | ||||
| 	{ | ||||
| 		// Were adding an interface to parent type, so we need to make sure the parent type is public. | ||||
| 		ast->ParentAccess = AccessSpec::Public; | ||||
| 		ast->ParentAccess = AccessSpec_Public; | ||||
| 		// If your planning on adding a proper parent, | ||||
| 		// then you'll need to move this over to ParentType->next and update ParentAccess accordingly. | ||||
| 	} | ||||
|   | ||||
| @@ -11,7 +11,7 @@ internal void deinit(); | ||||
| internal | ||||
| void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | ||||
| { | ||||
| 	Arena* last = & Global_AllocatorBuckets.back(); | ||||
| 	Arena* last = & back(Global_AllocatorBuckets); | ||||
|  | ||||
| 	switch ( type ) | ||||
| 	{ | ||||
| @@ -19,18 +19,18 @@ void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, s | ||||
| 		{ | ||||
| 			if ( ( last->TotalUsed + size ) > last->TotalSize ) | ||||
| 			{ | ||||
| 				Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); | ||||
| 				Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize ); | ||||
|  | ||||
| 				if ( bucket.PhysicalStart == nullptr ) | ||||
| 					GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets"); | ||||
|  | ||||
| 				if ( ! Global_AllocatorBuckets.append( bucket ) ) | ||||
| 				if ( ! append( Global_AllocatorBuckets, bucket ) ) | ||||
| 					GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets"); | ||||
|  | ||||
| 				last = & Global_AllocatorBuckets.back(); | ||||
| 				last = & back(Global_AllocatorBuckets); | ||||
| 			} | ||||
|  | ||||
| 			return alloc_align( * last, size, alignment ); | ||||
| 			return alloc_align( allocator_info(* last), size, alignment ); | ||||
| 		} | ||||
| 		case EAllocation_FREE: | ||||
| 		{ | ||||
| @@ -46,15 +46,15 @@ void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, s | ||||
| 		{ | ||||
| 			if ( last->TotalUsed + size > last->TotalSize ) | ||||
| 			{ | ||||
| 				Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); | ||||
| 				Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize ); | ||||
|  | ||||
| 				if ( bucket.PhysicalStart == nullptr ) | ||||
| 					GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets"); | ||||
|  | ||||
| 				if ( ! Global_AllocatorBuckets.append( bucket ) ) | ||||
| 				if ( ! append( Global_AllocatorBuckets, bucket ) ) | ||||
| 					GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets"); | ||||
|  | ||||
| 				last = & Global_AllocatorBuckets.back(); | ||||
| 				last = & back(Global_AllocatorBuckets); | ||||
| 			} | ||||
|  | ||||
| 			void* result = alloc_align( last->Backing, size, alignment ); | ||||
| @@ -74,16 +74,16 @@ void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, s | ||||
| internal | ||||
| void define_constants() | ||||
| { | ||||
| 	Code::Global          = make_code(); | ||||
| 	Code::Global->Name    = get_cached_string( txt("Global Code") ); | ||||
| 	Code::Global->Content = Code::Global->Name; | ||||
| 	Code::Global                         = make_code(); | ||||
| 	scast(String, Code::Global->Name)    = get_cached_string( txt("Global Code") ); | ||||
| 	scast(String, Code::Global->Content) = Code::Global->Name; | ||||
|  | ||||
| 	Code::Invalid = make_code(); | ||||
| 	Code::Invalid.set_global(); | ||||
|  | ||||
| 	t_empty          = (CodeType) make_code(); | ||||
| 	t_empty->Type    = ECode::Typename; | ||||
| 	t_empty->Name    = get_cached_string( txt("") ); | ||||
| 	t_empty       = (CodeType) make_code(); | ||||
| 	t_empty->Type = ECode::Typename; | ||||
| 	t_empty->Name = get_cached_string( txt("") ); | ||||
| 	t_empty.set_global(); | ||||
|  | ||||
| 	access_private       = make_code(); | ||||
| @@ -226,6 +226,10 @@ void define_constants() | ||||
| #	pragma pop_macro("local_persist") | ||||
| #	pragma pop_macro("neverinline") | ||||
|  | ||||
| #	pragma push_macro("enum_underlying") | ||||
|  | ||||
| #	pragma pop_macro("enum_underlying") | ||||
|  | ||||
| #	undef def_constant_spec | ||||
| } | ||||
|  | ||||
| @@ -235,28 +239,27 @@ void init() | ||||
| 	{ | ||||
| 		GlobalAllocator = AllocatorInfo { & Global_Allocator_Proc, nullptr }; | ||||
|  | ||||
| 		Global_AllocatorBuckets = Array<Arena>::init_reserve( heap(), 128 ); | ||||
| 		Global_AllocatorBuckets = array_init_reserve<Arena>( heap(), 128 ); | ||||
|  | ||||
| 		if ( Global_AllocatorBuckets == nullptr ) | ||||
| 			GEN_FATAL( "Failed to reserve memory for Global_AllocatorBuckets"); | ||||
|  | ||||
| 		Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); | ||||
| 		Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize ); | ||||
|  | ||||
| 		if ( bucket.PhysicalStart == nullptr ) | ||||
| 			GEN_FATAL( "Failed to create first bucket for Global_AllocatorBuckets"); | ||||
|  | ||||
| 		Global_AllocatorBuckets.append( bucket ); | ||||
|  | ||||
| 		append( Global_AllocatorBuckets, bucket ); | ||||
| 	} | ||||
|  | ||||
| 	// Setup the arrays | ||||
| 	{ | ||||
| 		CodePools = Array<Pool>::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); | ||||
| 		CodePools = array_init_reserve<Pool>( Allocator_DataArrays, InitSize_DataArrays ); | ||||
|  | ||||
| 		if ( CodePools == nullptr ) | ||||
| 			GEN_FATAL( "gen::init: Failed to initialize the CodePools array" ); | ||||
|  | ||||
| 		StringArenas = Array<Arena>::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); | ||||
| 		StringArenas = array_init_reserve<Arena>( Allocator_DataArrays, InitSize_DataArrays ); | ||||
|  | ||||
| 		if ( StringArenas == nullptr ) | ||||
| 			GEN_FATAL( "gen::init: Failed to initialize the StringArenas array" ); | ||||
| @@ -264,33 +267,33 @@ void init() | ||||
|  | ||||
| 	// Setup the code pool and code entries arena. | ||||
| 	{ | ||||
| 		Pool code_pool = Pool::init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); | ||||
| 		Pool code_pool = pool_init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); | ||||
|  | ||||
| 		if ( code_pool.PhysicalStart == nullptr ) | ||||
| 			GEN_FATAL( "gen::init: Failed to initialize the code pool" ); | ||||
|  | ||||
| 		CodePools.append( code_pool ); | ||||
| 		append(CodePools, code_pool ); | ||||
|  | ||||
| 		LexArena = Arena::init_from_allocator( Allocator_Lexer, LexAllocator_Size ); | ||||
| 		LexArena = arena_init_from_allocator( Allocator_Lexer, LexAllocator_Size ); | ||||
|  | ||||
| 		Arena string_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena ); | ||||
| 		Arena string_arena = arena_init_from_allocator( Allocator_StringArena, SizePer_StringArena ); | ||||
|  | ||||
| 		if ( string_arena.PhysicalStart == nullptr ) | ||||
| 			GEN_FATAL( "gen::init: Failed to initialize the string arena" ); | ||||
|  | ||||
| 		StringArenas.append( string_arena ); | ||||
| 		append(StringArenas, string_arena ); | ||||
| 	} | ||||
|  | ||||
| 	// Setup the hash tables | ||||
| 	{ | ||||
| 		StringCache = StringTable::init( Allocator_StringTable ); | ||||
| 		StringCache = hashtable_init<StringCached>(Allocator_StringTable); | ||||
|  | ||||
| 		if ( StringCache.Entries == nullptr ) | ||||
| 			GEN_FATAL( "gen::init: Failed to initialize the StringCache"); | ||||
| 	} | ||||
|  | ||||
| 	// Preprocessor Defines | ||||
| 	PreprocessorDefines = Array<StringCached>::init_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	PreprocessorDefines = array_init_reserve<StringCached>( GlobalAllocator, kilobytes(1) ); | ||||
|  | ||||
| 	define_constants(); | ||||
| 	parser::init(); | ||||
| @@ -299,62 +302,62 @@ void init() | ||||
| void deinit() | ||||
| { | ||||
| 	usize index = 0; | ||||
| 	usize left  = CodePools.num(); | ||||
| 	usize left  = num(CodePools); | ||||
| 	do | ||||
| 	{ | ||||
| 		Pool* code_pool = & CodePools[index]; | ||||
| 		code_pool->free(); | ||||
| 		free(* code_pool); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	index = 0; | ||||
| 	left  = StringArenas.num(); | ||||
| 	left  = num(StringArenas); | ||||
| 	do | ||||
| 	{ | ||||
| 		Arena* string_arena = & StringArenas[index]; | ||||
| 		string_arena->free(); | ||||
| 		free(* string_arena); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	StringCache.destroy(); | ||||
| 	destroy(StringCache); | ||||
|  | ||||
| 	CodePools.free(); | ||||
| 	StringArenas.free(); | ||||
| 	free(CodePools); | ||||
| 	free(StringArenas); | ||||
|  | ||||
| 	LexArena.free(); | ||||
| 	free(LexArena); | ||||
|  | ||||
| 	PreprocessorDefines.free(); | ||||
| 	free(PreprocessorDefines); | ||||
|  | ||||
| 	index = 0; | ||||
| 	left  = Global_AllocatorBuckets.num(); | ||||
| 	left  = num(Global_AllocatorBuckets); | ||||
| 	do | ||||
| 	{ | ||||
| 		Arena* bucket = & Global_AllocatorBuckets[ index ]; | ||||
| 		bucket->free(); | ||||
| 		free(* bucket); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	Global_AllocatorBuckets.free(); | ||||
| 	free(Global_AllocatorBuckets); | ||||
| 	parser::deinit(); | ||||
| } | ||||
|  | ||||
| void reset() | ||||
| { | ||||
| 	s32 index = 0; | ||||
| 	s32 left  = CodePools.num(); | ||||
| 	s32 left  = num(CodePools); | ||||
| 	do | ||||
| 	{ | ||||
| 		Pool* code_pool = & CodePools[index]; | ||||
| 		code_pool->clear(); | ||||
| 		clear(* code_pool); | ||||
| 		index++; | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	index = 0; | ||||
| 	left  = StringArenas.num(); | ||||
| 	left  = num(StringArenas); | ||||
| 	do | ||||
| 	{ | ||||
| 		Arena* string_arena = & StringArenas[index]; | ||||
| @@ -363,28 +366,28 @@ void reset() | ||||
| 	} | ||||
| 	while ( left--, left ); | ||||
|  | ||||
| 	StringCache.clear(); | ||||
| 	clear(StringCache); | ||||
|  | ||||
| 	define_constants(); | ||||
| } | ||||
|  | ||||
| AllocatorInfo get_string_allocator( s32 str_length ) | ||||
| { | ||||
| 	Arena* last = & StringArenas.back(); | ||||
| 	Arena* last = & back(StringArenas); | ||||
|  | ||||
| 	usize size_req = str_length + sizeof(String::Header) + sizeof(char*); | ||||
| 	usize size_req = str_length + sizeof(StringHeader) + sizeof(char*); | ||||
|  | ||||
| 	if ( last->TotalUsed + ssize(size_req) > last->TotalSize ) | ||||
| 	{ | ||||
| 		Arena new_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena ); | ||||
| 		Arena new_arena = arena_init_from_allocator( Allocator_StringArena, SizePer_StringArena ); | ||||
|  | ||||
| 		if ( ! StringArenas.append( new_arena ) ) | ||||
| 		if ( ! append(StringArenas, new_arena ) ) | ||||
| 			GEN_FATAL( "gen::get_string_allocator: Failed to allocate a new string arena" ); | ||||
|  | ||||
| 		last = & StringArenas.back(); | ||||
| 		last = & back(StringArenas); | ||||
| 	} | ||||
|  | ||||
| 	return * last; | ||||
| 	return allocator_info(* last); | ||||
| } | ||||
|  | ||||
| // Will either make or retrive a code string. | ||||
| @@ -393,14 +396,14 @@ StringCached get_cached_string( StrC str ) | ||||
| 	s32 hash_length = str.Len > kilobytes(1) ? kilobytes(1) : str.Len; | ||||
| 	u64 key         = crc32( str.Ptr, hash_length ); | ||||
| 	{ | ||||
| 		StringCached* result = StringCache.get( key ); | ||||
| 		StringCached* result = get(StringCache, key ); | ||||
|  | ||||
| 		if ( result ) | ||||
| 			return * result; | ||||
| 	} | ||||
|  | ||||
| 	String result = String::make( get_string_allocator( str.Len ), str ); | ||||
| 	StringCache.set( key, result ); | ||||
| 	String result = string_make( get_string_allocator( str.Len ), str ); | ||||
| 	set<StringCached>(StringCache, key, result ); | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
| @@ -408,21 +411,21 @@ StringCached get_cached_string( StrC str ) | ||||
| // Used internally to retireve a Code object form the CodePool. | ||||
| Code make_code() | ||||
| { | ||||
| 	Pool* allocator = & CodePools.back(); | ||||
| 	Pool* allocator = & back(CodePools); | ||||
| 	if ( allocator->FreeList == nullptr ) | ||||
| 	{ | ||||
| 		Pool code_pool = Pool::init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); | ||||
| 		Pool code_pool = pool_init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); | ||||
|  | ||||
| 		if ( code_pool.PhysicalStart == nullptr ) | ||||
| 			GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePool allcoator returned nullptr." ); | ||||
|  | ||||
| 		if ( ! CodePools.append( code_pool ) ) | ||||
| 		if ( ! append( CodePools, code_pool ) ) | ||||
| 			GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePools failed to append new pool." ); | ||||
|  | ||||
| 		allocator = & CodePools.back(); | ||||
| 		allocator = & back(CodePools); | ||||
| 	} | ||||
|  | ||||
| 	Code result { rcast( AST*, alloc( * allocator, sizeof(AST) )) }; | ||||
| 	Code result { rcast( AST*, alloc( allocator_info(* allocator), sizeof(AST) )) }; | ||||
| 	mem_set( result.ast, 0, sizeof(AST) ); | ||||
| 	// result->Type = ECode::Invalid; | ||||
|  | ||||
|   | ||||
| @@ -44,9 +44,9 @@ CodeComment    def_comment   ( StrC content ); | ||||
|  | ||||
| CodeClass def_class( StrC name | ||||
| 	, Code           body         = NoCode | ||||
| 	, CodeType       parent       = NoCode, AccessSpec access = AccessSpec::Default | ||||
| 	, CodeType       parent       = NoCode, AccessSpec access = AccessSpec_Default | ||||
| 	, CodeAttributes attributes   = NoCode | ||||
| 	, ModuleFlag     mflags       = ModuleFlag::None | ||||
| 	, ModuleFlag     mflags       = ModuleFlag_None | ||||
| 	, CodeType*      interfaces   = nullptr, s32 num_interfaces = 0 ); | ||||
|  | ||||
| CodeConstructor def_constructor( CodeParam params = NoCode, Code initializer_list = NoCode, Code body = NoCode ); | ||||
| @@ -56,9 +56,9 @@ CodeDefine def_define( StrC name, StrC content ); | ||||
| CodeDestructor def_destructor( Code body = NoCode, CodeSpecifiers specifiers = NoCode ); | ||||
|  | ||||
| CodeEnum def_enum( StrC name | ||||
| 	, Code         body      = NoCode,      CodeType       type       = NoCode | ||||
| 	, EnumT        specifier = EnumRegular, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag   mflags    = ModuleFlag::None ); | ||||
| 	, Code         body      = NoCode,           CodeType       type       = NoCode | ||||
| 	, EnumT        specifier = EnumDecl_Regular, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag   mflags    = ModuleFlag_None ); | ||||
|  | ||||
| CodeExec   def_execution  ( StrC content ); | ||||
| CodeExtern def_extern_link( StrC name, Code body ); | ||||
| @@ -67,16 +67,16 @@ CodeFriend def_friend     ( Code symbol ); | ||||
| CodeFn def_function( StrC name | ||||
| 	, CodeParam      params     = NoCode, CodeType       ret_type   = NoCode, Code body = NoCode | ||||
| 	, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag mflags     = ModuleFlag::None ); | ||||
| 	, ModuleFlag mflags     = ModuleFlag_None ); | ||||
|  | ||||
| CodeInclude   def_include  ( StrC content, bool foreign = false ); | ||||
| CodeModule    def_module   ( StrC name,            ModuleFlag mflags = ModuleFlag::None ); | ||||
| CodeNS        def_namespace( StrC name, Code body, ModuleFlag mflags = ModuleFlag::None ); | ||||
| CodeModule    def_module   ( StrC name,            ModuleFlag mflags = ModuleFlag_None ); | ||||
| CodeNS        def_namespace( StrC name, Code body, ModuleFlag mflags = ModuleFlag_None ); | ||||
|  | ||||
| CodeOperator def_operator( OperatorT op, StrC nspace | ||||
| 	, CodeParam      params     = NoCode, CodeType       ret_type   = NoCode, Code body = NoCode | ||||
| 	, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag     mflags     = ModuleFlag::None ); | ||||
| 	, ModuleFlag     mflags     = ModuleFlag_None ); | ||||
|  | ||||
| CodeOpCast def_operator_cast( CodeType type, Code body = NoCode, CodeSpecifiers specs = NoCode ); | ||||
|  | ||||
| @@ -89,27 +89,27 @@ CodeSpecifiers def_specifier( SpecifierT specifier ); | ||||
|  | ||||
| CodeStruct def_struct( StrC name | ||||
| 	, Code           body       = NoCode | ||||
| 	, CodeType       parent     = NoCode, AccessSpec access = AccessSpec::Default | ||||
| 	, CodeType       parent     = NoCode, AccessSpec access = AccessSpec_Default | ||||
| 	, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag     mflags     = ModuleFlag::None | ||||
| 	, ModuleFlag     mflags     = ModuleFlag_None | ||||
| 	, CodeType*      interfaces = nullptr, s32 num_interfaces = 0 ); | ||||
|  | ||||
| CodeTemplate def_template( CodeParam params, Code definition, ModuleFlag mflags = ModuleFlag::None ); | ||||
| CodeTemplate def_template( CodeParam params, Code definition, ModuleFlag mflags = ModuleFlag_None ); | ||||
|  | ||||
| CodeType    def_type   ( StrC name, Code arrayexpr = NoCode, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode ); | ||||
| CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag::None ); | ||||
| CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag_None ); | ||||
|  | ||||
| CodeUnion def_union( StrC name, Code body, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag::None ); | ||||
| CodeUnion def_union( StrC name, Code body, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag_None ); | ||||
|  | ||||
| CodeUsing def_using( StrC name, CodeType type = NoCode | ||||
| 	, CodeAttributes attributess = NoCode | ||||
| 	, ModuleFlag     mflags      = ModuleFlag::None ); | ||||
| 	, ModuleFlag     mflags      = ModuleFlag_None ); | ||||
|  | ||||
| CodeUsing def_using_namespace( StrC name ); | ||||
|  | ||||
| CodeVar def_variable( CodeType type, StrC name, Code value = NoCode | ||||
| 	, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode | ||||
| 	, ModuleFlag     mflags     = ModuleFlag::None ); | ||||
| 	, ModuleFlag     mflags     = ModuleFlag_None ); | ||||
|  | ||||
| // Constructs an empty body. Use AST::validate_body() to check if the body is was has valid entries. | ||||
| CodeBody def_body( CodeT type ); | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
| ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | ||||
| { | ||||
| 	char const* buf_begin = buf; | ||||
| 	ssize          remaining = buf_size; | ||||
| 	ssize       remaining = buf_size; | ||||
|  | ||||
| 	local_persist | ||||
| 	Arena tok_map_arena; | ||||
| @@ -16,8 +16,8 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | ||||
| 		local_persist | ||||
| 		char tok_map_mem[ TokenFmt_TokenMap_MemSize ]; | ||||
|  | ||||
| 		tok_map_arena = Arena::init_from_memory( tok_map_mem, sizeof(tok_map_mem) ); | ||||
| 		tok_map       = HashTable<StrC>::init( tok_map_arena ); | ||||
| 		tok_map_arena = arena_init_from_memory( tok_map_mem, sizeof(tok_map_mem) ); | ||||
| 		tok_map       = hashtable_init<StrC>( allocator_info(tok_map_arena) ); | ||||
|  | ||||
| 		s32 left = num_tokens - 1; | ||||
|  | ||||
| @@ -28,7 +28,7 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | ||||
|  | ||||
| 			u32 key = crc32( token, str_len(token) ); | ||||
|  | ||||
| 			tok_map.set( key, value ); | ||||
| 			set(tok_map, key, value ); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -64,7 +64,7 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | ||||
| 			char const* token = fmt + 1; | ||||
|  | ||||
| 			u32       key   = crc32( token, tok_len ); | ||||
| 			StrC*     value = tok_map.get( key ); | ||||
| 			StrC*     value = get(tok_map, key ); | ||||
|  | ||||
| 			if ( value ) | ||||
| 			{ | ||||
| @@ -94,8 +94,8 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	tok_map.clear(); | ||||
| 	tok_map_arena.free(); | ||||
| 	clear(tok_map); | ||||
| 	free(tok_map_arena); | ||||
|  | ||||
| 	ssize result = buf_size - remaining; | ||||
|  | ||||
|   | ||||
| @@ -458,7 +458,7 @@ CodeComment def_comment( StrC content ) | ||||
|  | ||||
| 	static char line[ MaxCommentLineLength ]; | ||||
|  | ||||
| 	String      cmt_formatted = String::make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String      cmt_formatted = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	char const* end           = content.Ptr + content.Len; | ||||
| 	char const* scanner       = content.Ptr; | ||||
| 	s32         curr          = 0; | ||||
| @@ -474,15 +474,15 @@ CodeComment def_comment( StrC content ) | ||||
| 		length++; | ||||
|  | ||||
| 		str_copy( line, scanner, length ); | ||||
| 		cmt_formatted.append_fmt( "//%.*s", length, line ); | ||||
| 		append_fmt(cmt_formatted, "//%.*s", length, line ); | ||||
| 		mem_set( line, 0, MaxCommentLineLength ); | ||||
|  | ||||
| 		scanner += length; | ||||
| 	} | ||||
| 	while ( scanner <= end ); | ||||
|  | ||||
| 	if ( cmt_formatted.back() != '\n' ) | ||||
| 		cmt_formatted.append( "\n" ); | ||||
| 	if ( back(cmt_formatted) != '\n' ) | ||||
| 		append( cmt_formatted, "\n" ); | ||||
|  | ||||
| 	Code | ||||
| 	result          = make_code(); | ||||
| @@ -490,7 +490,7 @@ CodeComment def_comment( StrC content ) | ||||
| 	result->Name    = get_cached_string( cmt_formatted ); | ||||
| 	result->Content = result->Name; | ||||
|  | ||||
| 	cmt_formatted.free(); | ||||
| 	free(cmt_formatted); | ||||
|  | ||||
| 	return (CodeComment) result; | ||||
| } | ||||
| @@ -719,14 +719,14 @@ CodeEnum def_enum( StrC name | ||||
| 				return CodeInvalid; | ||||
| 		} | ||||
|  | ||||
| 		result->Type = specifier == EnumClass ? | ||||
| 		result->Type = specifier == EnumDecl_Class ? | ||||
| 			Enum_Class : Enum; | ||||
|  | ||||
| 		result->Body = body; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		result->Type = specifier == EnumClass ? | ||||
| 		result->Type = specifier == EnumDecl_Class ? | ||||
| 			Enum_Class_Fwd : Enum_Fwd; | ||||
| 	} | ||||
|  | ||||
| @@ -1145,16 +1145,16 @@ CodePreprocessCond def_preprocess_cond( EPreprocessCond type, StrC expr ) | ||||
|  | ||||
| 	switch (type) | ||||
| 	{ | ||||
| 		case EPreprocessCond::If: | ||||
| 		case PreprocessCond_If: | ||||
| 			result->Type = Preprocess_If; | ||||
| 		break; | ||||
| 		case EPreprocessCond::IfDef: | ||||
| 		case PreprocessCond_IfDef: | ||||
| 			result->Type = Preprocess_IfDef; | ||||
| 		break; | ||||
| 		case EPreprocessCond::IfNotDef: | ||||
| 		case PreprocessCond_IfNotDef: | ||||
| 			result->Type = Preprocess_IfNotDef; | ||||
| 		break; | ||||
| 		case EPreprocessCond::ElIf: | ||||
| 		case PreprocessCond_ElIf: | ||||
| 			result->Type = Preprocess_ElIf; | ||||
| 		break; | ||||
| 	} | ||||
|   | ||||
| @@ -89,11 +89,11 @@ struct Token | ||||
|  | ||||
| 	String to_string() | ||||
| 	{ | ||||
| 		String result = String::make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
| 		String result = string_make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
|  | ||||
| 		StrC type_str = ETokType::to_str( Type ); | ||||
|  | ||||
| 		result.append_fmt( "Line: %d Column: %d, Type: %.*s Content: %.*s" | ||||
| 		append_fmt( result, "Line: %d Column: %d, Type: %.*s Content: %.*s" | ||||
| 			, Line, Column | ||||
| 			, type_str.Len, type_str.Ptr | ||||
| 			, Length, Text | ||||
| @@ -222,7 +222,7 @@ s32 lex_preprocessor_directive( | ||||
| 	, Token&           token ) | ||||
| { | ||||
| 	char const* hash = scanner; | ||||
| 	Tokens.append( { hash, 1, TokType::Preprocess_Hash, line, column, TF_Preprocess } ); | ||||
| 	append(Tokens, { hash, 1, TokType::Preprocess_Hash, line, column, TF_Preprocess } ); | ||||
|  | ||||
| 	move_forward(); | ||||
| 	SkipWhitespace(); | ||||
| @@ -298,14 +298,14 @@ s32 lex_preprocessor_directive( | ||||
|  | ||||
| 		token.Length = token.Length + token.Text - hash; | ||||
| 		token.Text   = hash; | ||||
| 		Tokens.append( token ); | ||||
| 		append(Tokens, token ); | ||||
| 		return Lex_Continue; // Skip found token, its all handled here. | ||||
| 	} | ||||
|  | ||||
| 	if ( token.Type == TokType::Preprocess_Else || token.Type == TokType::Preprocess_EndIf ) | ||||
| 	{ | ||||
| 		token.Flags |= TF_Preprocess_Cond; | ||||
| 		Tokens.append( token ); | ||||
| 		append(Tokens, token ); | ||||
| 		end_line(); | ||||
| 		return Lex_Continue; | ||||
| 	} | ||||
| @@ -314,7 +314,7 @@ s32 lex_preprocessor_directive( | ||||
| 		token.Flags |= TF_Preprocess_Cond; | ||||
| 	} | ||||
|  | ||||
| 	Tokens.append( token ); | ||||
| 	append(Tokens, token ); | ||||
|  | ||||
| 	SkipWhitespace(); | ||||
|  | ||||
| @@ -338,10 +338,10 @@ s32 lex_preprocessor_directive( | ||||
| 			name.Length++; | ||||
| 		} | ||||
|  | ||||
| 		Tokens.append( name ); | ||||
| 		append(Tokens, name ); | ||||
|  | ||||
| 		u64 key = crc32( name.Text, name.Length ); | ||||
| 		defines.set( key, name ); | ||||
| 		set<StrC>(defines, key, name ); | ||||
| 	} | ||||
|  | ||||
| 	Token preprocess_content = { scanner, 0, TokType::Preprocess_Content, line, column, TF_Preprocess }; | ||||
| @@ -352,7 +352,7 @@ s32 lex_preprocessor_directive( | ||||
|  | ||||
| 		if ( current != '"' && current != '<' ) | ||||
| 		{ | ||||
| 			String directive_str = String::fmt_buf( GlobalAllocator, "%.*s", min( 80, left + preprocess_content.Length ), token.Text ); | ||||
| 			String directive_str = string_fmt_buf( GlobalAllocator, "%.*s", min( 80, left + preprocess_content.Length ), token.Text ); | ||||
|  | ||||
| 			log_failure( "gen::Parser::lex: Expected '\"' or '<' after #include, not '%c' (%d, %d)\n%s" | ||||
| 				, current | ||||
| @@ -384,7 +384,7 @@ s32 lex_preprocessor_directive( | ||||
| 			move_forward(); | ||||
| 		} | ||||
|  | ||||
| 		Tokens.append( preprocess_content ); | ||||
| 		append(Tokens, preprocess_content ); | ||||
| 		return Lex_Continue; // Skip found token, its all handled here. | ||||
| 	} | ||||
|  | ||||
| @@ -419,8 +419,8 @@ s32 lex_preprocessor_directive( | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				String directive_str = String::make_length( GlobalAllocator, token.Text, token.Length ); | ||||
| 				String content_str   = String::fmt_buf( GlobalAllocator, "%.*s", min( 400, left + preprocess_content.Length ), preprocess_content.Text ); | ||||
| 				String directive_str = string_make_length( GlobalAllocator, token.Text, token.Length ); | ||||
| 				String content_str   = string_fmt_buf( GlobalAllocator, "%.*s", min( 400, left + preprocess_content.Length ), preprocess_content.Text ); | ||||
|  | ||||
| 				log_failure( "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)" | ||||
| 							" in preprocessor directive '%s' (%d, %d)\n%s" | ||||
| @@ -446,7 +446,7 @@ s32 lex_preprocessor_directive( | ||||
| 		preprocess_content.Length++; | ||||
| 	} | ||||
|  | ||||
| 	Tokens.append( preprocess_content ); | ||||
| 	append(Tokens, preprocess_content ); | ||||
| 	return Lex_Continue; // Skip found token, its all handled here. | ||||
| } | ||||
|  | ||||
| @@ -461,7 +461,7 @@ void lex_found_token( StrC& content | ||||
| { | ||||
| 	if ( token.Type != TokType::Invalid ) | ||||
| 	{ | ||||
| 		Tokens.append( token ); | ||||
| 		append(Tokens, token ); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| @@ -488,7 +488,7 @@ void lex_found_token( StrC& content | ||||
| 		} | ||||
|  | ||||
| 		token.Type = type; | ||||
| 		Tokens.append( token ); | ||||
| 		append(Tokens, token ); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| @@ -498,7 +498,7 @@ void lex_found_token( StrC& content | ||||
| 	{ | ||||
| 		token.Type   = type; | ||||
| 		token.Flags |= TF_Specifier; | ||||
| 		Tokens.append( token ); | ||||
| 		append(Tokens, token ); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| @@ -506,7 +506,7 @@ void lex_found_token( StrC& content | ||||
| 	if ( type != TokType::Invalid ) | ||||
| 	{ | ||||
| 		token.Type = type; | ||||
| 		Tokens.append( token ); | ||||
| 		append(Tokens, token ); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| @@ -516,7 +516,7 @@ void lex_found_token( StrC& content | ||||
| 	else | ||||
| 		key = crc32( token.Text, token.Length ); | ||||
|  | ||||
| 	StrC* define = defines.get( key ); | ||||
| 	StrC* define = get(defines, key ); | ||||
| 	if ( define ) | ||||
| 	{ | ||||
| 		token.Type = TokType::Preprocess_Macro; | ||||
| @@ -558,7 +558,7 @@ void lex_found_token( StrC& content | ||||
| 		token.Type = TokType::Identifier; | ||||
| 	} | ||||
|  | ||||
| 	Tokens.append( token ); | ||||
| 	append(Tokens, token ); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -582,11 +582,11 @@ TokArray lex( StrC content ) | ||||
| 		return { { nullptr }, 0 }; | ||||
| 	} | ||||
|  | ||||
| 	for ( StringCached entry : PreprocessorDefines ) | ||||
| 	foreach( StringCached, entry, PreprocessorDefines ) | ||||
| 	{ | ||||
| 		s32         length  = 0; | ||||
| 		char const* scanner = entry.Data; | ||||
| 		while ( entry.length() > length && (char_is_alphanumeric( *scanner ) || *scanner == '_') ) | ||||
| 		while ( GEN_NS length(entry) > length && (char_is_alphanumeric( *scanner ) || *scanner == '_') ) | ||||
| 		{ | ||||
| 			scanner++; | ||||
| 			length ++; | ||||
| @@ -597,10 +597,10 @@ TokArray lex( StrC content ) | ||||
| 		} | ||||
|  | ||||
| 		u64 key = crc32( entry.Data, length ); | ||||
| 		defines.set( key, entry ); | ||||
| 		set<StrC>(defines, key, entry ); | ||||
| 	} | ||||
|  | ||||
| 	Tokens.clear(); | ||||
| 	clear(Tokens); | ||||
|  | ||||
| 	while (left ) | ||||
| 	{ | ||||
| @@ -630,7 +630,7 @@ TokArray lex( StrC content ) | ||||
| 				token.Type = TokType::NewLine; | ||||
| 				token.Length++; | ||||
|  | ||||
| 				Tokens.append( token ); | ||||
| 				append(Tokens, token ); | ||||
| 				continue; | ||||
| 			} | ||||
| 		} | ||||
| @@ -678,7 +678,7 @@ TokArray lex( StrC content ) | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						String context_str = String::fmt_buf( GlobalAllocator, "%s", scanner, min( 100, left ) ); | ||||
| 						String context_str = string_fmt_buf( GlobalAllocator, "%s", scanner, min( 100, left ) ); | ||||
|  | ||||
| 						log_failure( "gen::lex: invalid varadic argument, expected '...' got '..%c' (%d, %d)\n%s", current, line, column, context_str ); | ||||
| 					} | ||||
| @@ -1099,7 +1099,7 @@ TokArray lex( StrC content ) | ||||
| 							move_forward(); | ||||
| 							token.Length++; | ||||
| 						} | ||||
| 						Tokens.append( token ); | ||||
| 						append(Tokens, token ); | ||||
| 						continue; | ||||
| 					} | ||||
| 					else if ( current == '*' ) | ||||
| @@ -1135,7 +1135,7 @@ TokArray lex( StrC content ) | ||||
| 							move_forward(); | ||||
| 							token.Length++; | ||||
| 						} | ||||
| 						Tokens.append( token ); | ||||
| 						append(Tokens, token ); | ||||
| 						// end_line(); | ||||
| 						continue; | ||||
| 					} | ||||
| @@ -1228,9 +1228,9 @@ TokArray lex( StrC content ) | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			s32 start = max( 0, Tokens.num() - 100 ); | ||||
| 			s32 start = max( 0, num(Tokens) - 100 ); | ||||
| 			log_fmt("\n%d\n", start); | ||||
| 			for ( s32 idx = start; idx < Tokens.num(); idx++ ) | ||||
| 			for ( s32 idx = start; idx < num(Tokens); idx++ ) | ||||
| 			{ | ||||
| 				log_fmt( "Token %d Type: %s : %.*s\n" | ||||
| 					, idx | ||||
| @@ -1239,7 +1239,7 @@ TokArray lex( StrC content ) | ||||
| 				); | ||||
| 			} | ||||
|  | ||||
| 			String context_str = String::fmt_buf( GlobalAllocator, "%.*s", min( 100, left ), scanner ); | ||||
| 			String context_str = string_fmt_buf( GlobalAllocator, "%.*s", min( 100, left ), scanner ); | ||||
| 			log_failure( "Failed to lex token '%c' (%d, %d)\n%s", current, line, column, context_str ); | ||||
|  | ||||
| 			// Skip to next whitespace since we can't know if anything else is valid until then. | ||||
| @@ -1253,13 +1253,13 @@ TokArray lex( StrC content ) | ||||
| 		lex_found_token( content, left, scanner, line, column, defines, token ); | ||||
| 	} | ||||
|  | ||||
| 	if ( Tokens.num() == 0 ) | ||||
| 	if ( num(Tokens) == 0 ) | ||||
| 	{ | ||||
| 		log_failure( "Failed to lex any tokens" ); | ||||
| 		return { { nullptr }, 0 }; | ||||
| 	} | ||||
|  | ||||
| 	defines.clear(); | ||||
| 	clear(defines); | ||||
| 	// defines_map_arena.free(); | ||||
| 	return { Tokens, 0 }; | ||||
| } | ||||
|   | ||||
| @@ -45,31 +45,31 @@ struct ParseContext | ||||
|  | ||||
| 	String to_string() | ||||
| 	{ | ||||
| 		String result = String::make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
| 		String result = string_make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
|  | ||||
| 		Token scope_start = Scope->Start; | ||||
| 		Token last_valid  = Tokens.Idx >= Tokens.Arr.num() ? Tokens.Arr[Tokens.Arr.num() -1] : Tokens.current(); | ||||
| 		Token last_valid  = Tokens.Idx >= num(Tokens.Arr) ? Tokens.Arr[num(Tokens.Arr) -1] : Tokens.current(); | ||||
|  | ||||
| 		sptr        length  = scope_start.Length; | ||||
| 		char const* current = scope_start.Text + length; | ||||
| 		while ( current <= Tokens.Arr.back().Text && *current != '\n' && length < 74 ) | ||||
| 		while ( current <= back(Tokens.Arr).Text && *current != '\n' && length < 74 ) | ||||
| 		{ | ||||
| 			current++; | ||||
| 			length++; | ||||
| 		} | ||||
|  | ||||
| 		String line = String::make( GlobalAllocator, { length, scope_start.Text } ); | ||||
| 		result.append_fmt("\tScope    : %s\n", line ); | ||||
| 		line.free(); | ||||
| 		String line = string_make( GlobalAllocator, { length, scope_start.Text } ); | ||||
| 		append_fmt( result, "\tScope    : %s\n", line ); | ||||
| 		free(line); | ||||
|  | ||||
| 		sptr   dist            = (sptr)last_valid.Text - (sptr)scope_start.Text + 2; | ||||
| 		sptr   length_from_err = dist; | ||||
| 		String line_from_err   = String::make( GlobalAllocator, { length_from_err, last_valid.Text } ); | ||||
| 		String line_from_err   = string_make( GlobalAllocator, { length_from_err, last_valid.Text } ); | ||||
|  | ||||
| 		if ( length_from_err < 100 ) | ||||
| 			result.append_fmt("\t(%d, %d):%*c\n", last_valid.Line, last_valid.Column, length_from_err, '^' ); | ||||
| 			append_fmt(result, "\t(%d, %d):%*c\n", last_valid.Line, last_valid.Column, length_from_err, '^' ); | ||||
| 		else | ||||
| 			result.append_fmt("\t(%d, %d)\n", last_valid.Line, last_valid.Column ); | ||||
| 			append_fmt(result, "\t(%d, %d)\n", last_valid.Line, last_valid.Column ); | ||||
|  | ||||
| 		StackNode* curr_scope = Scope; | ||||
| 		s32 level = 0; | ||||
| @@ -77,11 +77,11 @@ struct ParseContext | ||||
| 		{ | ||||
| 			if ( curr_scope->Name ) | ||||
| 			{ | ||||
| 				result.append_fmt("\t%d: %s, AST Name: %.*s\n", level, curr_scope->ProcName.Ptr, curr_scope->Name.Length, curr_scope->Name.Text ); | ||||
| 				append_fmt(result, "\t%d: %s, AST Name: %.*s\n", level, curr_scope->ProcName.Ptr, curr_scope->Name.Length, curr_scope->Name.Text ); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				result.append_fmt("\t%d: %s\n", level, curr_scope->ProcName.Ptr ); | ||||
| 				append_fmt(result, "\t%d: %s\n", level, curr_scope->ProcName.Ptr ); | ||||
| 			} | ||||
|  | ||||
| 			curr_scope = curr_scope->Prev; | ||||
| @@ -96,7 +96,7 @@ global ParseContext Context; | ||||
|  | ||||
| bool TokArray::__eat( TokType type ) | ||||
| { | ||||
| 	if ( Arr.num() - Idx <= 0 ) | ||||
| 	if ( num(Arr) - Idx <= 0 ) | ||||
| 	{ | ||||
| 		log_failure( "No tokens left.\n%s", Context.to_string() ); | ||||
| 		return false; | ||||
| @@ -132,12 +132,12 @@ bool TokArray::__eat( TokType type ) | ||||
| internal | ||||
| void init() | ||||
| { | ||||
| 	Tokens = Array<Token>::init_reserve( LexArena | ||||
| 		, ( LexAllocator_Size - sizeof( Array<Token>::Header ) ) / sizeof(Token) | ||||
| 	Tokens = array_init_reserve<Token>( allocator_info(LexArena) | ||||
| 		, ( LexAllocator_Size - sizeof( ArrayHeader ) ) / sizeof(Token) | ||||
| 	); | ||||
|  | ||||
| 	defines_map_arena = Arena_256KB::init(); | ||||
| 	defines           = HashTable<StrC>::init_reserve( defines_map_arena, 256 ); | ||||
| 	fixed_arena_init(defines_map_arena); | ||||
| 	defines = hashtable_init_reserve<StrC>( allocator_info(defines_map_arena), 256 ); | ||||
| } | ||||
|  | ||||
| internal | ||||
| @@ -167,7 +167,7 @@ if ( def.Ptr == nullptr )                                                      \ | ||||
| #	define prevtok        Context.Tokens.previous() | ||||
| #	define nexttok		  Context.Tokens.next() | ||||
| #	define eat( Type_ )   Context.Tokens.__eat( Type_ ) | ||||
| #	define left           ( Context.Tokens.Arr.num() - Context.Tokens.Idx ) | ||||
| #	define left           ( num(Context.Tokens.Arr) - Context.Tokens.Idx ) | ||||
|  | ||||
| #ifdef check | ||||
| #define CHECK_WAS_DEFINED | ||||
| @@ -243,7 +243,7 @@ constexpr bool strip_formatting_dont_preserve_newlines = false; | ||||
| internal | ||||
| String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | ||||
| { | ||||
| 	String content = String::make_reserve( GlobalAllocator, raw_text.Len ); | ||||
| 	String content = string_make_reserve( GlobalAllocator, raw_text.Len ); | ||||
|  | ||||
| 	if ( raw_text.Len == 0 ) | ||||
| 		return content; | ||||
| @@ -290,7 +290,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | ||||
| 			if ( tokleft ) | ||||
| 				move_fwd(); | ||||
|  | ||||
| 			content.append( cut_ptr, cut_length ); | ||||
| 			append( content, cut_ptr, cut_length ); | ||||
| 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | ||||
| 			continue; | ||||
| 		} | ||||
| @@ -312,7 +312,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | ||||
| 			if ( tokleft ) | ||||
| 				move_fwd(); | ||||
|  | ||||
| 			content.append( cut_ptr, cut_length ); | ||||
| 			append( content, cut_ptr, cut_length ); | ||||
| 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | ||||
| 			continue; | ||||
| 		} | ||||
| @@ -326,7 +326,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | ||||
| 			scanner += 2; | ||||
| 			tokleft -= 2; | ||||
|  | ||||
| 			content.append( cut_ptr, cut_length ); | ||||
| 			append( content,  cut_ptr, cut_length ); | ||||
| 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | ||||
| 			continue; | ||||
| 		} | ||||
| @@ -345,7 +345,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | ||||
| 			if (tokleft) | ||||
| 				move_fwd(); | ||||
|  | ||||
| 			content.append( cut_ptr, cut_length ); | ||||
| 			append( content,  cut_ptr, cut_length ); | ||||
| 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | ||||
| 			continue; | ||||
| 		} | ||||
| @@ -354,10 +354,10 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | ||||
| 		if (scanner[0] == '\t') | ||||
| 		{ | ||||
| 			if (pos > last_cut) | ||||
| 				content.append(cut_ptr, cut_length); | ||||
| 				append( content, cut_ptr, cut_length); | ||||
|  | ||||
| 			if ( content.back() != ' ' ) | ||||
| 				content.append(' '); | ||||
| 			if ( back( content ) != ' ' ) | ||||
| 				append( content, ' '); | ||||
|  | ||||
| 			move_fwd(); | ||||
| 			last_cut = sptr(scanner) - sptr(raw_text.Ptr); | ||||
| @@ -373,17 +373,17 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | ||||
| 				scanner += 2; | ||||
| 				tokleft -= 2; | ||||
|  | ||||
| 				content.append( cut_ptr, cut_length ); | ||||
| 				append( content,  cut_ptr, cut_length ); | ||||
| 				last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | ||||
| 				continue; | ||||
| 			} | ||||
|  | ||||
| 			if ( pos > last_cut ) | ||||
| 				content.append( cut_ptr, cut_length ); | ||||
| 				append( content,  cut_ptr, cut_length ); | ||||
|  | ||||
| 			// Replace with a space | ||||
| 			if ( content.back() != ' ' ) | ||||
| 				content.append( ' ' ); | ||||
| 			if ( back( content ) != ' ' ) | ||||
| 				append( content,  ' ' ); | ||||
|  | ||||
| 			scanner += 2; | ||||
| 			tokleft -= 2; | ||||
| @@ -400,17 +400,17 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | ||||
|  | ||||
| 				move_fwd(); | ||||
|  | ||||
| 				content.append( cut_ptr, cut_length ); | ||||
| 				append( content,  cut_ptr, cut_length ); | ||||
| 				last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | ||||
| 				continue; | ||||
| 			} | ||||
|  | ||||
| 			if ( pos > last_cut ) | ||||
| 				content.append( cut_ptr, cut_length ); | ||||
| 				append( content,  cut_ptr, cut_length ); | ||||
|  | ||||
| 			// Replace with a space | ||||
| 			if ( content.back() != ' ' ) | ||||
| 				content.append( ' ' ); | ||||
| 			if ( back( content ) != ' ' ) | ||||
| 				append( content,  ' ' ); | ||||
|  | ||||
| 			move_fwd(); | ||||
|  | ||||
| @@ -421,7 +421,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | ||||
| 		// Escaped newlines | ||||
| 		if ( scanner[0] == '\\' ) | ||||
| 		{ | ||||
| 			content.append( cut_ptr, cut_length ); | ||||
| 			append( content,  cut_ptr, cut_length ); | ||||
|  | ||||
| 			s32 amount_to_skip = 1; | ||||
| 			if ( tokleft > 1 && scanner[1] == '\n' ) | ||||
| @@ -448,7 +448,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | ||||
| 		// Consectuive spaces | ||||
| 		if ( tokleft > 1 && char_is_space( scanner[0] ) && char_is_space( scanner[ 1 ] ) ) | ||||
| 		{ | ||||
| 			content.append( cut_ptr, cut_length ); | ||||
| 			append( content,  cut_ptr, cut_length ); | ||||
| 			do | ||||
| 			{ | ||||
| 				move_fwd(); | ||||
| @@ -458,8 +458,8 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | ||||
| 			last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); | ||||
|  | ||||
| 			// Preserve only 1 space of formattting | ||||
| 			if ( content.back() != ' ' ) | ||||
| 				content.append( ' ' ); | ||||
| 			if ( back( content ) != ' ' ) | ||||
| 				append( content,  ' ' ); | ||||
|  | ||||
| 			continue; | ||||
| 		} | ||||
| @@ -469,7 +469,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) | ||||
|  | ||||
| 	if ( last_cut < raw_text.Len ) | ||||
| 	{ | ||||
| 		content.append( cut_ptr, raw_text.Len - last_cut ); | ||||
| 		append( content,  cut_ptr, raw_text.Len - last_cut ); | ||||
| 	} | ||||
|  | ||||
| #undef cut_ptr | ||||
| @@ -682,17 +682,17 @@ Code parse_class_struct( TokType which, bool inplace_def = false ) | ||||
|  | ||||
| 	Token name { nullptr, 0, TokType::Invalid }; | ||||
|  | ||||
| 	AccessSpec     access     = AccessSpec::Default; | ||||
| 	AccessSpec     access     = AccessSpec_Default; | ||||
| 	CodeType       parent     = { nullptr }; | ||||
| 	CodeBody       body       = { nullptr }; | ||||
| 	CodeAttributes attributes = { nullptr }; | ||||
| 	ModuleFlag     mflags     = ModuleFlag::None; | ||||
| 	ModuleFlag     mflags     = ModuleFlag_None; | ||||
|  | ||||
| 	CodeClass result = CodeInvalid; | ||||
|  | ||||
| 	if ( check(TokType::Module_Export) ) | ||||
| 	{ | ||||
| 		mflags = ModuleFlag::Export; | ||||
| 		mflags = ModuleFlag_Export; | ||||
| 		eat( TokType::Module_Export ); | ||||
| 	} | ||||
| 	// <ModuleFlags> | ||||
| @@ -712,7 +712,10 @@ Code parse_class_struct( TokType which, bool inplace_def = false ) | ||||
|  | ||||
| 	local_persist | ||||
| 	char interface_arr_mem[ kilobytes(4) ] {0}; | ||||
| 	Array<CodeType> interfaces = Array<CodeType>::init_reserve( Arena::init_from_memory(interface_arr_mem, kilobytes(4) ), 4 ); | ||||
| 	Array<CodeType> interfaces; { | ||||
| 		Arena arena = arena_init_from_memory( interface_arr_mem, kilobytes(4) ); | ||||
| 		interfaces  = array_init_reserve<CodeType>( allocator_info(arena), 4 ); | ||||
| 	} | ||||
|  | ||||
| 	// TODO(Ed) : Make an AST_DerivedType, we'll store any arbitary derived type into there as a linear linked list of them. | ||||
| 	if ( check( TokType::Assign_Classifer ) ) | ||||
| @@ -742,7 +745,7 @@ Code parse_class_struct( TokType which, bool inplace_def = false ) | ||||
| 			} | ||||
| 			Token interface_tok = parse_identifier(); | ||||
|  | ||||
| 			interfaces.append( def_type( interface_tok ) ); | ||||
| 			append(interfaces, def_type( interface_tok ) ); | ||||
| 			// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier> <Name>, ... | ||||
| 		} | ||||
| 	} | ||||
| @@ -774,7 +777,7 @@ Code parse_class_struct( TokType which, bool inplace_def = false ) | ||||
| 	if ( inline_cmt ) | ||||
| 		result->InlineCmt = inline_cmt; | ||||
|  | ||||
| 	interfaces.free(); | ||||
| 	free(interfaces); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| @@ -1036,8 +1039,8 @@ CodeBody parse_class_struct_body( TokType which, Token name ) | ||||
|  | ||||
| 					if ( attributes ) | ||||
| 					{ | ||||
| 						String fused = String::make_reserve( GlobalAllocator, attributes->Content.length() + more_attributes->Content.length() ); | ||||
| 						fused.append_fmt( "%S %S", attributes->Content, more_attributes->Content ); | ||||
| 						String fused = string_make_reserve( GlobalAllocator, length(attributes->Content) + length(more_attributes->Content) ); | ||||
| 						append_fmt( fused, "%S %S", attributes->Content, more_attributes->Content ); | ||||
|  | ||||
| 						attributes->Name    = get_cached_string(fused); | ||||
| 						attributes->Content = attributes->Name; | ||||
| @@ -1149,7 +1152,7 @@ Code parse_complicated_definition( TokType which ) | ||||
|  | ||||
| 	s32 idx         = tokens.Idx; | ||||
| 	s32 level       = 0; | ||||
| 	for ( ; idx < tokens.Arr.num(); idx++ ) | ||||
| 	for ( ; idx < num(tokens.Arr); idx++ ) | ||||
| 	{ | ||||
| 		if ( tokens[ idx ].Type == TokType::BraceCurly_Open ) | ||||
| 			level++; | ||||
| @@ -1481,8 +1484,8 @@ CodeFn parse_function_after_name( | ||||
| 	using namespace ECode; | ||||
|  | ||||
| 	String | ||||
| 	name_stripped = String::make( GlobalAllocator, name ); | ||||
| 	name_stripped.strip_space(); | ||||
| 	name_stripped = string_make( GlobalAllocator, name ); | ||||
| 	strip_space(name_stripped); | ||||
|  | ||||
| 	CodeFn | ||||
| 	result              = (CodeFn) make_code(); | ||||
| @@ -1834,7 +1837,7 @@ CodeBody parse_global_nspace( CodeT which ) | ||||
| 				bool found_operator_cast_outside_class_implmentation = false; | ||||
| 				s32  idx = Context.Tokens.Idx; | ||||
|  | ||||
| 				for ( ; idx < Context.Tokens.Arr.num(); idx++ ) | ||||
| 				for ( ; idx < num(Context.Tokens.Arr); idx++ ) | ||||
| 				{ | ||||
| 					Token tok = Context.Tokens[ idx ]; | ||||
|  | ||||
| @@ -1906,14 +1909,14 @@ Code parse_global_nspace_constructor_destructor( CodeSpecifiers specifiers ) | ||||
|  | ||||
| 	s32   idx = tokens.Idx; | ||||
| 	Token nav = tokens[ idx ]; | ||||
| 	for ( ; idx < tokens.Arr.num(); idx++, nav = tokens[ idx ] ) | ||||
| 	for ( ; idx < num(tokens.Arr); idx++, nav = tokens[ idx ] ) | ||||
| 	{ | ||||
| 		if ( nav.Text[0] == '<' ) | ||||
| 		{ | ||||
| 			// Skip templated expressions as they mey have expressions with the () operators | ||||
| 			s32 capture_level  = 0; | ||||
| 			s32 template_level = 0; | ||||
| 			for ( ; idx < tokens.Arr.num(); idx++, nav = tokens[idx] ) | ||||
| 			for ( ; idx < num(tokens.Arr); idx++, nav = tokens[idx] ) | ||||
| 			{ | ||||
| 				if (nav.Text[ 0 ] == '<') | ||||
| 					++ template_level; | ||||
| @@ -2508,7 +2511,7 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes | ||||
| 	bool found_operator = false; | ||||
| 	s32  idx            = Context.Tokens.Idx; | ||||
|  | ||||
| 	for ( ; idx < Context.Tokens.Arr.num(); idx++ ) | ||||
| 	for ( ; idx < num(Context.Tokens.Arr); idx++ ) | ||||
| 	{ | ||||
| 		Token tok = Context.Tokens[ idx ]; | ||||
|  | ||||
| @@ -2531,7 +2534,7 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes | ||||
| 	if ( found_operator ) | ||||
| 	{ | ||||
| 		// Dealing with an operator overload | ||||
| 		result = parse_operator_after_ret_type( ModuleFlag::None, attributes, specifiers, type ); | ||||
| 		result = parse_operator_after_ret_type( ModuleFlag_None, attributes, specifiers, type ); | ||||
| 		// <Attributes> <Specifiers> <ReturnType> operator ... | ||||
| 	} | ||||
| 	else | ||||
| @@ -2549,7 +2552,7 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes | ||||
| 		if ( detected_capture && ! detected_comma ) | ||||
| 		{ | ||||
| 			// Dealing with a function | ||||
| 			result = parse_function_after_name( ModuleFlag::None, attributes, specifiers, type, name ); | ||||
| 			result = parse_function_after_name( ModuleFlag_None, attributes, specifiers, type, name ); | ||||
| 			// <Attributes> <Specifiers> <ReturnType> <Name> ( ... | ||||
| 		} | ||||
| 		else | ||||
| @@ -2562,7 +2565,7 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes | ||||
| 			} | ||||
|  | ||||
| 			// Dealing with a variable | ||||
| 			result = parse_variable_after_name( ModuleFlag::None, attributes, specifiers, type, name ); | ||||
| 			result = parse_variable_after_name( ModuleFlag_None, attributes, specifiers, type, name ); | ||||
| 			// <Attributes> <Specifiers> <ValueType> <Name> ... | ||||
| 		} | ||||
| 	} | ||||
| @@ -3316,7 +3319,7 @@ CodeVar parse_variable_declaration_list() | ||||
| 		eat( TokType::Identifier ); | ||||
| 		// , <Specifiers> <Name> | ||||
|  | ||||
| 		CodeVar var = parse_variable_after_name( ModuleFlag::None, NoCode, specifiers, NoCode, name ); | ||||
| 		CodeVar var = parse_variable_after_name( ModuleFlag_None, NoCode, specifiers, NoCode, name ); | ||||
| 		// , <Specifiers> <Name> ... | ||||
|  | ||||
| 		if ( ! result ) | ||||
| @@ -3586,6 +3589,8 @@ CodeEnum parse_enum( bool inplace_def ) | ||||
| 	} | ||||
| 	// enum <class> <Attributes> <Name> | ||||
|  | ||||
| 	b32  use_macro_underlying = false; | ||||
| 	Code underlying_macro = { nullptr }; | ||||
| 	if ( currtok.Type == TokType::Assign_Classifer ) | ||||
| 	{ | ||||
| 		eat( TokType::Assign_Classifer ); | ||||
| @@ -3600,6 +3605,17 @@ CodeEnum parse_enum( bool inplace_def ) | ||||
| 		} | ||||
| 		// enum <class> <Attributes> <Name> : <UnderlyingType> | ||||
| 	} | ||||
| 	else if ( currtok.Type == TokType::Preprocess_Define ) | ||||
| 	{ | ||||
| 		// We'll support the enum_underlying macro | ||||
| 		StrC sig = txt("enum_underlying"); | ||||
|  | ||||
| 		if (currtok.Length >= sig.Len && str_compare(currtok.Text, sig.Ptr, sig.Len) == 0 ) | ||||
| 		{ | ||||
| 			use_macro_underlying = true; | ||||
| 			underlying_macro     = parse_simple_preprocess( ETokType::Preprocess_Macro); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	CodeBody body = { nullptr }; | ||||
|  | ||||
| @@ -3767,11 +3783,18 @@ CodeEnum parse_enum( bool inplace_def ) | ||||
| 		result->Attributes = attributes; | ||||
|  | ||||
| 	if ( type ) | ||||
| 		result->UnderlyingType = type; | ||||
| 	{ | ||||
| 		result->EnumUnderlyingMacro = use_macro_underlying; | ||||
| 		if ( use_macro_underlying ) | ||||
| 			result->UnderlyingTypeMacro = underlying_macro; | ||||
| 		else | ||||
| 			result->UnderlyingType = type; | ||||
| 	} | ||||
|  | ||||
| 	if ( inline_cmt ) | ||||
| 		result->InlineCmt = inline_cmt; | ||||
|  | ||||
|  | ||||
| 	Context.pop(); | ||||
| 	return result; | ||||
| } | ||||
| @@ -3857,7 +3880,7 @@ CodeFriend parse_friend() | ||||
| 		Context.Scope->Name = name; | ||||
| 		// friend <ReturnType> <Name> | ||||
|  | ||||
| 		function = parse_function_after_name( ModuleFlag::None, NoCode, NoCode, type, name ); | ||||
| 		function = parse_function_after_name( ModuleFlag_None, NoCode, NoCode, type, name ); | ||||
|  | ||||
| 		// Parameter list | ||||
| 		// CodeParam params = parse_params(); | ||||
| @@ -3911,11 +3934,11 @@ CodeFn parse_function() | ||||
|  | ||||
| 	CodeAttributes attributes = { nullptr }; | ||||
| 	CodeSpecifiers specifiers = { nullptr }; | ||||
| 	ModuleFlag     mflags     = ModuleFlag::None; | ||||
| 	ModuleFlag     mflags     = ModuleFlag_None; | ||||
|  | ||||
| 	if ( check(TokType::Module_Export) ) | ||||
| 	{ | ||||
| 		mflags = ModuleFlag::Export; | ||||
| 		mflags = ModuleFlag_Export; | ||||
| 		eat( TokType::Module_Export ); | ||||
| 	} | ||||
| 	// <export> | ||||
| @@ -4021,14 +4044,14 @@ CodeOperator parse_operator() | ||||
|  | ||||
| 	CodeAttributes attributes = { nullptr }; | ||||
| 	CodeSpecifiers specifiers = { nullptr }; | ||||
| 	ModuleFlag     mflags     = ModuleFlag::None; | ||||
| 	ModuleFlag     mflags     = ModuleFlag_None; | ||||
|  | ||||
| 	SpecifierT specs_found[16] { ESpecifier::NumSpecifiers }; | ||||
| 	s32        NumSpecifiers = 0; | ||||
|  | ||||
| 	if ( check(TokType::Module_Export) ) | ||||
| 	{ | ||||
| 		mflags = ModuleFlag::Export; | ||||
| 		mflags = ModuleFlag_Export; | ||||
| 		eat( TokType::Module_Export ); | ||||
| 	} | ||||
| 	// <export> | ||||
| @@ -4111,7 +4134,7 @@ CodeOpCast parse_operator_cast( CodeSpecifiers specifiers ) | ||||
| 	Code type = parse_type(); | ||||
| 	// <Specifiers> <Qualifier> :: ... operator <UnderlyingType> | ||||
|  | ||||
| 	Context.Scope->Name = { type->Name.Data, type->Name.length() }; | ||||
| 	Context.Scope->Name = { type->Name.Data, length(type->Name) }; | ||||
|  | ||||
| 	eat( TokType::Capture_Start ); | ||||
| 	eat( TokType::Capture_End ); | ||||
| @@ -4209,11 +4232,11 @@ CodeTemplate parse_template() | ||||
|  | ||||
| 	push_scope(); | ||||
|  | ||||
| 	ModuleFlag mflags = ModuleFlag::None; | ||||
| 	ModuleFlag mflags = ModuleFlag_None; | ||||
|  | ||||
| 	if ( check( TokType::Module_Export ) ) | ||||
| 	{ | ||||
| 		mflags = ModuleFlag::Export; | ||||
| 		mflags = ModuleFlag_Export; | ||||
| 		eat( TokType::Module_Export ); | ||||
| 	} | ||||
| 	// <export> template | ||||
| @@ -4345,7 +4368,7 @@ CodeTemplate parse_template() | ||||
| 			bool found_operator_cast_outside_class_implmentation = false; | ||||
| 			s32  idx = Context.Tokens.Idx; | ||||
|  | ||||
| 			for ( ; idx < Context.Tokens.Arr.num(); idx++ ) | ||||
| 			for ( ; idx < num(Context.Tokens.Arr); idx++ ) | ||||
| 			{ | ||||
| 				Token tok = Context.Tokens[ idx ]; | ||||
|  | ||||
| @@ -4383,6 +4406,7 @@ CodeTemplate parse_template() | ||||
| 	result->Params      = params; | ||||
| 	result->Declaration = definition; | ||||
| 	result->ModuleFlags = mflags; | ||||
| 	// result->Name        = definition->Name; | ||||
|  | ||||
| 	Context.pop(); | ||||
| 	return result; | ||||
| @@ -4852,11 +4876,11 @@ CodeTypedef parse_typedef() | ||||
| 	Code  array_expr  = { nullptr }; | ||||
| 	Code  type        = { nullptr }; | ||||
|  | ||||
| 	ModuleFlag mflags = ModuleFlag::None; | ||||
| 	ModuleFlag mflags = ModuleFlag_None; | ||||
|  | ||||
| 	if ( check(TokType::Module_Export) ) | ||||
| 	{ | ||||
| 		mflags = ModuleFlag::Export; | ||||
| 		mflags = ModuleFlag_Export; | ||||
| 		eat( TokType::Module_Export ); | ||||
| 	} | ||||
| 	// <ModuleFlags> | ||||
| @@ -4893,7 +4917,7 @@ CodeTypedef parse_typedef() | ||||
|  | ||||
| 			s32 idx = tokens.Idx; | ||||
| 			s32 level = 0; | ||||
| 			for ( ; idx < tokens.Arr.num(); idx ++ ) | ||||
| 			for ( ; idx < num(tokens.Arr); idx ++ ) | ||||
| 			{ | ||||
| 				if ( tokens[idx].Type == TokType::BraceCurly_Open ) | ||||
| 					level++; | ||||
| @@ -5047,11 +5071,11 @@ CodeUnion parse_union( bool inplace_def ) | ||||
| { | ||||
| 	push_scope(); | ||||
|  | ||||
| 	ModuleFlag mflags = ModuleFlag::None; | ||||
| 	ModuleFlag mflags = ModuleFlag_None; | ||||
|  | ||||
| 	if ( check(TokType::Module_Export) ) | ||||
| 	{ | ||||
| 		mflags = ModuleFlag::Export; | ||||
| 		mflags = ModuleFlag_Export; | ||||
| 		eat( TokType::Module_Export ); | ||||
| 	} | ||||
| 	// <ModuleFlags> | ||||
| @@ -5196,12 +5220,12 @@ CodeUsing parse_using() | ||||
|  | ||||
| 	bool is_namespace = false; | ||||
|  | ||||
| 	ModuleFlag     mflags     = ModuleFlag::None; | ||||
| 	ModuleFlag     mflags     = ModuleFlag_None; | ||||
| 	CodeAttributes attributes = { nullptr }; | ||||
|  | ||||
| 	if ( check(TokType::Module_Export) ) | ||||
| 	{ | ||||
| 		mflags = ModuleFlag::Export; | ||||
| 		mflags = ModuleFlag_Export; | ||||
| 		eat( TokType::Module_Export ); | ||||
| 	} | ||||
| 	// <ModuleFlags> | ||||
| @@ -5290,13 +5314,13 @@ CodeVar parse_variable() | ||||
| 	SpecifierT specs_found[16] { ESpecifier::NumSpecifiers }; | ||||
| 	s32        NumSpecifiers = 0; | ||||
|  | ||||
| 	ModuleFlag	   mflags     = ModuleFlag::None; | ||||
| 	ModuleFlag	   mflags     = ModuleFlag_None; | ||||
| 	CodeAttributes attributes = { nullptr }; | ||||
| 	CodeSpecifiers specifiers = { nullptr }; | ||||
|  | ||||
| 	if ( check(TokType::Module_Export) ) | ||||
| 	{ | ||||
| 		mflags = ModuleFlag::Export; | ||||
| 		mflags = ModuleFlag_Export; | ||||
| 		eat( TokType::Module_Export ); | ||||
| 	} | ||||
| 	// <ModuleFlags> | ||||
|   | ||||
| @@ -13,63 +13,71 @@ using LogFailType = ssize(*)(char const*, ...); | ||||
| 	#define log_failure GEN_FATAL | ||||
| #endif | ||||
|  | ||||
| enum class AccessSpec : u32 | ||||
| enum AccessSpec enum_underlying(u32) | ||||
| { | ||||
| 	Default, | ||||
| 	Private, | ||||
| 	Protected, | ||||
| 	Public, | ||||
| 	AccessSpec_Default, | ||||
| 	AccessSpec_Private, | ||||
| 	AccessSpec_Protected, | ||||
| 	AccessSpec_Public, | ||||
|  | ||||
| 	Num_AccessSpec, | ||||
| 	Invalid, | ||||
| 	AccessSpec_Num_AccessSpec, | ||||
| 	AccessSpec_Invalid, | ||||
|  | ||||
| 	AccessSpec_SizeDef = GEN_U32_MAX, | ||||
| }; | ||||
| static_assert( size_of(AccessSpec) == size_of(u32)); | ||||
|  | ||||
| inline | ||||
| char const* to_str( AccessSpec type ) | ||||
| { | ||||
| 	local_persist | ||||
| 	char const* lookup[ (u32)AccessSpec::Num_AccessSpec ] = { | ||||
| 	char const* lookup[ (u32)AccessSpec_Num_AccessSpec ] = { | ||||
| 		"", | ||||
| 		"private", | ||||
| 		"protected", | ||||
| 		"public", | ||||
| 	}; | ||||
|  | ||||
| 	if ( type > AccessSpec::Public ) | ||||
| 	if ( type > AccessSpec_Public ) | ||||
| 		return "Invalid"; | ||||
|  | ||||
| 	return lookup[ (u32)type ]; | ||||
| } | ||||
|  | ||||
|  | ||||
| enum CodeFlag : u32 | ||||
| enum CodeFlag enum_underlying(u32) | ||||
| { | ||||
| 	None          = 0, | ||||
| 	FunctionType  = bit(0), | ||||
| 	ParamPack     = bit(1), | ||||
| 	Module_Export = bit(2), | ||||
| 	Module_Import = bit(3), | ||||
| 	CodeFlag_None          = 0, | ||||
| 	CodeFlag_FunctionType  = bit(0), | ||||
| 	CodeFlag_ParamPack     = bit(1), | ||||
| 	CodeFlag_Module_Export = bit(2), | ||||
| 	CodeFlag_Module_Import = bit(3), | ||||
|  | ||||
| 	CodeFlag_SizeDef = GEN_U32_MAX, | ||||
| }; | ||||
| static_assert( size_of(CodeFlag) == size_of(u32)); | ||||
|  | ||||
| // Used to indicate if enum definitoin is an enum class or regular enum. | ||||
| enum class EnumT : u8 | ||||
| enum EnumDecl enum_underlying(u8) | ||||
| { | ||||
| 	Regular, | ||||
| 	Class | ||||
| 	EnumDecl_Regular, | ||||
| 	EnumDecl_Class, | ||||
|  | ||||
| 	EnumT_SizeDef = GEN_U8_MAX, | ||||
| }; | ||||
| typedef u8 EnumT; | ||||
|  | ||||
| constexpr EnumT EnumClass   = EnumT::Class; | ||||
| constexpr EnumT EnumRegular = EnumT::Regular; | ||||
|  | ||||
| enum class ModuleFlag : u32 | ||||
| enum ModuleFlag enum_underlying(u32) | ||||
| { | ||||
| 	None    = 0, | ||||
| 	Export  = bit(0), | ||||
| 	Import  = bit(1), | ||||
| 	ModuleFlag_None    = 0, | ||||
| 	ModuleFlag_Export  = bit(0), | ||||
| 	ModuleFlag_Import  = bit(1), | ||||
|  | ||||
| 	Num_ModuleFlags, | ||||
| 	Invalid, | ||||
| 	ModuleFlag_Invalid, | ||||
|  | ||||
| 	ModuleFlag_SizeDef = GEN_U32_MAX, | ||||
| }; | ||||
| static_assert( size_of(ModuleFlag) == size_of(u32)); | ||||
|  | ||||
| inline | ||||
| StrC to_str( ModuleFlag flag ) | ||||
| @@ -81,7 +89,7 @@ StrC to_str( ModuleFlag flag ) | ||||
| 		{ sizeof("import"), "import" }, | ||||
| 	}; | ||||
|  | ||||
| 	if ( flag > ModuleFlag::Import ) | ||||
| 	if ( flag > ModuleFlag_Import ) | ||||
| 		return { sizeof("invalid"), "invalid" }; | ||||
|  | ||||
| 	return lookup[ (u32)flag ]; | ||||
| @@ -93,15 +101,13 @@ ModuleFlag operator|( ModuleFlag A, ModuleFlag B) | ||||
| 	return (ModuleFlag)( (u32)A | (u32)B ); | ||||
| } | ||||
|  | ||||
| enum class EPreprocessCond : u32 | ||||
| enum EPreprocessCond enum_underlying(u32) | ||||
| { | ||||
| 	If, | ||||
| 	IfDef, | ||||
| 	IfNotDef, | ||||
| 	ElIf | ||||
| }; | ||||
| 	PreprocessCond_If, | ||||
| 	PreprocessCond_IfDef, | ||||
| 	PreprocessCond_IfNotDef, | ||||
| 	PreprocessCond_ElIf, | ||||
|  | ||||
| constexpr EPreprocessCond PreprocessCond_If       = EPreprocessCond::If; | ||||
| constexpr EPreprocessCond PreprocessCond_IfDef    = EPreprocessCond::IfDef; | ||||
| constexpr EPreprocessCond PreprocessCond_IfNotDef = EPreprocessCond::IfNotDef; | ||||
| constexpr EPreprocessCond PreprocessCond_ElIf     = EPreprocessCond::ElIf; | ||||
| 	EPreprocessCond_SizeDef = GEN_U32_MAX, | ||||
| }; | ||||
| static_assert( size_of(EPreprocessCond) == size_of(u32)); | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| #ifdef GEN_INTELLISENSE_DIRECTIVES | ||||
| #	pragma once | ||||
| #	include "platform.hpp" | ||||
| #	include "macros.hpp" | ||||
| #endif | ||||
|  | ||||
| @@ -122,13 +123,21 @@ typedef s8  b8; | ||||
| typedef s16 b16; | ||||
| typedef s32 b32; | ||||
|  | ||||
| using mem_ptr       = void*; | ||||
| using mem_ptr_const = void const*; | ||||
| typedef void*       mem_ptr; | ||||
| typedef void const* mem_ptr_const ; | ||||
|  | ||||
| #if ! GEN_COMPILER_C | ||||
| template<typename Type> uptr to_uptr( Type* ptr ) { return (uptr)ptr; } | ||||
| template<typename Type> sptr to_sptr( Type* ptr ) { return (sptr)ptr; } | ||||
|  | ||||
| template<typename Type> mem_ptr       to_mem_ptr      ( Type ptr ) { return (mem_ptr)      ptr; } | ||||
| template<typename Type> mem_ptr_const to_mem_ptr_const( Type ptr ) { return (mem_ptr_const)ptr; } | ||||
| #else | ||||
| #define to_utpr( ptr ) ((uptr)(ptr)) | ||||
| #define to_stpr( ptr ) ((sptr)(ptr)) | ||||
|  | ||||
| #define to_mem_ptr( ptr)       ((mem_ptr)ptr) | ||||
| #define to_mem_ptr_const( ptr) ((mem_ptr)ptr) | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Basic Types | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -24,7 +24,7 @@ | ||||
| 	{                                                                                        \ | ||||
| 		if ( ! ( cond ) )                                                                    \ | ||||
| 		{                                                                                    \ | ||||
| 			assert_handler( #cond, __FILE__, scast( s64, __LINE__ ), msg, ##__VA_ARGS__ ); \ | ||||
| 			assert_handler( #cond, __FILE__, scast( s64, __LINE__ ), msg, ##__VA_ARGS__ );   \ | ||||
| 			GEN_DEBUG_TRAP();                                                                \ | ||||
| 		}                                                                                    \ | ||||
| 	} while ( 0 ) | ||||
|   | ||||
| @@ -505,7 +505,7 @@ b8 file_stream_new( FileInfo* file, AllocatorInfo allocator ) | ||||
| 	d->allocator = allocator; | ||||
| 	d->flags     = EFileStream_CLONE_WRITABLE; | ||||
| 	d->cap       = 0; | ||||
| 	d->buf       = Array<u8>::init( allocator ); | ||||
| 	d->buf       = array_init<u8>( allocator ); | ||||
|  | ||||
| 	if ( ! d->buf ) | ||||
| 		return false; | ||||
| @@ -531,7 +531,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize | ||||
| 	d->flags     = flags; | ||||
| 	if ( d->flags & EFileStream_CLONE_WRITABLE ) | ||||
| 	{ | ||||
| 		Array<u8> arr = Array<u8>::init_reserve( allocator, size ); | ||||
| 		Array<u8> arr = array_init_reserve<u8>( allocator, size ); | ||||
| 		d->buf = arr; | ||||
|  | ||||
| 		if ( ! d->buf ) | ||||
| @@ -540,7 +540,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize | ||||
| 		mem_copy( d->buf, buffer, size ); | ||||
| 		d->cap = size; | ||||
|  | ||||
| 		arr.get_header()->Num = size; | ||||
| 		get_header(arr)->Num = size; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -610,9 +610,9 @@ GEN_FILE_WRITE_AT_PROC( _memory_file_write ) | ||||
| 	{ | ||||
| 		Array<u8> arr = { d->buf }; | ||||
|  | ||||
| 		if ( arr.get_header()->Capacity < usize(new_cap) ) | ||||
| 		if ( get_header(arr)->Capacity < usize(new_cap) ) | ||||
| 		{ | ||||
| 			if ( ! arr.grow( ( s64 )( new_cap ) ) ) | ||||
| 			if ( ! grow( arr, ( s64 )( new_cap ) ) ) | ||||
| 				return false; | ||||
| 			d->buf = arr; | ||||
| 		} | ||||
| @@ -626,7 +626,7 @@ GEN_FILE_WRITE_AT_PROC( _memory_file_write ) | ||||
|  | ||||
| 		mem_copy( d->buf + offset + rwlen, pointer_add_const( buffer, rwlen ), extralen ); | ||||
| 		d->cap = new_cap; | ||||
| 		arr.get_header()->Capacity = new_cap; | ||||
| 		get_header(arr)->Capacity = new_cap; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -647,7 +647,7 @@ GEN_FILE_CLOSE_PROC( _memory_file_close ) | ||||
| 	if ( d->flags & EFileStream_CLONE_WRITABLE ) | ||||
| 	{ | ||||
| 		Array<u8> arr = { d->buf }; | ||||
| 		arr.free(); | ||||
| 		free(arr); | ||||
| 	} | ||||
|  | ||||
| 	free( allocator, d ); | ||||
|   | ||||
| @@ -23,17 +23,32 @@ | ||||
| #define bitfield_is_equal( Type, Field, Mask ) ( (Type(Mask) & Type(Field)) == Type(Mask) ) | ||||
| #endif | ||||
|  | ||||
| #ifndef ccast | ||||
| #define ccast( type, value ) ( const_cast< type >( (value) ) ) | ||||
| #endif | ||||
| #ifndef pcast | ||||
| #define pcast( type, value ) ( * reinterpret_cast< type* >( & ( value ) ) ) | ||||
| #endif | ||||
| #ifndef rcast | ||||
| #define rcast( type, value ) reinterpret_cast< type >( value ) | ||||
| #endif | ||||
| #ifndef scast | ||||
| #define scast( type, value ) static_cast< type >( value ) | ||||
| #if ! GEN_C_COMPILER | ||||
| #	ifndef ccast | ||||
| #	define ccast( type, value ) ( const_cast< type >( (value) ) ) | ||||
| #	endif | ||||
| #	ifndef pcast | ||||
| #	define pcast( type, value ) ( * reinterpret_cast< type* >( & ( value ) ) ) | ||||
| #	endif | ||||
| #	ifndef rcast | ||||
| #	define rcast( type, value ) reinterpret_cast< type >( value ) | ||||
| #	endif | ||||
| #	ifndef scast | ||||
| #	define scast( type, value ) static_cast< type >( value ) | ||||
| #	endif | ||||
| #else | ||||
| #	ifndef ccast | ||||
| #	define ccast( type, value ) ( (type)(value) ) | ||||
| #	endif | ||||
| #	ifndef pcast | ||||
| #	define pcast( type, value ) ( (type)(value) ) | ||||
| #	endif | ||||
| #	ifndef rcast | ||||
| #	define rcast( type, value ) ( (type)(value) ) | ||||
| #	endif | ||||
| #	ifndef scast | ||||
| #	define scast( type, value ) ( (type)(value) ) | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| #ifndef stringize | ||||
| @@ -123,20 +138,20 @@ | ||||
| #define min( a, b ) ( (a < b) ? (a) : (b) ) | ||||
| #endif | ||||
|  | ||||
| #if defined( _MSC_VER ) || defined( GEN_COMPILER_TINYC ) | ||||
| #if GEN_COMPILER_MSVC || GEN_COMPILER_TINYC | ||||
| #	define offset_of( Type, element ) ( ( GEN_NS( ssize ) ) & ( ( ( Type* )0 )->element ) ) | ||||
| #else | ||||
| #	define offset_of( Type, element ) __builtin_offsetof( Type, element ) | ||||
| #endif | ||||
|  | ||||
| #ifndef        forceinline | ||||
| #	ifdef GEN_COMPILER_MSVC | ||||
| #	if GEN_COMPILER_MSVC | ||||
| #		define forceinline __forceinline | ||||
| #		define neverinline __declspec( noinline ) | ||||
| #	elif defined(GEN_COMPILER_GCC) | ||||
| #	elif GEN_COMPILER_GCC | ||||
| #		define forceinline inline __attribute__((__always_inline__)) | ||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | ||||
| #	elif defined(GEN_COMPILER_CLANG) | ||||
| #	elif GEN_COMPILER_CLANG | ||||
| #	if __has_attribute(__always_inline__) | ||||
| #		define forceinline inline __attribute__((__always_inline__)) | ||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | ||||
| @@ -151,11 +166,11 @@ | ||||
| #endif | ||||
|  | ||||
| #ifndef        neverinline | ||||
| #	ifdef GEN_COMPILER_MSVC | ||||
| #	if GEN_COMPILER_MSVC | ||||
| #		define neverinline __declspec( noinline ) | ||||
| #	elif defined(GEN_COMPILER_GCC) | ||||
| #	elif GEN_COMPILER_GCC | ||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | ||||
| #	elif defined(GEN_COMPILER_CLANG) | ||||
| #	elif GEN_COMPILER_CLANG | ||||
| #	if __has_attribute(__always_inline__) | ||||
| #		define neverinline __attribute__( ( __noinline__ ) ) | ||||
| #	else | ||||
| @@ -166,4 +181,38 @@ | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| #if !defined(GEN_SUPPORT_CPP_MEMBER_FEATURES) && (!GEN_COMPILER_C || __STDC_VERSION__ < 202311L) | ||||
| #	define GEN_SUPPORT_CPP_MEMBER_FEATURES 0 | ||||
| #endif | ||||
|  | ||||
| #if !defined(typeof) && (!GEN_COMPILER_C || __STDC_VERSION__ < 202311L) | ||||
| #	if ! GEN_COMPILER_C | ||||
| #		define typeof decltype | ||||
| #	elif defined(_MSC_VER) | ||||
| #		define typeof(x) __typeof(x) | ||||
| #	elif defined(__GNUC__) || defined(__clang__) | ||||
| #		define typeof(x) __typeof__(x) | ||||
| #	else | ||||
| #		error "Compiler not supported" | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| // This is intended to only really be used internally or with the C-library variant | ||||
| // C++ users can just use the for-range directly. | ||||
| #if GEN_COMPILER_C | ||||
| #	define foreach(Type, entry_id, iterable) for ( Type entry_id = begin(iterable); entry_id != end(iterable); entry_id = next(iterable, entry_id) ) | ||||
| #else | ||||
| #	define foreach(Type, entry_id, iterable) for ( Type entry_id : iterable ) | ||||
| #endif | ||||
|  | ||||
| #if GEN_COMPILER_C | ||||
| #	if __STDC_VERSION__ >= 202311L | ||||
| #		define enum_underlying(type) : type | ||||
| #	else | ||||
| #		define enum_underlying(type) | ||||
| #   endif | ||||
| #else | ||||
| #	define enum_underlying(type) : type | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Macros | ||||
|   | ||||
| @@ -334,7 +334,7 @@ ssize virtual_memory_page_size( ssize* alignment_out ) | ||||
|  | ||||
| #pragma endregion VirtualMemory | ||||
|  | ||||
| void* Arena::allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | ||||
| void* arena_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | ||||
| { | ||||
| 	Arena* arena = rcast(Arena*, allocator_data); | ||||
| 	void*      ptr   = NULL; | ||||
| @@ -384,7 +384,7 @@ void* Arena::allocator_proc( void* allocator_data, AllocType type, ssize size, s | ||||
| 	return ptr; | ||||
| } | ||||
|  | ||||
| void* Pool::allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | ||||
| void* pool_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) | ||||
| { | ||||
| 	Pool* pool = rcast( Pool*, allocator_data); | ||||
| 	void* ptr  = NULL; | ||||
| @@ -457,7 +457,7 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, ssize size, ss | ||||
| 	return ptr; | ||||
| } | ||||
|  | ||||
| Pool Pool::init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align ) | ||||
| Pool pool_init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align ) | ||||
| { | ||||
| 	Pool pool = {}; | ||||
|  | ||||
| @@ -495,16 +495,16 @@ Pool Pool::init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size | ||||
| 	return pool; | ||||
| } | ||||
|  | ||||
| void Pool::clear() | ||||
| void clear(Pool& pool) | ||||
| { | ||||
| 	ssize    actual_block_size, block_index; | ||||
| 	ssize actual_block_size, block_index; | ||||
| 	void* curr; | ||||
| 	uptr* end; | ||||
|  | ||||
| 	actual_block_size = BlockSize + BlockAlign; | ||||
| 	actual_block_size = pool.BlockSize + pool.BlockAlign; | ||||
|  | ||||
| 	curr = PhysicalStart; | ||||
| 	for ( block_index = 0; block_index < NumBlocks - 1; block_index++ ) | ||||
| 	curr = pool.PhysicalStart; | ||||
| 	for ( block_index = 0; block_index < pool.NumBlocks - 1; block_index++ ) | ||||
| 	{ | ||||
| 		uptr* next = ( uptr* ) curr; | ||||
| 		*next      = ( uptr  ) curr + actual_block_size; | ||||
| @@ -514,7 +514,7 @@ void Pool::clear() | ||||
| 	end  =  ( uptr* ) curr; | ||||
| 	*end =  ( uptr )  NULL; | ||||
|  | ||||
| 	FreeList = PhysicalStart; | ||||
| 	pool.FreeList = pool.PhysicalStart; | ||||
| } | ||||
|  | ||||
| #pragma endregion Memory | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|  | ||||
| #pragma region Memory | ||||
|  | ||||
| #define kilobytes( x ) ( ( x ) * ( s64 )( 1024 ) ) | ||||
| #define kilobytes( x ) (          ( x ) * ( s64 )( 1024 ) ) | ||||
| #define megabytes( x ) ( kilobytes( x ) * ( s64 )( 1024 ) ) | ||||
| #define gigabytes( x ) ( megabytes( x ) * ( s64 )( 1024 ) ) | ||||
| #define terabytes( x ) ( gigabytes( x ) * ( s64 )( 1024 ) ) | ||||
| @@ -70,10 +70,7 @@ enum AllocType : u8 | ||||
| 	EAllocation_RESIZE, | ||||
| }; | ||||
|  | ||||
| using AllocatorProc = void* ( void* allocator_data, AllocType type | ||||
| 	, ssize size, ssize alignment | ||||
| 	, void* old_memory, ssize old_size | ||||
| 	, u64 flags ); | ||||
| typedef void*(AllocatorProc)( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ); | ||||
|  | ||||
| struct AllocatorInfo | ||||
| { | ||||
| @@ -170,121 +167,177 @@ b32 gen_vm_purge( VirtualMemory vm ); | ||||
| //! Retrieve VM's page size and alignment. | ||||
| ssize gen_virtual_memory_page_size( ssize* alignment_out ); | ||||
|  | ||||
| struct Arena | ||||
| { | ||||
| 	static | ||||
| 	void* allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ); | ||||
| #pragma region Arena | ||||
| struct Arena; | ||||
|  | ||||
| 	static | ||||
| 	Arena init_from_memory( void* start, ssize size ) | ||||
| 	{ | ||||
| 		return | ||||
| 		{ | ||||
| 			{ nullptr, nullptr }, | ||||
| 			start, | ||||
| 			size, | ||||
| 			0, | ||||
| 			0 | ||||
| 		}; | ||||
| 	} | ||||
| AllocatorInfo allocator_info( Arena& arena ); | ||||
|  | ||||
| 	static | ||||
| 	Arena init_from_allocator( AllocatorInfo backing, ssize size ) | ||||
| 	{ | ||||
| 		Arena result = | ||||
| 		{ | ||||
| 		backing, | ||||
| 		alloc( backing, size), | ||||
| 		size, | ||||
| 		0, | ||||
| 		0 | ||||
| 		}; | ||||
| 		return result; | ||||
| 	} | ||||
| // Remove static keyword and rename allocator_proc | ||||
| void* arena_allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags); | ||||
|  | ||||
| 	static | ||||
| 	Arena init_sub( Arena& parent, ssize size ) | ||||
| 	{ | ||||
| 		return init_from_allocator( parent.Backing, size ); | ||||
| 	} | ||||
|  | ||||
| 	ssize alignment_of( ssize alignment ) | ||||
| 	{ | ||||
| 		ssize alignment_offset, result_pointer, mask; | ||||
| 		GEN_ASSERT( is_power_of_two( alignment ) ); | ||||
|  | ||||
| 		alignment_offset = 0; | ||||
| 		result_pointer   = (ssize) PhysicalStart + TotalUsed; | ||||
| 		mask             = alignment - 1; | ||||
|  | ||||
| 		if ( result_pointer & mask ) | ||||
| 			alignment_offset = alignment - ( result_pointer & mask ); | ||||
|  | ||||
| 		return alignment_offset; | ||||
| 	} | ||||
| // Add these declarations after the Arena struct | ||||
| Arena arena_init_from_allocator(AllocatorInfo backing, ssize size); | ||||
| Arena arena_init_from_memory( void* start, ssize size ); | ||||
| Arena init_sub(Arena& parent, ssize size); | ||||
| ssize alignment_of(Arena& arena, ssize alignment); | ||||
|  | ||||
| // This id is defined by Unreal for asserts | ||||
| #pragma push_macro("check") | ||||
| #undef check | ||||
| 	void check() | ||||
| 	{ | ||||
| 		GEN_ASSERT( TempCount == 0 ); | ||||
| 	} | ||||
| void   check(Arena& arena); | ||||
| #pragma pop_macro("check") | ||||
|  | ||||
| 	void free() | ||||
| 	{ | ||||
| 		if ( Backing.Proc ) | ||||
| 		{ | ||||
| 			gen::free( Backing, PhysicalStart ); | ||||
| 			PhysicalStart = nullptr; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	ssize size_remaining( ssize alignment ) | ||||
| 	{ | ||||
| 		ssize result = TotalSize - ( TotalUsed + alignment_of( alignment ) ); | ||||
| 		return result; | ||||
| 	} | ||||
| void  free(Arena& arena); | ||||
| ssize size_remaining(Arena& arena, ssize alignment); | ||||
|  | ||||
| struct Arena | ||||
| { | ||||
| 	AllocatorInfo Backing; | ||||
| 	void*         PhysicalStart; | ||||
| 	ssize            TotalSize; | ||||
| 	ssize            TotalUsed; | ||||
| 	ssize            TempCount; | ||||
| 	ssize         TotalSize; | ||||
| 	ssize         TotalUsed; | ||||
| 	ssize         TempCount; | ||||
|  | ||||
| 	operator AllocatorInfo() | ||||
| 	{ | ||||
| 		return { allocator_proc, this }; | ||||
| 	} | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| #pragma region Member Mapping | ||||
| 	forceinline operator AllocatorInfo() { return GEN_NS allocator_info(* this); } | ||||
|  | ||||
| 	forceinline static void* allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) { return GEN_NS arena_allocator_proc( allocator_data, type, size, alignment, old_memory, old_size, flags ); } | ||||
| 	forceinline static Arena init_from_memory( void* start, ssize size )                                                                                      { return GEN_NS arena_init_from_memory( start, size ); } | ||||
| 	forceinline static Arena init_from_allocator( AllocatorInfo backing, ssize size )                                                                         { return GEN_NS arena_init_from_allocator( backing, size ); } | ||||
| 	forceinline static Arena init_sub( Arena& parent, ssize size )                                                                                            { return GEN_NS arena_init_from_allocator( parent.Backing, size ); } | ||||
| 	forceinline        ssize alignment_of( ssize alignment )                                                                                                  { return GEN_NS alignment_of(* this, alignment); } | ||||
| 	forceinline        void  free()                                                                                                                           { return GEN_NS free(* this);  } | ||||
| 	forceinline        ssize size_remaining( ssize alignment )                                                                                                { return GEN_NS size_remaining(* this, alignment); } | ||||
|  | ||||
| // This id is defined by Unreal for asserts | ||||
| #pragma push_macro("check") | ||||
| #undef check | ||||
| 	forceinline void check() { GEN_NS check(* this); } | ||||
| #pragma pop_macro("check") | ||||
|  | ||||
| #pragma endregion Member Mapping | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| inline | ||||
| AllocatorInfo allocator_info( Arena& arena ) { | ||||
| 	return { arena_allocator_proc, &arena }; | ||||
| } | ||||
|  | ||||
| inline | ||||
| Arena arena_init_from_memory( void* start, ssize size ) | ||||
| { | ||||
| 	Arena arena = { | ||||
| 		{ nullptr, nullptr }, | ||||
| 		start, | ||||
| 		size, | ||||
| 		0, | ||||
| 		0 | ||||
| 	}; | ||||
| 	return arena; | ||||
| } | ||||
|  | ||||
| inline | ||||
| Arena arena_init_from_allocator(AllocatorInfo backing, ssize size) { | ||||
| 	Arena result = { | ||||
| 		backing, | ||||
| 		alloc(backing, size), | ||||
| 		size, | ||||
| 		0, | ||||
| 		0 | ||||
| 	}; | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| Arena init_sub(Arena& parent, ssize size) { | ||||
| 	return arena_init_from_allocator(parent.Backing, size); | ||||
| } | ||||
|  | ||||
| inline | ||||
| ssize alignment_of(Arena& arena, ssize alignment) | ||||
| { | ||||
| 	ssize alignment_offset, result_pointer, mask; | ||||
| 	GEN_ASSERT(is_power_of_two(alignment)); | ||||
|  | ||||
| 	alignment_offset = 0; | ||||
| 	result_pointer  = (ssize)arena.PhysicalStart + arena.TotalUsed; | ||||
| 	mask            = alignment - 1; | ||||
|  | ||||
| 	if (result_pointer & mask) | ||||
| 	alignment_offset = alignment - (result_pointer & mask); | ||||
|  | ||||
| 	return alignment_offset; | ||||
| } | ||||
|  | ||||
| #pragma push_macro("check") | ||||
| #undef check | ||||
| inline | ||||
| void check(Arena& arena) | ||||
| { | ||||
|     GEN_ASSERT(arena.TempCount == 0); | ||||
| } | ||||
| #pragma pop_macro("check") | ||||
|  | ||||
| inline | ||||
| void free(Arena& arena) | ||||
| { | ||||
| 	if (arena.Backing.Proc) | ||||
| 	{ | ||||
| 		GEN_NS free(arena.Backing, arena.PhysicalStart); | ||||
| 		arena.PhysicalStart = nullptr; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| inline | ||||
| ssize size_remaining(Arena& arena, ssize alignment) | ||||
| { | ||||
| 	ssize result = arena.TotalSize - (arena.TotalUsed + alignment_of(arena, alignment)); | ||||
| 	return result; | ||||
| } | ||||
| #pragma endregion Arena | ||||
|  | ||||
| #pragma region FixedArena | ||||
| template<s32 Size> | ||||
| struct FixedArena; | ||||
|  | ||||
| template<s32 Size> AllocatorInfo    allocator_info( FixedArena<Size>& fixed_arena ); | ||||
| template<s32 Size> FixedArena<Size> fixed_arena_init(); | ||||
| template<s32 Size> ssize            size_remaining(FixedArena<Size>& fixed_arena, ssize alignment); | ||||
|  | ||||
| // Just a wrapper around using an arena with memory associated with its scope instead of from an allocator. | ||||
| // Used for static segment or stack allocations. | ||||
| template< s32 Size > | ||||
| struct FixedArena | ||||
| { | ||||
| 	static | ||||
| 	FixedArena init() | ||||
| 	{ | ||||
| 		FixedArena result = { Arena::init_from_memory( result.memory, Size ), {0} }; | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	ssize size_remaining( ssize alignment ) | ||||
| 	{ | ||||
| 		return arena.size_remaining( alignment ); | ||||
| 	} | ||||
|  | ||||
| 	operator AllocatorInfo() | ||||
| 	{ | ||||
| 		return { Arena::allocator_proc, &arena }; | ||||
| 	} | ||||
|  | ||||
| 	char  memory[Size]; | ||||
| 	Arena arena; | ||||
| 	char  memory[ Size ]; | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| #pragma region Member Mapping | ||||
| 	forceinline operator AllocatorInfo() { return GEN_NS allocator_info(* this); } | ||||
|  | ||||
| 	forceinline static FixedArena init()                          { FixedArena result; GEN_NS fixed_arena_init<Size>(result); return result; } | ||||
| 	forceinline ssize             size_remaining(ssize alignment) { GEN_NS size_remaining(*this, alignment); } | ||||
| #pragma endregion Member Mapping | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| template<s32 Size> inline | ||||
| AllocatorInfo allocator_info( FixedArena<Size>& fixed_arena ) { return { arena_allocator_proc, & fixed_arena.arena }; } | ||||
|  | ||||
| template<s32 Size> inline | ||||
| void fixed_arena_init(FixedArena<Size>& result) { | ||||
|     zero_size(& result.memory[0], Size); | ||||
|     result.arena = arena_init_from_memory(& result.memory[0], Size); | ||||
| } | ||||
|  | ||||
| template<s32 Size> inline | ||||
| ssize size_remaining(FixedArena<Size>& fixed_arena, ssize alignment) { | ||||
|     return size_remaining(fixed_arena.arena, alignment); | ||||
| } | ||||
|  | ||||
| using Arena_1KB   = FixedArena< kilobytes( 1 ) >; | ||||
| using Arena_4KB   = FixedArena< kilobytes( 4 ) >; | ||||
| using Arena_8KB   = FixedArena< kilobytes( 8 ) >; | ||||
| @@ -297,31 +350,20 @@ using Arena_512KB = FixedArena< kilobytes( 512 ) >; | ||||
| using Arena_1MB   = FixedArena< megabytes( 1 ) >; | ||||
| using Arena_2MB   = FixedArena< megabytes( 2 ) >; | ||||
| using Arena_4MB   = FixedArena< megabytes( 4 ) >; | ||||
| #pragma endregion FixedArena | ||||
|  | ||||
| #pragma region Pool | ||||
| struct Pool; | ||||
|  | ||||
| AllocatorInfo allocator_info(Pool& pool); | ||||
| void*         pool_allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags); | ||||
| Pool          pool_init(AllocatorInfo backing, ssize num_blocks, ssize block_size); | ||||
| Pool          pool_init_align(AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align); | ||||
| void          clear(Pool& pool); | ||||
| void          free(Pool& pool); | ||||
|  | ||||
| struct Pool | ||||
| { | ||||
| 	static | ||||
| 	void* allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ); | ||||
|  | ||||
| 	static | ||||
| 	Pool init( AllocatorInfo backing, ssize num_blocks, ssize block_size ) | ||||
| 	{ | ||||
| 		return init_align( backing, num_blocks, block_size, GEN_DEFAULT_MEMORY_ALIGNMENT ); | ||||
| 	} | ||||
|  | ||||
| 	static | ||||
| 	Pool init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align ); | ||||
|  | ||||
| 	void clear(); | ||||
|  | ||||
| 	void free() | ||||
| 	{ | ||||
| 		if ( Backing.Proc ) | ||||
| 		{ | ||||
| 			gen::free( Backing, PhysicalStart ); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	AllocatorInfo Backing; | ||||
| 	void*         PhysicalStart; | ||||
| 	void*         FreeList; | ||||
| @@ -330,12 +372,36 @@ struct Pool | ||||
| 	ssize         TotalSize; | ||||
| 	ssize         NumBlocks; | ||||
|  | ||||
| 	operator AllocatorInfo() | ||||
| 	{ | ||||
| 		return { allocator_proc, this }; | ||||
| 	} | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| #pragma region Member Mapping | ||||
|     forceinline operator AllocatorInfo() { return GEN_NS allocator_info(* this); } | ||||
|  | ||||
|     forceinline static void* allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags) { return GEN_NS pool_allocator_proc(allocator_data, type, size, alignment, old_memory, old_size, flags); } | ||||
|     forceinline static Pool  init(AllocatorInfo backing, ssize num_blocks, ssize block_size)                                                                { return GEN_NS pool_init(backing, num_blocks, block_size); } | ||||
|     forceinline static Pool  init_align(AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align)                                       { return GEN_NS pool_init_align(backing, num_blocks, block_size, block_align); } | ||||
|     forceinline        void  clear() { GEN_NS clear(* this); } | ||||
|     forceinline        void  free()  { GEN_NS free(* this); } | ||||
| #pragma endregion | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| inline | ||||
| AllocatorInfo allocator_info(Pool& pool) { | ||||
|    return { pool_allocator_proc, &pool }; | ||||
| } | ||||
|  | ||||
| inline | ||||
| Pool pool_init(AllocatorInfo backing, ssize num_blocks, ssize block_size) { | ||||
|    return pool_init_align(backing, num_blocks, block_size, GEN_DEFAULT_MEMORY_ALIGNMENT); | ||||
| } | ||||
|  | ||||
| inline | ||||
| void free(Pool& pool) { | ||||
|    if(pool.Backing.Proc) { | ||||
|        GEN_NS free(pool.Backing, pool.PhysicalStart); | ||||
|    } | ||||
| } | ||||
| #pragma endregion Pool | ||||
|  | ||||
| inline | ||||
| b32 is_power_of_two( ssize x ) { | ||||
|   | ||||
| @@ -23,7 +23,7 @@ u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32 | ||||
| 	node->type   = type; | ||||
| 	node->name   = name; | ||||
| 	node->parent = parent; | ||||
| 	node->nodes  = Array<ADT_Node>::init( backing ); | ||||
| 	node->nodes  = array_init<ADT_Node>( backing ); | ||||
|  | ||||
| 	if ( ! node->nodes ) | ||||
| 		return EADT_ERROR_OUT_OF_MEMORY; | ||||
| @@ -36,12 +36,12 @@ u8 adt_destroy_branch( ADT_Node* node ) | ||||
| 	GEN_ASSERT_NOT_NULL( node ); | ||||
| 	if ( ( node->type == EADT_TYPE_OBJECT || node->type == EADT_TYPE_ARRAY ) && node->nodes ) | ||||
| 	{ | ||||
| 		for ( ssize i = 0; i < scast(ssize, node->nodes.num()); ++i ) | ||||
| 		for ( ssize i = 0; i < scast(ssize, num(node->nodes)); ++i ) | ||||
| 		{ | ||||
| 			adt_destroy_branch( node->nodes + i ); | ||||
| 		} | ||||
|  | ||||
| 		node->nodes.free(); | ||||
| 		free(node->nodes); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| @@ -66,7 +66,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ) | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ ) | ||||
| 	for ( ssize i = 0; i < scast(ssize, num(node->nodes)); i++ ) | ||||
| 	{ | ||||
| 		if ( ! str_compare( node->nodes[ i ].name, name ) ) | ||||
| 		{ | ||||
| @@ -76,7 +76,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ) | ||||
|  | ||||
| 	if ( deep_search ) | ||||
| 	{ | ||||
| 		for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ ) | ||||
| 		for ( ssize i = 0; i < scast(ssize, num(node->nodes)); i++ ) | ||||
| 		{ | ||||
| 			ADT_Node* res = adt_find( node->nodes + i, name, deep_search ); | ||||
|  | ||||
| @@ -132,7 +132,7 @@ internal ADT_Node* _adt_get_value( ADT_Node* node, char const* value ) | ||||
|  | ||||
| internal ADT_Node* _adt_get_field( ADT_Node* node, char* name, char* value ) | ||||
| { | ||||
| 	for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ ) | ||||
| 	for ( ssize i = 0; i < scast(ssize, num(node->nodes)); i++ ) | ||||
| 	{ | ||||
| 		if ( ! str_compare( node->nodes[ i ].name, name ) ) | ||||
| 		{ | ||||
| @@ -207,7 +207,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) | ||||
| 			/* run a value comparison against any child that is an object node */ | ||||
| 			else if ( node->type == EADT_TYPE_ARRAY ) | ||||
| 			{ | ||||
| 				for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ ) | ||||
| 				for ( ssize i = 0; i < scast(ssize, num(node->nodes)); i++ ) | ||||
| 				{ | ||||
| 					ADT_Node* child = &node->nodes[ i ]; | ||||
| 					if ( child->type != EADT_TYPE_OBJECT ) | ||||
| @@ -225,7 +225,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) | ||||
| 		/* [value] */ | ||||
| 		else | ||||
| 		{ | ||||
| 			for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ ) | ||||
| 			for ( ssize i = 0; i < scast(ssize, num(node->nodes)); i++ ) | ||||
| 			{ | ||||
| 				ADT_Node* child = &node->nodes[ i ]; | ||||
| 				if ( _adt_get_value( child, l_b2 ) ) | ||||
| @@ -257,7 +257,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) | ||||
| 	else | ||||
| 	{ | ||||
| 		ssize idx = ( ssize )str_to_i64( buf, NULL, 10 ); | ||||
| 		if ( idx >= 0 && idx < scast(ssize, node->nodes.num()) ) | ||||
| 		if ( idx >= 0 && idx < scast(ssize, num(node->nodes)) ) | ||||
| 		{ | ||||
| 			found_node = &node->nodes[ idx ]; | ||||
|  | ||||
| @@ -282,12 +282,12 @@ ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index ) | ||||
| 	if ( ! parent->nodes ) | ||||
| 		return NULL; | ||||
|  | ||||
| 	if ( index < 0 || index > scast(ssize, parent->nodes.num()) ) | ||||
| 	if ( index < 0 || index > scast(ssize, num(parent->nodes)) ) | ||||
| 		return NULL; | ||||
|  | ||||
| 	ADT_Node o = { 0 }; | ||||
| 	o.parent   = parent; | ||||
| 	if ( ! parent->nodes.append_at( o, index ) ) | ||||
| 	if ( ! append_at( parent->nodes, o, index ) ) | ||||
| 		return NULL; | ||||
|  | ||||
| 	return parent->nodes + index; | ||||
| @@ -303,7 +303,7 @@ ADT_Node* adt_alloc( ADT_Node* parent ) | ||||
| 	if ( ! parent->nodes ) | ||||
| 		return NULL; | ||||
|  | ||||
| 	return adt_alloc_at( parent, parent->nodes.num() ); | ||||
| 	return adt_alloc_at( parent, num(parent->nodes) ); | ||||
| } | ||||
|  | ||||
| b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing ) | ||||
| @@ -357,7 +357,7 @@ ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent ) | ||||
| 	GEN_ASSERT_NOT_NULL( node ); | ||||
| 	GEN_ASSERT_NOT_NULL( new_parent ); | ||||
| 	GEN_ASSERT( new_parent->type == EADT_TYPE_ARRAY || new_parent->type == EADT_TYPE_OBJECT ); | ||||
| 	return adt_move_node_at( node, new_parent, new_parent->nodes.num() ); | ||||
| 	return adt_move_node_at( node, new_parent, num(new_parent->nodes) ); | ||||
| } | ||||
|  | ||||
| void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ) | ||||
| @@ -381,7 +381,7 @@ void adt_remove_node( ADT_Node* node ) | ||||
| 	GEN_ASSERT_NOT_NULL( node->parent ); | ||||
| 	ADT_Node* parent = node->parent; | ||||
| 	ssize        index  = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); | ||||
| 	parent->nodes.remove_at( index ); | ||||
| 	remove_at( parent->nodes, index ); | ||||
| } | ||||
|  | ||||
| ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ) | ||||
| @@ -389,7 +389,7 @@ ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ) | ||||
| 	ADT_Node* o = adt_alloc( parent ); | ||||
| 	if ( ! o ) | ||||
| 		return NULL; | ||||
| 	if ( adt_set_obj( o, name, parent->nodes.get_header()->Allocator ) ) | ||||
| 	if ( adt_set_obj( o, name, get_header(parent->nodes)->Allocator ) ) | ||||
| 	{ | ||||
| 		adt_remove_node( o ); | ||||
| 		return NULL; | ||||
| @@ -402,7 +402,7 @@ ADT_Node* adt_append_arr( ADT_Node* parent, char const* name ) | ||||
| 	ADT_Node* o = adt_alloc( parent ); | ||||
| 	if ( ! o ) | ||||
| 		return NULL; | ||||
| 	if ( adt_set_arr( o, name, parent->nodes.get_header()->Allocator ) ) | ||||
| 	if ( adt_set_arr( o, name, get_header(parent->nodes)->Allocator ) ) | ||||
| 	{ | ||||
| 		adt_remove_node( o ); | ||||
| 		return NULL; | ||||
| @@ -447,7 +447,7 @@ char* adt_parse_number_strict( ADT_Node* node, char* base_str ) | ||||
| 	while ( *e ) | ||||
| 		++e; | ||||
|  | ||||
| 	while ( *p && ( str_find( "eE.+-", *p ) || char_is_hex_digit( *p ) ) ) | ||||
| 	while ( *p && ( char_first_occurence( "eE.+-", *p ) || char_is_hex_digit( *p ) ) ) | ||||
| 	{ | ||||
| 		++p; | ||||
| 	} | ||||
| @@ -476,7 +476,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) | ||||
| 	u8        node_props = 0; | ||||
|  | ||||
| 	/* skip false positives and special cases */ | ||||
| 	if ( ! ! str_find( "eE", *p ) || ( ! ! str_find( ".+-", *p ) && ! char_is_hex_digit( *( p + 1 ) ) && *( p + 1 ) != '.' ) ) | ||||
| 	if ( ! ! char_first_occurence( "eE", *p ) || ( ! ! char_first_occurence( ".+-", *p ) && ! char_is_hex_digit( *( p + 1 ) ) && *( p + 1 ) != '.' ) ) | ||||
| 	{ | ||||
| 		return ++base_str; | ||||
| 	} | ||||
| @@ -552,7 +552,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) | ||||
| 	char expbuf[ 6 ] = { 0 }; | ||||
| 	ssize   expi        = 0; | ||||
|  | ||||
| 	if ( *e && ! ! str_find( "eE", *e ) ) | ||||
| 	if ( *e && ! ! char_first_occurence( "eE", *e ) ) | ||||
| 	{ | ||||
| 		++e; | ||||
| 		if ( *e == '+' || *e == '-' || char_is_digit( *e ) ) | ||||
| @@ -748,7 +748,7 @@ ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_ | ||||
| 	{ | ||||
| 		p = str_skip_any( p, escaped_chars ); | ||||
| 		_adt_fprintf( file, "%.*s", pointer_diff( b, p ), b ); | ||||
| 		if ( *p && ! ! str_find( escaped_chars, *p ) ) | ||||
| 		if ( *p && ! ! char_first_occurence( escaped_chars, *p ) ) | ||||
| 		{ | ||||
| 			_adt_fprintf( file, "%s%c", escape_symbol, *p ); | ||||
| 			p++; | ||||
| @@ -946,12 +946,12 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if ( columnIndex >= scast(ssize, root->nodes.num()) ) | ||||
| 		if ( columnIndex >= scast(ssize, num(root->nodes)) ) | ||||
| 		{ | ||||
| 			adt_append_arr( root, NULL ); | ||||
| 		} | ||||
|  | ||||
| 		root->nodes[ columnIndex ].nodes.append( rowItem ); | ||||
| 		append(root->nodes[ columnIndex ].nodes, rowItem ); | ||||
|  | ||||
| 		if ( delimiter == delim ) | ||||
| 		{ | ||||
| @@ -979,7 +979,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | ||||
| 	} | ||||
| 	while ( *currentChar ); | ||||
|  | ||||
| 	if ( root->nodes.num() == 0 ) | ||||
| 	if (num( root->nodes) == 0 ) | ||||
| 	{ | ||||
| 		GEN_CSV_ASSERT( "unexpected end of input. stream is empty." ); | ||||
| 		error = ECSV_Error__UNEXPECTED_END_OF_INPUT; | ||||
| @@ -989,12 +989,12 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b | ||||
| 	/* consider first row as a header. */ | ||||
| 	if ( has_header ) | ||||
| 	{ | ||||
| 		for ( ssize i = 0; i < scast(ssize, root->nodes.num()); i++ ) | ||||
| 		for ( ssize i = 0; i < scast(ssize, num(root->nodes)); i++ ) | ||||
| 		{ | ||||
| 			CSV_Object* col = root->nodes + i; | ||||
| 			CSV_Object* hdr = col->nodes; | ||||
| 			col->name       = hdr->string; | ||||
| 			col->nodes.remove_at( 0 ); | ||||
| 			remove_at(col->nodes, 0 ); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -1057,11 +1057,11 @@ void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delimiter ) | ||||
| 	GEN_ASSERT_NOT_NULL( file ); | ||||
| 	GEN_ASSERT_NOT_NULL( obj ); | ||||
| 	GEN_ASSERT( obj->nodes ); | ||||
| 	ssize cols = obj->nodes.num(); | ||||
| 	ssize cols = num(obj->nodes); | ||||
| 	if ( cols == 0 ) | ||||
| 		return; | ||||
|  | ||||
| 	ssize rows = obj->nodes[ 0 ].nodes.num(); | ||||
| 	ssize rows = num(obj->nodes[ 0 ].nodes); | ||||
| 	if ( rows == 0 ) | ||||
| 		return; | ||||
|  | ||||
| @@ -1102,7 +1102,7 @@ String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delimi | ||||
|  | ||||
| 	ssize  fsize; | ||||
| 	u8*    buf    = file_stream_buf( &tmp, &fsize ); | ||||
| 	String output = String::make_length( a, ( char* )buf, fsize ); | ||||
| 	String output = string_make_length( a, ( char* )buf, fsize ); | ||||
| 	file_close( &tmp ); | ||||
| 	return output; | ||||
| } | ||||
|   | ||||
| @@ -76,13 +76,18 @@ | ||||
| /* Platform compiler */ | ||||
|  | ||||
| #if defined( _MSC_VER ) | ||||
| #	define GEN_COMPILER_MSVC 1 | ||||
| #	define GEN_COMPILER_CLANG 0 | ||||
| #	define GEN_COMPILER_MSVC  1 | ||||
| #	define GEN_COMPILER_GCC   0 | ||||
| #elif defined( __GNUC__ ) | ||||
| #	define GEN_COMPILER_GCC 1 | ||||
| #	define GEN_COMPILER_CLANG 0 | ||||
| #	define GEN_COMPILER_MSVC  0 | ||||
| #	define GEN_COMPILER_GCC   1 | ||||
| #elif defined( __clang__ ) | ||||
| #	define GEN_COMPILER_CLANG 1 | ||||
| #elif defined( __MINGW32__ ) | ||||
| #	define GEN_COMPILER_MINGW 1 | ||||
| #	define GEN_COMPILER_MSVC  0 | ||||
| #	define GEN_COMPILER_GCC   1 | ||||
| #else | ||||
| #	error Unknown compiler | ||||
| #endif | ||||
|  | ||||
| @@ -101,6 +106,14 @@ | ||||
| #  define GEN_GCC_VERSION_CHECK(major,minor,patch) (0) | ||||
| #endif | ||||
|  | ||||
| #ifndef GEN_COMPILER_C | ||||
| #	if defined(__STDC_VERSION__) | ||||
| #		define GEN_COMPILER_C 1 | ||||
| #	else | ||||
| #		define GEN_COMPILER_C 0 | ||||
| #	endif | ||||
| #endif | ||||
|  | ||||
| #pragma endregion Platform Detection | ||||
|  | ||||
| #pragma region Mandatory Includes | ||||
| @@ -114,11 +127,23 @@ | ||||
|  | ||||
| #pragma endregion Mandatory Includes | ||||
|  | ||||
| #ifdef GEN_DONT_USE_NAMESPACE | ||||
| #	define GEN_NS | ||||
| #	define GEN_NS_BEGIN | ||||
| #	define GEN_NS_END | ||||
| #if GEN_DONT_USE_NAMESPACE | ||||
| #	if GEN_COMPILER_C | ||||
| #		define GEN_NS_ENUM_BEGIN | ||||
| #		define GEN_NS_ENUM_END | ||||
| #		define GEN_NS | ||||
| #		define GEN_NS_BEGIN | ||||
| #		define GEN_NS_END | ||||
| #	else | ||||
| #		define GEN_NS_ENUM_BEGIN namespace gen_internal_enums { | ||||
| #		define GEN_NS_ENUM_END   } | ||||
| #		define GEN_NS       :: | ||||
| #		define GEN_NS_BEGIN | ||||
| #		define GEN_NS_END | ||||
| #	endif | ||||
| #else | ||||
| #	define GEN_NS_ENUM_BEGIN namespace gen_internal_enums { | ||||
| #	define GEN_NS_ENUM_END   } | ||||
| #	define GEN_NS       gen:: | ||||
| #	define GEN_NS_BEGIN namespace gen { | ||||
| #	define GEN_NS_END   } | ||||
|   | ||||
| @@ -422,7 +422,7 @@ neverinline ssize str_fmt_va( char* text, ssize max_len, char const* fmt, va_lis | ||||
| 			{ | ||||
| 				String gen_str = String { va_arg( va, char*) }; | ||||
|  | ||||
| 				info.precision = gen_str.length(); | ||||
| 				info.precision = length(gen_str); | ||||
| 				len            = _print_string( text, remaining, &info, gen_str ); | ||||
| 			} | ||||
| 			break; | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #pragma region String Ops | ||||
|  | ||||
| const char* char_first_occurence( const char* str, char c ); | ||||
| constexpr auto str_find = &char_first_occurence; | ||||
|  | ||||
| b32   char_is_alpha( char c ); | ||||
| b32   char_is_alphanumeric( char c ); | ||||
|   | ||||
| @@ -4,20 +4,9 @@ | ||||
| #endif | ||||
|  | ||||
| #pragma region String | ||||
|  | ||||
| String String::fmt( AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ... ) | ||||
| String string_make_length( AllocatorInfo allocator, char const* str, ssize length ) | ||||
| { | ||||
| 	va_list va; | ||||
| 	va_start( va, fmt ); | ||||
| 	str_fmt_va( buf, buf_size, fmt, va ); | ||||
| 	va_end( va ); | ||||
|  | ||||
| 	return make( allocator, buf ); | ||||
| } | ||||
|  | ||||
| String String::make_length( AllocatorInfo allocator, char const* str, ssize length ) | ||||
| { | ||||
| 	constexpr ssize header_size = sizeof( Header ); | ||||
| 	constexpr ssize header_size = sizeof( StringHeader ); | ||||
|  | ||||
| 	s32   alloc_size = header_size + length + 1; | ||||
| 	void* allocation = alloc( allocator, alloc_size ); | ||||
| @@ -25,8 +14,8 @@ String String::make_length( AllocatorInfo allocator, char const* str, ssize leng | ||||
| 	if ( allocation == nullptr ) | ||||
| 		return { nullptr }; | ||||
|  | ||||
| 	Header& | ||||
| 	header = * rcast(Header*, allocation); | ||||
| 	StringHeader& | ||||
| 	header = * rcast(StringHeader*, allocation); | ||||
| 	header = { allocator, length, length }; | ||||
|  | ||||
| 	String  result = { rcast( char*, allocation) + header_size }; | ||||
| @@ -41,9 +30,9 @@ String String::make_length( AllocatorInfo allocator, char const* str, ssize leng | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| String String::make_reserve( AllocatorInfo allocator, ssize capacity ) | ||||
| String string_make_reserve( AllocatorInfo allocator, ssize capacity ) | ||||
| { | ||||
| 	constexpr ssize header_size = sizeof( Header ); | ||||
| 	constexpr ssize header_size = sizeof( StringHeader ); | ||||
|  | ||||
| 	s32   alloc_size = header_size + capacity + 1; | ||||
| 	void* allocation = alloc( allocator, alloc_size ); | ||||
| @@ -53,8 +42,8 @@ String String::make_reserve( AllocatorInfo allocator, ssize capacity ) | ||||
|  | ||||
| 	mem_set( allocation, 0, alloc_size ); | ||||
|  | ||||
| 	Header* | ||||
| 		header            = rcast(Header*, allocation); | ||||
| 	StringHeader* | ||||
| 	header            = rcast(StringHeader*, allocation); | ||||
| 	header->Allocator = allocator; | ||||
| 	header->Capacity  = capacity; | ||||
| 	header->Length    = 0; | ||||
| @@ -62,69 +51,4 @@ String String::make_reserve( AllocatorInfo allocator, ssize capacity ) | ||||
| 	String result = { rcast(char*, allocation) + header_size }; | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| String String::fmt_buf( AllocatorInfo allocator, char const* fmt, ... ) | ||||
| { | ||||
| 	local_persist thread_local | ||||
| 	char buf[ GEN_PRINTF_MAXLEN ] = { 0 }; | ||||
|  | ||||
| 	va_list va; | ||||
| 	va_start( va, fmt ); | ||||
| 	str_fmt_va( buf, GEN_PRINTF_MAXLEN, fmt, va ); | ||||
| 	va_end( va ); | ||||
|  | ||||
| 	return make( allocator, buf ); | ||||
| } | ||||
|  | ||||
| bool String::append_fmt( char const* fmt, ... ) | ||||
| { | ||||
| 	ssize   res; | ||||
| 	char buf[ GEN_PRINTF_MAXLEN ] = { 0 }; | ||||
|  | ||||
| 	va_list va; | ||||
| 	va_start( va, fmt ); | ||||
| 	res = str_fmt_va( buf, count_of( buf ) - 1, fmt, va ) - 1; | ||||
| 	va_end( va ); | ||||
|  | ||||
| 	return append( buf, res ); | ||||
| } | ||||
|  | ||||
| bool String::make_space_for( char const* str, ssize add_len ) | ||||
| { | ||||
| 	ssize available = avail_space(); | ||||
|  | ||||
| 	// NOTE: Return if there is enough space left | ||||
| 	if ( available >= add_len ) | ||||
| 	{ | ||||
| 		return true; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		ssize new_len, old_size, new_size; | ||||
|  | ||||
| 		void* ptr; | ||||
| 		void* new_ptr; | ||||
|  | ||||
| 		AllocatorInfo allocator = get_header().Allocator; | ||||
| 		Header*       header	= nullptr; | ||||
|  | ||||
| 		new_len  = grow_formula( length() + add_len ); | ||||
| 		ptr      = & get_header(); | ||||
| 		old_size = size_of( Header ) + length() + 1; | ||||
| 		new_size = size_of( Header ) + new_len + 1; | ||||
|  | ||||
| 		new_ptr = resize( allocator, ptr, old_size, new_size ); | ||||
|  | ||||
| 		if ( new_ptr == nullptr ) | ||||
| 			return false; | ||||
|  | ||||
| 		header            = rcast( Header*, new_ptr); | ||||
| 		header->Allocator = allocator; | ||||
| 		header->Capacity  = new_len; | ||||
|  | ||||
| 		Data = rcast( char*, header + 1 ); | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
| #pragma endregion String | ||||
|   | ||||
| @@ -8,19 +8,20 @@ | ||||
| // Constant string with length. | ||||
| struct StrC | ||||
| { | ||||
| 	ssize          Len; | ||||
| 	ssize       Len; | ||||
| 	char const* Ptr; | ||||
|  | ||||
| #if ! GEN_COMPILER_C | ||||
| 	operator char const* ()               const { return Ptr; } | ||||
| 	char const& operator[]( ssize index ) const { return Ptr[index]; } | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| #define cast_to_strc( str ) * rcast( StrC*, (str) - sizeof(ssize) ) | ||||
| #define txt( text )         StrC { sizeof( text ) - 1, ( text ) } | ||||
|  | ||||
| inline | ||||
| StrC to_str( char const* str ) | ||||
| { | ||||
| StrC to_str( char const* str ) { | ||||
| 	return { str_len( str ), str }; | ||||
| } | ||||
|  | ||||
| @@ -28,388 +29,549 @@ StrC to_str( char const* str ) | ||||
| // This is directly based off the ZPL string api. | ||||
| // They used a header pattern | ||||
| // I kept it for simplicty of porting but its not necessary to keep it that way. | ||||
| #pragma region String | ||||
| struct StringHeader; | ||||
| struct String; | ||||
|  | ||||
| String        string_make(AllocatorInfo allocator, char const* str); | ||||
| String        string_make(AllocatorInfo allocator, StrC str); | ||||
| String        string_make_reserve(AllocatorInfo allocator, ssize capacity); | ||||
| String        string_make_length(AllocatorInfo allocator, char const* str, ssize length); | ||||
| String        string_fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...); | ||||
| String        string_fmt_buf(AllocatorInfo allocator, char const* fmt, ...); | ||||
| String        string_join(AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue); | ||||
| usize         string_grow_formula(usize value); | ||||
| bool          are_equal(String const& lhs, String const& rhs); | ||||
| bool          are_equal(String const& lhs, StrC rhs); | ||||
| bool          make_space_for(String& str, char const* to_append, ssize add_len); | ||||
| bool          append(String& str, char c); | ||||
| bool          append(String& str, char const* str_to_append); | ||||
| bool          append(String& str, char const* str_to_append, ssize length); | ||||
| bool          append(String& str, StrC str_to_append); | ||||
| bool          append(String& str, const String other); | ||||
| bool          append_fmt(String& str, char const* fmt, ...); | ||||
| ssize         avail_space(String const& str); | ||||
| char&         back(String& str); | ||||
| bool          contains(String const& str, StrC substring); | ||||
| bool          contains(String const& str, String const& substring); | ||||
| ssize         capacity(String const& str); | ||||
| void          clear(String& str); | ||||
| String        duplicate(String const& str, AllocatorInfo allocator); | ||||
| void          free(String& str); | ||||
| StringHeader& get_header(String& str); | ||||
| ssize         length(String const& str); | ||||
| b32           starts_with(String const& str, StrC substring); | ||||
| b32           starts_with(String const& str, String substring); | ||||
| void          skip_line(String& str); | ||||
| void          strip_space(String& str); | ||||
| void          trim(String& str, char const* cut_set); | ||||
| void          trim_space(String& str); | ||||
| String        visualize_whitespace(String const& str); | ||||
|  | ||||
| struct StringHeader { | ||||
| 	AllocatorInfo Allocator; | ||||
| 	ssize         Capacity; | ||||
| 	ssize         Length; | ||||
| }; | ||||
|  | ||||
| #if ! GEN_COMPILER_C | ||||
| struct String | ||||
| { | ||||
| 	struct Header | ||||
| 	{ | ||||
| 		AllocatorInfo Allocator; | ||||
| 		ssize            Capacity; | ||||
| 		ssize            Length; | ||||
| 	}; | ||||
| 	char* Data; | ||||
|  | ||||
| 	static | ||||
| 	usize grow_formula( usize value ) | ||||
| 	{ | ||||
| 		// Using a very aggressive growth formula to reduce time mem_copying with recursive calls to append in this library. | ||||
| 		return 4 * value + 8; | ||||
| 	} | ||||
| 	forceinline operator bool()              { return Data != nullptr; } | ||||
| 	forceinline operator char*()             { return Data; } | ||||
| 	forceinline operator char const*() const { return Data; } | ||||
| 	forceinline operator StrC() const        { return { GEN_NS length(* this), Data }; } | ||||
|  | ||||
| 	static | ||||
| 	String make( AllocatorInfo allocator, char const* str ) | ||||
| 	{ | ||||
| 		ssize length = str ? str_len( str ) : 0; | ||||
| 		return make_length( allocator, str, length ); | ||||
| 	} | ||||
|  | ||||
| 	static | ||||
| 	String make( AllocatorInfo allocator, StrC str ) | ||||
| 	{ | ||||
| 		return make_length( allocator, str.Ptr, str.Len ); | ||||
| 	} | ||||
|  | ||||
| 	static | ||||
| 	String make_reserve( AllocatorInfo allocator, ssize capacity ); | ||||
|  | ||||
| 	static | ||||
| 	String make_length( AllocatorInfo allocator, char const* str, ssize length ); | ||||
|  | ||||
| 	static | ||||
| 	String fmt( AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ... ); | ||||
|  | ||||
| 	static | ||||
| 	String fmt_buf( AllocatorInfo allocator, char const* fmt, ... ); | ||||
|  | ||||
| 	static | ||||
| 	String join( AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue ) | ||||
| 	{ | ||||
| 		String result = make( allocator, "" ); | ||||
|  | ||||
| 		for ( ssize idx = 0; idx < num_parts; ++idx ) | ||||
| 		{ | ||||
| 			result.append( parts[ idx ] ); | ||||
|  | ||||
| 			if ( idx < num_parts - 1 ) | ||||
| 				result.append( glue ); | ||||
| 		} | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	static | ||||
| 	bool are_equal( String lhs, String rhs ) | ||||
| 	{ | ||||
| 		if ( lhs.length() != rhs.length() ) | ||||
| 			return false; | ||||
|  | ||||
| 		for ( ssize idx = 0; idx < lhs.length(); ++idx ) | ||||
| 			if ( lhs[ idx ] != rhs[ idx ] ) | ||||
| 				return false; | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	static | ||||
| 	bool are_equal( String lhs, StrC rhs ) | ||||
| 	{ | ||||
| 		if ( lhs.length() != (rhs.Len) ) | ||||
| 			return false; | ||||
|  | ||||
| 		for ( ssize idx = 0; idx < lhs.length(); ++idx ) | ||||
| 			if ( lhs[idx] != rhs[idx] ) | ||||
| 				return false; | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	bool make_space_for( char const* str, ssize add_len ); | ||||
|  | ||||
| 	bool append( char c ) | ||||
| 	{ | ||||
| 		return append( & c, 1 ); | ||||
| 	} | ||||
|  | ||||
| 	bool append( char const* str ) | ||||
| 	{ | ||||
| 		return append( str, str_len( str ) ); | ||||
| 	} | ||||
|  | ||||
| 	bool append( char const* str, ssize length ) | ||||
| 	{ | ||||
| 		if ( sptr(str) > 0 ) | ||||
| 		{ | ||||
| 			ssize curr_len = this->length(); | ||||
|  | ||||
| 			if ( ! make_space_for( str, length ) ) | ||||
| 				return false; | ||||
|  | ||||
| 			Header& header = get_header(); | ||||
|  | ||||
| 			mem_copy( Data + curr_len, str, length ); | ||||
|  | ||||
| 			Data[ curr_len + length ] = '\0'; | ||||
|  | ||||
| 			header.Length = curr_len + length; | ||||
| 		} | ||||
| 		return str != nullptr; | ||||
| 	} | ||||
|  | ||||
| 	bool append( StrC str) | ||||
| 	{ | ||||
| 		return append( str.Ptr, str.Len ); | ||||
| 	} | ||||
|  | ||||
| 	bool append( const String other ) | ||||
| 	{ | ||||
| 		return append( other.Data, other.length() ); | ||||
| 	} | ||||
|  | ||||
| 	bool append_fmt( char const* fmt, ... ); | ||||
|  | ||||
| 	ssize avail_space() const | ||||
| 	{ | ||||
| 		Header const& | ||||
| 		header = * rcast( Header const*, Data - sizeof( Header )); | ||||
|  | ||||
| 		return header.Capacity - header.Length; | ||||
| 	} | ||||
|  | ||||
| 	char& back() | ||||
| 	{ | ||||
| 		return Data[ length() - 1 ]; | ||||
| 	} | ||||
|  | ||||
| 	ssize capacity() const | ||||
| 	{ | ||||
| 		Header const& | ||||
| 		header = * rcast( Header const*, Data - sizeof( Header )); | ||||
|  | ||||
| 		return header.Capacity; | ||||
| 	} | ||||
|  | ||||
| 	void clear() | ||||
| 	{ | ||||
| 		get_header().Length = 0; | ||||
| 	} | ||||
|  | ||||
| 	String duplicate( AllocatorInfo allocator ) const | ||||
| 	{ | ||||
| 		return make_length( allocator, Data, length() ); | ||||
| 	} | ||||
|  | ||||
| 	void free() | ||||
| 	{ | ||||
| 		if ( ! Data ) | ||||
| 			return; | ||||
|  | ||||
| 		Header& header = get_header(); | ||||
|  | ||||
| 		gen::free( header.Allocator, & header ); | ||||
| 	} | ||||
|  | ||||
| 	Header& get_header() | ||||
| 	{ | ||||
| 		return *(Header*)(Data - sizeof(Header)); | ||||
| 	} | ||||
|  | ||||
| 	ssize length() const | ||||
| 	{ | ||||
| 		Header const& | ||||
| 		header = * rcast( Header const*, Data - sizeof( Header )); | ||||
|  | ||||
| 		return header.Length; | ||||
| 	} | ||||
|  | ||||
| 	b32 starts_with( StrC substring ) const | ||||
| 	{ | ||||
| 		if (substring.Len > length()) | ||||
| 			return false; | ||||
|  | ||||
| 		b32 result = str_compare(Data, substring.Ptr, substring.Len ) == 0; | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	b32 starts_with( String substring ) const | ||||
| 	{ | ||||
| 		if (substring.length() > length()) | ||||
| 			return false; | ||||
|  | ||||
| 		b32 result = str_compare(Data, substring, substring.length() - 1 ) == 0; | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	void skip_line() | ||||
| 	{ | ||||
| 	#define current (*scanner) | ||||
| 		char* scanner = Data; | ||||
| 		while ( current != '\r' && current != '\n' ) | ||||
| 		{ | ||||
| 			++ scanner; | ||||
| 		} | ||||
|  | ||||
| 		s32 new_length = scanner - Data; | ||||
|  | ||||
| 		if ( current == '\r' ) | ||||
| 		{ | ||||
| 			new_length += 1; | ||||
| 		} | ||||
|  | ||||
| 		mem_move( Data, scanner, new_length ); | ||||
|  | ||||
| 		Header* header = & get_header(); | ||||
| 		header->Length = new_length; | ||||
| 	#undef current | ||||
| 	} | ||||
|  | ||||
| 	void strip_space() | ||||
| 	{ | ||||
| 		char* write_pos = Data; | ||||
| 		char* read_pos  = Data; | ||||
|  | ||||
| 		while ( * read_pos) | ||||
| 		{ | ||||
| 			if ( ! char_is_space( *read_pos )) | ||||
| 			{ | ||||
| 				*write_pos = *read_pos; | ||||
| 				write_pos++; | ||||
| 			} | ||||
| 			read_pos++; | ||||
| 		} | ||||
|  | ||||
| 		write_pos[0] = '\0';  // Null-terminate the modified string | ||||
|  | ||||
| 		// Update the length if needed | ||||
| 		get_header().Length = write_pos - Data; | ||||
| 	} | ||||
|  | ||||
| 	void trim( char const* cut_set ) | ||||
| 	{ | ||||
| 		ssize len = 0; | ||||
|  | ||||
| 		char* start_pos = Data; | ||||
| 		char* end_pos   = Data + length() - 1; | ||||
|  | ||||
| 		while ( start_pos <= end_pos && char_first_occurence( cut_set, *start_pos ) ) | ||||
| 			start_pos++; | ||||
|  | ||||
| 		while ( end_pos > start_pos && char_first_occurence( cut_set, *end_pos ) ) | ||||
| 			end_pos--; | ||||
|  | ||||
| 		len = scast( ssize, ( start_pos > end_pos ) ? 0 : ( ( end_pos - start_pos ) + 1 ) ); | ||||
|  | ||||
| 		if ( Data != start_pos ) | ||||
| 			mem_move( Data, start_pos, len ); | ||||
|  | ||||
| 		Data[ len ] = '\0'; | ||||
|  | ||||
| 		get_header().Length = len; | ||||
| 	} | ||||
|  | ||||
| 	void trim_space() | ||||
| 	{ | ||||
| 		return trim( " \t\r\n\v\f" ); | ||||
| 	} | ||||
|  | ||||
| 	// Debug function that provides a copy of the string with whitespace characters visualized. | ||||
| 	String visualize_whitespace() const | ||||
| 	{ | ||||
| 		Header* header = (Header*)(Data - sizeof(Header)); | ||||
|  | ||||
| 		String result = make_reserve(header->Allocator, length() * 2); // Assume worst case for space requirements. | ||||
|  | ||||
| 		for ( char c : *this ) | ||||
| 		{ | ||||
| 			switch ( c ) | ||||
| 			{ | ||||
| 				case ' ': | ||||
| 					result.append( txt("·") ); | ||||
| 				break; | ||||
| 				case '\t': | ||||
| 					result.append( txt("→") ); | ||||
| 				break; | ||||
| 				case '\n': | ||||
| 					result.append( txt("↵") ); | ||||
| 				break; | ||||
| 				case '\r': | ||||
| 					result.append( txt("⏎") ); | ||||
| 				break; | ||||
| 				case '\v': | ||||
| 					result.append( txt("⇕") ); | ||||
| 				break; | ||||
| 				case '\f': | ||||
| 					result.append( txt("⌂") ); | ||||
| 				break; | ||||
| 				default: | ||||
| 					result.append(c); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	// For-range support | ||||
|  | ||||
| 	char* begin() const | ||||
| 	{ | ||||
| 		return Data; | ||||
| 	} | ||||
|  | ||||
| 	char* end() const | ||||
| 	{ | ||||
| 		Header const& | ||||
| 		header = * rcast( Header const*, Data - sizeof( Header )); | ||||
|  | ||||
| 		return Data + header.Length; | ||||
| 	} | ||||
|  | ||||
| 	operator bool() | ||||
| 	{ | ||||
| 		return Data != nullptr; | ||||
| 	} | ||||
|  | ||||
| 	operator char* () | ||||
| 	{ | ||||
| 		return Data; | ||||
| 	} | ||||
|  | ||||
| 	operator char const* () const | ||||
| 	{ | ||||
| 		return Data; | ||||
| 	} | ||||
|  | ||||
| 	operator StrC() const | ||||
| 	{ | ||||
| 		return { length(), Data }; | ||||
| 	} | ||||
|  | ||||
| 	// Used with cached strings | ||||
| 	// Essentially makes the string a string view. | ||||
| 	String const& operator = ( String const& other ) const | ||||
| 	{ | ||||
| 		if ( this == & other ) | ||||
| 	String const& operator=(String const& other) const { | ||||
| 		if (this == &other) | ||||
| 			return *this; | ||||
|  | ||||
| 		String* | ||||
| 		this_ = ccast(String*, this); | ||||
| 		String* this_ = ccast(String*, this); | ||||
| 		this_->Data = other.Data; | ||||
|  | ||||
| 		return *this; | ||||
| 	} | ||||
|  | ||||
| 	char& operator [] ( ssize index ) | ||||
| 	{ | ||||
| 		return Data[ index ]; | ||||
| 	forceinline char& operator[](ssize index)             { return Data[index]; } | ||||
| 	forceinline char const& operator[](ssize index) const { return Data[index]; } | ||||
|  | ||||
| 	forceinline char* begin() const { return Data; } | ||||
| 	forceinline char* end() const   { return Data + GEN_NS length(* this); } | ||||
|  | ||||
| #if GEN_SUPPORT_CPP_MEMBER_FEATURES | ||||
| #pragma region Member Mapping | ||||
| 	forceinline static String make(AllocatorInfo allocator, char const* str)                { return GEN_NS string_make(allocator, str); } | ||||
| 	forceinline static String make(AllocatorInfo allocator, StrC str)                       { return GEN_NS string_make(allocator, str); } | ||||
| 	forceinline static String make_reserve(AllocatorInfo allocator, ssize cap)              { return GEN_NS string_make_reserve(allocator, cap); } | ||||
| 	forceinline static String make_length(AllocatorInfo a, char const* s, ssize l)          { return GEN_NS string_make_length(a, s, l); } | ||||
| 	forceinline static String join(AllocatorInfo a, char const** p, ssize n, char const* g) { return GEN_NS string_join(a, p, n, g); } | ||||
| 	forceinline static usize  grow_formula(usize value)                                     { return GEN_NS string_grow_formula(value); } | ||||
|  | ||||
| 	static | ||||
| 	String fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) { | ||||
| 		va_list va; | ||||
| 		va_start(va, fmt); | ||||
| 		str_fmt_va(buf, buf_size, fmt, va); | ||||
| 		va_end(va); | ||||
| 		return GEN_NS string_make(allocator, buf); | ||||
| 	} | ||||
|  | ||||
| 	char const& operator [] ( ssize index ) const | ||||
| 	{ | ||||
| 		return Data[ index ]; | ||||
| 	static | ||||
| 	String fmt_buf(AllocatorInfo allocator, char const* fmt, ...) { | ||||
| 		local_persist thread_local | ||||
| 		char buf[GEN_PRINTF_MAXLEN] = { 0 }; | ||||
| 		va_list va; | ||||
| 		va_start(va, fmt); | ||||
| 		str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va); | ||||
| 		va_end(va); | ||||
| 		return GEN_NS string_make(allocator, buf); | ||||
| 	} | ||||
|  | ||||
| 	char* Data; | ||||
| 	forceinline bool          make_space_for(char const* str, ssize add_len) { return GEN_NS make_space_for(*this, str, add_len); } | ||||
| 	forceinline bool          append(char c)                                 { return GEN_NS append(*this, c); } | ||||
| 	forceinline bool          append(char const* str)                        { return GEN_NS append(*this, str); } | ||||
| 	forceinline bool          append(char const* str, ssize length)          { return GEN_NS append(*this, str, length); } | ||||
| 	forceinline bool          append(StrC str)                               { return GEN_NS append(*this, str); } | ||||
| 	forceinline bool          append(const String other)                     { return GEN_NS append(*this, other); } | ||||
| 	forceinline ssize         avail_space() const                            { return GEN_NS avail_space(*this); } | ||||
| 	forceinline char&         back()                                         { return GEN_NS back(*this); } | ||||
| 	forceinline bool          contains(StrC substring) const                 { return GEN_NS contains(*this, substring); } | ||||
| 	forceinline bool          contains(String const& substring) const        { return GEN_NS contains(*this, substring); } | ||||
| 	forceinline ssize         capacity() const                               { return GEN_NS capacity(*this); } | ||||
| 	forceinline void          clear()                                        { GEN_NS clear(*this); } | ||||
| 	forceinline String        duplicate(AllocatorInfo allocator) const       { return GEN_NS duplicate(*this, allocator); } | ||||
| 	forceinline void          free()                                         { GEN_NS free(*this); } | ||||
| 	forceinline bool          is_equal(String const& other) const            { return GEN_NS are_equal(* this, other); } | ||||
| 	forceinline bool          is_equal(StrC other) const                     { return GEN_NS are_equal(* this, other); } | ||||
| 	forceinline ssize         length() const                                 { return GEN_NS length(*this); } | ||||
| 	forceinline b32           starts_with(StrC substring) const              { return GEN_NS starts_with(*this, substring); } | ||||
| 	forceinline b32           starts_with(String substring) const            { return GEN_NS starts_with(*this, substring); } | ||||
| 	forceinline void          skip_line()                                    { GEN_NS skip_line(*this); } | ||||
| 	forceinline void          strip_space()                                  { GEN_NS strip_space(*this); } | ||||
| 	forceinline void          trim(char const* cut_set)                      { GEN_NS trim(*this, cut_set); } | ||||
| 	forceinline void          trim_space()                                   { GEN_NS trim_space(*this); } | ||||
| 	forceinline String        visualize_whitespace() const                   { return GEN_NS visualize_whitespace(*this); } | ||||
| 	forceinline StringHeader& get_header()                                   { return GEN_NS get_header(*this); } | ||||
|  | ||||
| 	bool append_fmt(char const* fmt, ...) { | ||||
| 		ssize res; | ||||
| 		char buf[GEN_PRINTF_MAXLEN] = { 0 }; | ||||
|  | ||||
| 		va_list va; | ||||
| 		va_start(va, fmt); | ||||
| 		res = str_fmt_va(buf, count_of(buf) - 1, fmt, va) - 1; | ||||
| 		va_end(va); | ||||
|  | ||||
| 		return GEN_NS append(*this, buf, res); | ||||
| 	} | ||||
| #pragma endregion Member Mapping | ||||
| #endif | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| struct String_POD | ||||
| inline char* begin(String& str) { return str; } | ||||
| inline char* end(String& str)   { return scast(char*, str) + length(str); } | ||||
| inline char* next(String& str)  { return scast(char*, str) + 1; } | ||||
|  | ||||
| inline | ||||
| usize string_grow_formula(usize value) { | ||||
| 	// Using a very aggressive growth formula to reduce time mem_copying with recursive calls to append in this library. | ||||
| 	return 4 * value + 8; | ||||
| } | ||||
|  | ||||
| inline | ||||
| String string_make(AllocatorInfo allocator, char const* str) { | ||||
| 	ssize length = str ? str_len(str) : 0; | ||||
| 	return string_make_length(allocator, str, length); | ||||
| } | ||||
|  | ||||
| inline | ||||
| String string_make(AllocatorInfo allocator, StrC str) { | ||||
| 	return string_make_length(allocator, str.Ptr, str.Len); | ||||
| } | ||||
|  | ||||
| inline | ||||
| String string_fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) { | ||||
| 	va_list va; | ||||
| 	va_start(va, fmt); | ||||
| 	str_fmt_va(buf, buf_size, fmt, va); | ||||
| 	va_end(va); | ||||
|  | ||||
| 	return string_make(allocator, buf); | ||||
| } | ||||
|  | ||||
| inline | ||||
| String string_fmt_buf(AllocatorInfo allocator, char const* fmt, ...) | ||||
| { | ||||
| 	local_persist thread_local | ||||
| 	char buf[GEN_PRINTF_MAXLEN] = { 0 }; | ||||
|  | ||||
| 	va_list va; | ||||
| 	va_start(va, fmt); | ||||
| 	str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va); | ||||
| 	va_end(va); | ||||
|  | ||||
| 	return string_make(allocator, buf); | ||||
| } | ||||
|  | ||||
| inline | ||||
| String string_join(AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue) | ||||
| { | ||||
| 	String result = string_make(allocator, ""); | ||||
|  | ||||
| 	for (ssize idx = 0; idx < num_parts; ++idx) | ||||
| 	{ | ||||
| 		append(result, parts[idx]); | ||||
|  | ||||
| 		if (idx < num_parts - 1) | ||||
| 			append(result, glue); | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool append(String& str, char c) { | ||||
| 	return append(str, &c, 1); | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool append(String& str, char const* str_to_append) { | ||||
| 	return append(str, str_to_append, str_len(str_to_append)); | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool append(String& str, char const* str_to_append, ssize append_length) | ||||
| { | ||||
| 	if (sptr(str_to_append) > 0) | ||||
| 	{ | ||||
| 		ssize curr_len = length(str); | ||||
|  | ||||
| 		if (!make_space_for(str, str_to_append, append_length)) | ||||
| 			return false; | ||||
|  | ||||
| 		StringHeader& header = get_header(str); | ||||
|  | ||||
| 		mem_copy( scast(char*, str) + curr_len, str_to_append, append_length); | ||||
|  | ||||
| 		str[curr_len + append_length] = '\0'; | ||||
|  | ||||
| 		header.Length = curr_len + append_length; | ||||
| 	} | ||||
| 	return str_to_append != nullptr; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool append(String& str, StrC str_to_append) { | ||||
| 	return append(str, str_to_append.Ptr, str_to_append.Len); | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool append(String& str, const String other) { | ||||
| 	return append(str, other, length(other)); | ||||
| } | ||||
|  | ||||
| bool append_fmt(String& str, char const* fmt, ...) { | ||||
| 	ssize res; | ||||
| 	char buf[GEN_PRINTF_MAXLEN] = { 0 }; | ||||
|  | ||||
| 	va_list va; | ||||
| 	va_start(va, fmt); | ||||
| 	res = str_fmt_va(buf, count_of(buf) - 1, fmt, va) - 1; | ||||
| 	va_end(va); | ||||
|  | ||||
| 	return append(str, buf, res); | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool are_equal(String const& lhs, String const& rhs) | ||||
| { | ||||
| 	if (length(lhs) != length(rhs)) | ||||
| 		return false; | ||||
|  | ||||
| 	for (ssize idx = 0; idx < length(lhs); ++idx) | ||||
| 		if (lhs[idx] != rhs[idx]) | ||||
| 			return false; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool are_equal(String const& lhs, StrC rhs) | ||||
| { | ||||
| 	if (length(lhs) != (rhs.Len)) | ||||
| 		return false; | ||||
|  | ||||
| 	for (ssize idx = 0; idx < length(lhs); ++idx) | ||||
| 		if (lhs[idx] != rhs[idx]) | ||||
| 			return false; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| inline | ||||
| ssize avail_space(String const& str) { | ||||
| 	StringHeader const& header = *rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
| 	return header.Capacity - header.Length; | ||||
| } | ||||
|  | ||||
| inline | ||||
| char& back(String& str) { | ||||
| 	return str.Data[length(str) - 1]; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool contains(String const& str, StrC substring) | ||||
| { | ||||
| 	StringHeader const& header = *rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
|  | ||||
| 	if (substring.Len > header.Length) | ||||
| 		return false; | ||||
|  | ||||
| 	ssize main_len = header.Length; | ||||
| 	ssize sub_len = substring.Len; | ||||
|  | ||||
| 	for (ssize idx = 0; idx <= main_len - sub_len; ++idx) | ||||
| 	{ | ||||
| 		if (str_compare(str.Data + idx, substring.Ptr, sub_len) == 0) | ||||
| 			return true; | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool contains(String const& str, String const& substring) | ||||
| { | ||||
| 	StringHeader const& header = *rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
|  | ||||
| 	if (length(substring) > header.Length) | ||||
| 		return false; | ||||
|  | ||||
| 	ssize main_len = header.Length; | ||||
| 	ssize sub_len = length(substring); | ||||
|  | ||||
| 	for (ssize idx = 0; idx <= main_len - sub_len; ++idx) | ||||
| 	{ | ||||
| 		if (str_compare(str.Data + idx, substring.Data, sub_len) == 0) | ||||
| 			return true; | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| inline | ||||
| ssize capacity(String const& str) { | ||||
|    StringHeader const& header = *rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
|    return header.Capacity; | ||||
| } | ||||
|  | ||||
| inline | ||||
| void clear(String& str) { | ||||
|    get_header(str).Length = 0; | ||||
| } | ||||
|  | ||||
| inline | ||||
| String duplicate(String const& str, AllocatorInfo allocator) { | ||||
|    return string_make_length(allocator, str, length(str)); | ||||
| } | ||||
|  | ||||
| inline | ||||
| void free(String& str) { | ||||
|    if (!str.Data) | ||||
|    	return; | ||||
|  | ||||
|    StringHeader& header = get_header(str); | ||||
|    GEN_NS free(header.Allocator, &header); | ||||
| } | ||||
|  | ||||
| inline | ||||
| StringHeader& get_header(String& str) { | ||||
|    return *(StringHeader*)(str.Data - sizeof(StringHeader)); | ||||
| } | ||||
|  | ||||
| inline | ||||
| ssize length(String const& str) | ||||
| { | ||||
|    StringHeader const& header = *rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader)); | ||||
|    return header.Length; | ||||
| } | ||||
|  | ||||
| inline | ||||
| bool make_space_for(String& str, char const* to_append, ssize add_len) | ||||
| { | ||||
| 	ssize available = avail_space(str); | ||||
|  | ||||
| 	if (available >= add_len) { | ||||
| 		return true; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		ssize new_len, old_size, new_size; | ||||
| 		void* ptr; | ||||
| 		void* new_ptr; | ||||
|  | ||||
| 		AllocatorInfo allocator = get_header(str).Allocator; | ||||
| 		StringHeader* header = nullptr; | ||||
|  | ||||
| 		new_len = string_grow_formula(length(str) + add_len); | ||||
| 		ptr = &get_header(str); | ||||
| 		old_size = size_of(StringHeader) + length(str) + 1; | ||||
| 		new_size = size_of(StringHeader) + new_len + 1; | ||||
|  | ||||
| 		new_ptr = resize(allocator, ptr, old_size, new_size); | ||||
|  | ||||
| 		if (new_ptr == nullptr) | ||||
| 			return false; | ||||
|  | ||||
| 		header = rcast(StringHeader*, new_ptr); | ||||
| 		header->Allocator = allocator; | ||||
| 		header->Capacity = new_len; | ||||
|  | ||||
| 		str.Data = rcast(char*, header + 1); | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| inline | ||||
| b32 starts_with(String const& str, StrC substring) { | ||||
| 	if (substring.Len > length(str)) | ||||
| 	return false; | ||||
|  | ||||
| 	b32 result = str_compare(str.Data, substring.Ptr, substring.Len) == 0; | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| b32 starts_with(String const& str, String substring) { | ||||
| 	if (length(substring) > length(str)) | ||||
| 		return false; | ||||
|  | ||||
| 	b32 result = str_compare(str.Data, substring.Data, length(substring) - 1) == 0; | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| inline | ||||
| void skip_line(String& str) | ||||
| { | ||||
| #define current (*scanner) | ||||
| 	char* scanner = str.Data; | ||||
| 	while (current != '\r' && current != '\n') { | ||||
|  		++scanner; | ||||
| 	} | ||||
|  | ||||
| 	s32 new_length = scanner - str.Data; | ||||
|  | ||||
| 	if (current == '\r') { | ||||
| 		new_length += 1; | ||||
| 	} | ||||
|  | ||||
| 	mem_move(str.Data, scanner, new_length); | ||||
|  | ||||
| 	StringHeader* header = &get_header(str); | ||||
| 	header->Length = new_length; | ||||
| #undef current | ||||
| } | ||||
|  | ||||
| inline | ||||
| void strip_space(String& str) | ||||
| { | ||||
|    char* write_pos = str.Data; | ||||
|    char* read_pos = str.Data; | ||||
|  | ||||
|    while (*read_pos) | ||||
|    { | ||||
|    	if (!char_is_space(*read_pos)) | ||||
|    	{ | ||||
|    		*write_pos = *read_pos; | ||||
|    		write_pos++; | ||||
|    	} | ||||
|    	read_pos++; | ||||
|    } | ||||
|  | ||||
|    write_pos[0] = '\0';  // Null-terminate the modified string | ||||
|  | ||||
|    // Update the length if needed | ||||
|    get_header(str).Length = write_pos - str.Data; | ||||
| } | ||||
|  | ||||
| inline | ||||
| void trim(String& str, char const* cut_set) | ||||
| { | ||||
|    ssize len = 0; | ||||
|  | ||||
|    char* start_pos = str.Data; | ||||
|    char* end_pos = str.Data + length(str) - 1; | ||||
|  | ||||
|    while (start_pos <= end_pos && char_first_occurence(cut_set, *start_pos)) | ||||
|    	start_pos++; | ||||
|  | ||||
|    while (end_pos > start_pos && char_first_occurence(cut_set, *end_pos)) | ||||
|    	end_pos--; | ||||
|  | ||||
|    len = scast(ssize, (start_pos > end_pos) ? 0 : ((end_pos - start_pos) + 1)); | ||||
|  | ||||
|    if (str.Data != start_pos) | ||||
|    	mem_move(str.Data, start_pos, len); | ||||
|  | ||||
|    str.Data[len] = '\0'; | ||||
|  | ||||
|    get_header(str).Length = len; | ||||
| } | ||||
|  | ||||
| inline | ||||
| void trim_space(String& str) { | ||||
|    trim(str, " \t\r\n\v\f"); | ||||
| } | ||||
|  | ||||
| inline | ||||
| String visualize_whitespace(String const& str) | ||||
| { | ||||
| 	StringHeader* header = (StringHeader*)(scast(char const*, str) - sizeof(StringHeader)); | ||||
| 	String        result = string_make_reserve(header->Allocator, length(str) * 2); // Assume worst case for space requirements. | ||||
|  | ||||
| 	for (auto c : str) switch (c) | ||||
| 	{ | ||||
| 		case ' ': | ||||
| 			append(result, txt("·")); | ||||
| 		break; | ||||
| 		case '\t': | ||||
| 			append(result, txt("→")); | ||||
| 		break; | ||||
| 		case '\n': | ||||
| 			append(result, txt("↵")); | ||||
| 		break; | ||||
| 		case '\r': | ||||
| 			append(result, txt("⏎")); | ||||
| 		break; | ||||
| 		case '\v': | ||||
| 			append(result, txt("⇕")); | ||||
| 		break; | ||||
| 		case '\f': | ||||
| 			append(result, txt("⌂")); | ||||
| 		break; | ||||
| 		default: | ||||
| 			append(result, c); | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
| #pragma endregion String | ||||
|  | ||||
| struct String_POD { | ||||
| 	char* Data; | ||||
| }; | ||||
| static_assert( sizeof( String_POD ) == sizeof( String ), "String is not a POD" ); | ||||
|  | ||||
| // Implements basic string interning. Data structure is based off the ZPL Hashtable. | ||||
| using StringTable = HashTable<String const>; | ||||
| typedef HashTable<String const>   StringTable; | ||||
|  | ||||
| // Represents strings cached with the string table. | ||||
| // Should never be modified, if changed string is desired, cache_string( str ) another. | ||||
| using StringCached = String const; | ||||
| typedef String const   StringCached; | ||||
|  | ||||
| #pragma endregion Strings | ||||
|   | ||||
| @@ -11,23 +11,23 @@ using namespace gen; | ||||
| CodeBody gen_ecode( char const* path ) | ||||
| { | ||||
| 	char  scratch_mem[kilobytes(1)]; | ||||
| 	Arena scratch = Arena::init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||
| 	Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||
|  | ||||
| 	file_read_contents( scratch, zero_terminate, path ); | ||||
| 	file_read_contents( allocator_info(scratch), zero_terminate, path ); | ||||
|  | ||||
| 	CSV_Object csv_nodes; | ||||
| 	csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | ||||
|  | ||||
| 	Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes; | ||||
|  | ||||
| 	String enum_entries   = String::make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String to_str_entries = String::make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String enum_entries   = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String to_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
|  | ||||
| 	for ( ADT_Node node : enum_strs ) | ||||
| 	{ | ||||
| 		char const* code = node.string; | ||||
| 		enum_entries.append_fmt( "%s,\n", code ); | ||||
| 		to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", code, code ); | ||||
| 		append_fmt( enum_entries, "%s,\n", code ); | ||||
| 		append_fmt( to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", code, code ); | ||||
| 	} | ||||
|  | ||||
| 	CodeEnum enum_code = parse_enum(gen::token_fmt_impl((3 + 1) / 2, "entries", (StrC)enum_entries, "enum Type : u32 { <entries> NumTypes };")); | ||||
| @@ -57,9 +57,9 @@ CodeBody gen_ecode( char const* path ) | ||||
| CodeBody gen_eoperator( char const* path ) | ||||
| { | ||||
| 	char scratch_mem[kilobytes(4)]; | ||||
| 	Arena scratch = Arena::init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||
| 	Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||
|  | ||||
| 	file_read_contents( scratch, zero_terminate, path ); | ||||
| 	file_read_contents( allocator_info(scratch), zero_terminate, path ); | ||||
|  | ||||
| 	CSV_Object csv_nodes; | ||||
| 	csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | ||||
| @@ -67,16 +67,16 @@ CodeBody gen_eoperator( char const* path ) | ||||
| 	Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes; | ||||
| 	Array<ADT_Node> str_strs  = csv_nodes.nodes[1].nodes; | ||||
|  | ||||
| 	String enum_entries   = String::make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String to_str_entries = String::make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String enum_entries   = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String to_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
|  | ||||
| 	for (usize idx = 0; idx < enum_strs.num(); idx++) | ||||
| 	for (usize idx = 0; idx < num(enum_strs); idx++) | ||||
| 	{ | ||||
| 		char const* enum_str     = enum_strs[idx].string; | ||||
| 		char const* entry_to_str = str_strs [idx].string; | ||||
|  | ||||
| 		enum_entries.append_fmt( "%s,\n", enum_str ); | ||||
| 		to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 		append_fmt( enum_entries, "%s,\n", enum_str ); | ||||
| 		append_fmt( to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 	} | ||||
|  | ||||
| 	CodeEnum  enum_code = parse_enum(token_fmt("entries", (StrC)enum_entries, stringize( | ||||
| @@ -113,9 +113,9 @@ CodeBody gen_eoperator( char const* path ) | ||||
| CodeBody gen_especifier( char const* path ) | ||||
| { | ||||
| 	char scratch_mem[kilobytes(4)]; | ||||
| 	Arena scratch = Arena::init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||
| 	Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||
|  | ||||
| 	file_read_contents( scratch, zero_terminate, path ); | ||||
| 	file_read_contents( allocator_info(scratch), zero_terminate, path ); | ||||
|  | ||||
| 	CSV_Object csv_nodes; | ||||
| 	csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false ); | ||||
| @@ -123,16 +123,16 @@ CodeBody gen_especifier( char const* path ) | ||||
| 	Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes; | ||||
| 	Array<ADT_Node> str_strs  = csv_nodes.nodes[1].nodes; | ||||
|  | ||||
| 	String enum_entries   = String::make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String to_str_entries = String::make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String enum_entries   = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
| 	String to_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) ); | ||||
|  | ||||
| 	for (usize idx = 0; idx < enum_strs.num(); idx++) | ||||
| 	for (usize idx = 0; idx < num(enum_strs); idx++) | ||||
| 	{ | ||||
| 		char const* enum_str     = enum_strs[idx].string; | ||||
| 		char const* entry_to_str = str_strs [idx].string; | ||||
|  | ||||
| 		enum_entries.append_fmt( "%s,\n", enum_str ); | ||||
| 		to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 		append_fmt( enum_entries, "%s,\n", enum_str ); | ||||
| 		append_fmt( to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 	} | ||||
|  | ||||
| 	CodeEnum  enum_code = parse_enum(token_fmt("entries", (StrC)enum_entries, stringize( | ||||
| @@ -218,14 +218,16 @@ CodeBody gen_especifier( char const* path ) | ||||
| CodeBody gen_etoktype( char const* etok_path, char const* attr_path ) | ||||
| { | ||||
| 	char  scratch_mem[kilobytes(16)]; | ||||
| 	Arena scratch = Arena::init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||
| 	Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) ); | ||||
|  | ||||
| 	FileContents enum_content = file_read_contents( scratch, zero_terminate, etok_path ); | ||||
| 	AllocatorInfo scratch_info = allocator_info(scratch); | ||||
|  | ||||
| 	FileContents enum_content = file_read_contents( scratch_info, zero_terminate, etok_path ); | ||||
|  | ||||
| 	CSV_Object csv_enum_nodes; | ||||
| 	csv_parse( &csv_enum_nodes, rcast(char*, enum_content.data), GlobalAllocator, false ); | ||||
|  | ||||
| 	FileContents attrib_content = file_read_contents( scratch, zero_terminate, attr_path ); | ||||
| 	FileContents attrib_content = file_read_contents( scratch_info, zero_terminate, attr_path ); | ||||
|  | ||||
| 	CSV_Object csv_attr_nodes; | ||||
| 	csv_parse( &csv_attr_nodes, rcast(char*, attrib_content.data), GlobalAllocator, false ); | ||||
| @@ -235,34 +237,34 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path ) | ||||
| 	Array<ADT_Node> attribute_strs     = csv_attr_nodes.nodes[0].nodes; | ||||
| 	Array<ADT_Node> attribute_str_strs = csv_attr_nodes.nodes[1].nodes; | ||||
|  | ||||
| 	String enum_entries             = String::make_reserve( GlobalAllocator, kilobytes(2) ); | ||||
| 	String to_str_entries           = String::make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
| 	String attribute_entries        = String::make_reserve( GlobalAllocator, kilobytes(2) ); | ||||
| 	String to_str_attributes        = String::make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
| 	String attribute_define_entries = String::make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
| 	String enum_entries             = string_make_reserve( GlobalAllocator, kilobytes(2) ); | ||||
| 	String to_str_entries           = string_make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
| 	String attribute_entries        = string_make_reserve( GlobalAllocator, kilobytes(2) ); | ||||
| 	String to_str_attributes        = string_make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
| 	String attribute_define_entries = string_make_reserve( GlobalAllocator, kilobytes(4) ); | ||||
|  | ||||
| 	for (usize idx = 0; idx < enum_strs.num(); idx++) | ||||
| 	for (usize idx = 0; idx < num(enum_strs); idx++) | ||||
| 	{ | ||||
| 		char const* enum_str     = enum_strs[idx].string; | ||||
| 		char const* entry_to_str = enum_str_strs [idx].string; | ||||
|  | ||||
| 		enum_entries.append_fmt( "%s,\n", enum_str ); | ||||
| 		to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 		append_fmt( enum_entries, "%s,\n", enum_str ); | ||||
| 		append_fmt( to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 	} | ||||
|  | ||||
| 	for ( usize idx = 0; idx < attribute_strs.num(); idx++ ) | ||||
| 	for ( usize idx = 0; idx < num(attribute_strs); idx++ ) | ||||
| 	{ | ||||
| 		char const* attribute_str = attribute_strs[idx].string; | ||||
| 		char const* entry_to_str  = attribute_str_strs [idx].string; | ||||
|  | ||||
| 		attribute_entries.append_fmt( "Attribute_%s,\n", attribute_str ); | ||||
| 		to_str_attributes.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 		attribute_define_entries.append_fmt( "Entry( Attribute_%s, \"%s\" )", attribute_str, entry_to_str ); | ||||
| 		append_fmt( attribute_entries, "Attribute_%s,\n", attribute_str ); | ||||
| 		append_fmt( to_str_attributes, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); | ||||
| 		append_fmt( attribute_define_entries, "Entry( Attribute_%s, \"%s\" )", attribute_str, entry_to_str ); | ||||
|  | ||||
| 		if ( idx < attribute_strs.num() - 1 ) | ||||
| 			attribute_define_entries.append( " \\\n"); | ||||
| 		if ( idx < num(attribute_strs) - 1 ) | ||||
| 			append( attribute_define_entries, " \\\n"); | ||||
| 		else | ||||
| 			attribute_define_entries.append( "\n"); | ||||
| 			append( attribute_define_entries, "\n"); | ||||
| 	} | ||||
|  | ||||
| #pragma push_macro("GEN_DEFINE_ATTRIBUTE_TOKENS") | ||||
| @@ -366,6 +368,15 @@ CodeBody gen_ast_inlines() | ||||
| 			return { rcast(AST*, ast)->duplicate() }; | ||||
| 		} | ||||
| 		inline | ||||
| 		bool <typename>::is_body() | ||||
| 		{ | ||||
| 			if ( ast == nullptr ) | ||||
| 			{ | ||||
| 				return rcast(AST*, ast)->is_body(); | ||||
| 			} | ||||
| 			return false; | ||||
| 		} | ||||
| 		inline | ||||
| 		bool <typename>::is_equal( Code other ) | ||||
| 		{ | ||||
| 			if ( ast == nullptr || other.ast == nullptr ) | ||||
|   | ||||
							
								
								
									
										10
									
								
								project/helpers/member_proc_support.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								project/helpers/member_proc_support.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "gen.hpp" | ||||
|  | ||||
| GEN_NS_BEGIN | ||||
| #include "dependencies/parsing.hpp" | ||||
| GEN_NS_END | ||||
|  | ||||
| using namespace gen; | ||||
|  | ||||
| @@ -44,6 +44,7 @@ Push-Location $path_root | ||||
| 	   $verbose      = $false | ||||
| [bool] $bootstrap    = $false | ||||
| [bool] $singleheader = $false | ||||
| [bool] $c_library    = $false | ||||
| [bool] $unreal       = $false | ||||
| [bool] $test         = $false | ||||
|  | ||||
| @@ -59,6 +60,7 @@ if ( $args ) { $args | ForEach-Object { | ||||
| 		"debug"               { $release      = $false } | ||||
| 		"bootstrap"           { $bootstrap    = $true } | ||||
| 		"singleheader"        { $singleheader = $true } | ||||
| 		"c_library"           { $c_library    = $true } | ||||
| 		"unreal"              { $unreal       = $true } | ||||
| 		"test"                { $test         = $true } | ||||
| 	} | ||||
| @@ -88,7 +90,7 @@ else { | ||||
| 	$optimize = $true | ||||
| } | ||||
|  | ||||
| if ( $bootstrap -eq $false -and $singleheader -eq $false -and $unreal -eq $false -and $test -eq $false ) { | ||||
| if ( $bootstrap -eq $false -and $singleheader -eq $false -and $c_library -eq $false -and $unreal -eq $false -and $test -eq $false ) { | ||||
| 	throw "No build target specified. One must be specified, this script will not assume one" | ||||
| } | ||||
|  | ||||
| @@ -103,8 +105,9 @@ write-host "Build Type: $(if ($release) {"Release"} else {"Debug"} )" | ||||
| $path_build        = Join-Path $path_root build | ||||
| $path_project      = Join-Path $path_root project | ||||
| $path_scripts      = Join-Path $path_root scripts | ||||
| $path_singleheader = Join-Path $path_root singleheader | ||||
| $path_unreal       = Join-Path $path_root unreal_engine | ||||
| $path_c_library    = join-Path $path_root gen_c_library | ||||
| $path_singleheader = Join-Path $path_root gen_singleheader | ||||
| $path_unreal       = Join-Path $path_root gen_unreal_engine | ||||
| $path_test         = Join-Path $path_root test | ||||
|  | ||||
| if ( $bootstrap ) | ||||
| @@ -187,6 +190,44 @@ if ( $singleheader ) | ||||
| 	Pop-Location | ||||
| } | ||||
|  | ||||
| if ( $c_library ) | ||||
| { | ||||
| 	$path_build = join-path $path_c_library build | ||||
| 	$path_gen   = join-path $path_c_library gen | ||||
|  | ||||
| 	if ( -not(Test-Path($path_build) )) { | ||||
| 		New-Item -ItemType Directory -Path $path_build | ||||
| 	} | ||||
| 	if ( -not(Test-Path($path_gen) )) { | ||||
| 		New-Item -ItemType Directory -Path $path_gen | ||||
| 	} | ||||
|  | ||||
| 	$includes    = @( $path_project ) | ||||
| 	$unit       = join-path $path_c_library "c_library.cpp" | ||||
| 	$executable = join-path $path_build     "c_library.exe" | ||||
|  | ||||
| 	$compiler_args = @() | ||||
| 	$compiler_args += ( $flag_define + 'GEN_TIME' ) | ||||
|  | ||||
| 	$linker_args   = @( | ||||
| 		$flag_link_win_subsystem_console | ||||
| 	) | ||||
|  | ||||
| 	build-simple $path_build $includes $compiler_args $linker_args $unit $executable | ||||
|  | ||||
| 	Push-Location $path_c_library | ||||
| 		if ( Test-Path( $executable ) ) { | ||||
| 			write-host "`nRunning c_library generator" | ||||
| 			$time_taken = Measure-Command { & $executable | ||||
| 					| ForEach-Object { | ||||
| 						write-host `t $_ -ForegroundColor Green | ||||
| 					} | ||||
| 				} | ||||
| 			write-host "`nc_library generator completed in $($time_taken.TotalMilliseconds) ms" | ||||
| 		} | ||||
| 	Pop-Location | ||||
| } | ||||
|  | ||||
| if ( $unreal ) | ||||
| { | ||||
| 	$path_build = join-path $path_unreal build | ||||
|   | ||||
							
								
								
									
										24
									
								
								scripts/c_library.refactor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								scripts/c_library.refactor
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
|  __VERSION 1 | ||||
|  | ||||
| // This is a example template to be used with the refactor program | ||||
| // Use it to refactor the naming convention of this library to your own. | ||||
| // Can be used as an aid to help use use your project's implementation if it fullfills the dependencies of this project. | ||||
| // Example: Most likely have a memory and string library already, just rename the functions and make sure the args are the same. | ||||
| // Program: https://github.com/Ed94/refactor | ||||
|  | ||||
| // NOTE: Due to the current limitations of the program, not every symbol in the library can be renamed. | ||||
| // This is due to the program not actually parsing C/C++. | ||||
|  | ||||
| // not       : Ignore | ||||
| // include   : #includes | ||||
| // word      : Alphanumeric or underscore | ||||
| // namespace : Prefix search and replace (c-namspaces). | ||||
| // regex     : Unavailable in __VERSION 1. | ||||
|  | ||||
| // Precedence (highest to lowest): | ||||
| // word, namespace, regex | ||||
|  | ||||
| // Gen Macro namespace | ||||
| // namespace GEN_, new_namespace_ | ||||
|  | ||||
| // TODO(Ed): This will be large as nearly all symbols will need to optionally support getting prefixed with gen_ or something else the user wants. | ||||
							
								
								
									
										0
									
								
								scripts/refactor_c_library.ps1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								scripts/refactor_c_library.ps1
									
									
									
									
									
										Normal file
									
								
							
		Reference in New Issue
	
	Block a user