mirror of
				https://github.com/Ed94/gencpp.git
				synced 2025-11-03 15:26:12 -08:00 
			
		
		
		
	Compare commits
	
		
			39 Commits
		
	
	
		
			v0.19-Alph
			...
			16b8a3a164
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 16b8a3a164 | |||
| 5b0079fb0c | |||
| 9321a04ebc | |||
| 9b68791e38 | |||
| 2dcc968c39 | |||
| c38b077c37 | |||
| f9b5029e64 | |||
| 2b24511f7d | |||
| 5cd69e1742 | |||
| 007bfa0cb0 | |||
| 37c33ffb3e | |||
| 937235b776 | |||
| f9c21ebc04 | |||
| fec709cc76 | |||
| 80cb3f4eca | |||
| 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,
 | 
			
		||||
 
 | 
			
		||||
@@ -552,7 +552,7 @@ Serialization:
 | 
			
		||||
Fields:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
SpecifierT     ArrSpecs[ AST::ArrSpecs_Cap ];
 | 
			
		||||
SpecifierT     ArrSpecs[ AST_ArrSpecs_Cap ];
 | 
			
		||||
CodeSpecifiers NextSpecs;
 | 
			
		||||
Code           Prev;
 | 
			
		||||
Code           Next;
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,8 @@ This library was written in a subset of C++ where the following are not used at
 | 
			
		||||
* Exceptions
 | 
			
		||||
 | 
			
		||||
Polymorphic & Member-functions are used as an ergonomic choice, along with a conserative use of operator overloads.  
 | 
			
		||||
The base library itself does not use anything but C-like features to allow for generating a derviative compatiable with C (WIP).
 | 
			
		||||
 | 
			
		||||
There are only 4 template definitions in the entire library. (`Array<Type>`, `Hashtable<Type>`, `swap<Type>`, and `AST/Code::cast<Type>`)
 | 
			
		||||
 | 
			
		||||
Two generic templated containers are used throughout the library:
 | 
			
		||||
@@ -99,7 +101,7 @@ union {
 | 
			
		||||
    };
 | 
			
		||||
    StringCached  Content;          // Attributes, Comment, Execution, Include
 | 
			
		||||
    struct {
 | 
			
		||||
        SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers
 | 
			
		||||
        SpecifierT ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers
 | 
			
		||||
        AST*       NextSpecs;                   // Specifiers
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										398
									
								
								gen_c_library/c_library.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										398
									
								
								gen_c_library/c_library.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,398 @@
 | 
			
		||||
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
 | 
			
		||||
#define GEN_ENFORCE_STRONG_CODE_TYPES
 | 
			
		||||
#define GEN_EXPOSE_BACKEND
 | 
			
		||||
#define GEN_SUPPORT_CPP_MEMBER_FEATURES 1
 | 
			
		||||
#define GEN_SUPPORT_CPP_REFERENCES      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   = cast(CodeUsing, entry);
 | 
			
		||||
					CodeTypedef typedef_ver = def_typedef(using_ver->Name, using_ver->UnderlyingType);
 | 
			
		||||
 | 
			
		||||
					memory.append(typedef_ver);
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
				case ECode::Function_Fwd:
 | 
			
		||||
				{
 | 
			
		||||
					CodeFn fn = cast(CodeFn, entry);
 | 
			
		||||
					if ( fn->Name.is_equal(txt("free")) )
 | 
			
		||||
					{
 | 
			
		||||
						fn->Name = get_cached_string(txt("gen_free_ptr"));
 | 
			
		||||
					}
 | 
			
		||||
					memory.append(entry);
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
				case ECode::Function:
 | 
			
		||||
				{
 | 
			
		||||
					CodeFn fn = cast(CodeFn, entry);
 | 
			
		||||
					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);
 | 
			
		||||
					}
 | 
			
		||||
					if ( fn->Name.is_equal(txt("free")) )
 | 
			
		||||
					{
 | 
			
		||||
						fn->Name = get_cached_string(txt("gen_free_ptr"));
 | 
			
		||||
					}
 | 
			
		||||
					memory.append(entry);
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
				case ECode::Template:
 | 
			
		||||
				{
 | 
			
		||||
					CodeTemplate tmpl = cast(CodeTemplate, entry);
 | 
			
		||||
					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 char* String; ));
 | 
			
		||||
						strings.append(c_def);
 | 
			
		||||
						strings.append(fmt_newline);
 | 
			
		||||
						++ entry;
 | 
			
		||||
						continue;
 | 
			
		||||
					}
 | 
			
		||||
					strings.append(entry);
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
				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:
 | 
			
		||||
						{
 | 
			
		||||
							b32 found = ignore_preprocess_cond_block(txt("! GEN_COMPILER_C"), body_entry, body );
 | 
			
		||||
							if (found) break;
 | 
			
		||||
 | 
			
		||||
							new_body.append(body_entry);
 | 
			
		||||
						}
 | 
			
		||||
						break;
 | 
			
		||||
						default:
 | 
			
		||||
							new_body.append(body_entry);
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
					entry->Body = rcast(AST*, new_body.ast);
 | 
			
		||||
					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();
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
		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");
 | 
			
		||||
	#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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 = cast(CodePreprocessCond, entry_iter);
 | 
			
		||||
	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 = cast(CodePragma, entry_iter);
 | 
			
		||||
 | 
			
		||||
	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 = cast(CodePragma, entry_iter);
 | 
			
		||||
				if ( possible_end_region->Content.contains(endregion_sig) ) {
 | 
			
		||||
					// body.append(possible_end_region);
 | 
			
		||||
					continue_for = false;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		body.append(entry_iter);
 | 
			
		||||
	}
 | 
			
		||||
	return found;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								gen_c_library/gen.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								gen_c_library/gen.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
#define GEN_IMPLEMENTATION
 | 
			
		||||
#include "gen/gen.h"
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
	// init();
 | 
			
		||||
}
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
 | 
			
		||||
#define GEN_ENFORCE_STRONG_CODE_TYPES
 | 
			
		||||
#define GEN_EXPOSE_BACKEND
 | 
			
		||||
#define GEN_SUPPORT_CPP_MEMBER_FEATURES 1
 | 
			
		||||
#define GEN_SUPPORT_CPP_REFERENCES      0
 | 
			
		||||
#include "gen.cpp"
 | 
			
		||||
 | 
			
		||||
#include "helpers/push_ignores.inline.hpp"
 | 
			
		||||
@@ -30,6 +30,13 @@ Feature Macros:
 | 
			
		||||
* `GEN_ROLL_OWN_DEPENDENCIES` : Optional override so that user may define the dependencies themselves.
 | 
			
		||||
* `GEN_DONT_ALLOW_INVALID_CODE` (Not implemented yet) : Will fail when an invalid code is constructed, parsed, or serialized.
 | 
			
		||||
 | 
			
		||||
By default the base library implementation strictly uses a C-like interface. This is to allow for the generation of a C-variant of the library using [gen_c_library](../gen_c_library/). However, the library was written in C++ and supports some of its features:
 | 
			
		||||
 | 
			
		||||
* `GEN_SUPPORT_CPP_REFERENCES` : Will enable support for reference interface on some definitions
 | 
			
		||||
* `GEN_SUPPORT_CPP_MEMBER_FEATURES` : Will enable support for definitions to have their interface as members.
 | 
			
		||||
 | 
			
		||||
*Note: A variant of the C++ library could be generated where those additonal support features are removed (see gen_c_library implementation for an idea of how)*
 | 
			
		||||
 | 
			
		||||
## On multi-threading
 | 
			
		||||
 | 
			
		||||
Currently unsupported. I want the library to be *stable* and *correct*, with the addition of exhausting all basic single-threaded optimizations before I consider multi-threading.
 | 
			
		||||
 
 | 
			
		||||
@@ -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,15 +21,15 @@ Builder Builder::open( char const* path )
 | 
			
		||||
 | 
			
		||||
void Builder::pad_lines( s32 num )
 | 
			
		||||
{
 | 
			
		||||
	Buffer.append( "\n" );
 | 
			
		||||
	append( & Buffer,  "\n" );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Builder::print( Code code )
 | 
			
		||||
{
 | 
			
		||||
	String   str = code->to_string();
 | 
			
		||||
	String   str = to_string(code);
 | 
			
		||||
	// 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,8 @@
 | 
			
		||||
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
 | 
			
		||||
#define GEN_ENFORCE_STRONG_CODE_TYPES
 | 
			
		||||
#define GEN_EXPOSE_BACKEND
 | 
			
		||||
#define GEN_SUPPORT_CPP_MEMBER_FEATURES 0
 | 
			
		||||
#define GEN_SUPPORT_CPP_REFERENCES      0
 | 
			
		||||
#include "gen.cpp"
 | 
			
		||||
 | 
			
		||||
#include "helpers/push_ignores.inline.hpp"
 | 
			
		||||
@@ -24,20 +26,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");
 | 
			
		||||
@@ -62,6 +64,8 @@ int gen_main()
 | 
			
		||||
{
 | 
			
		||||
	gen::init();
 | 
			
		||||
 | 
			
		||||
	// PreprocessorDefines.append("GEN_NS");
 | 
			
		||||
 | 
			
		||||
	Code push_ignores = scan_file( "helpers/push_ignores.inline.hpp" );
 | 
			
		||||
	Code pop_ignores  = scan_file( "helpers/pop_ignores.inline.hpp" );
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -73,79 +73,103 @@ struct AST_Union;
 | 
			
		||||
struct AST_Using;
 | 
			
		||||
struct AST_Var;
 | 
			
		||||
 | 
			
		||||
struct Code;
 | 
			
		||||
struct CodeBody;
 | 
			
		||||
// These are to offer ease of use and optionally strong type safety for the AST.
 | 
			
		||||
struct CodeAttributes;
 | 
			
		||||
// struct CodeBaseClass;
 | 
			
		||||
struct CodeComment;
 | 
			
		||||
struct CodeClass;
 | 
			
		||||
struct CodeConstructor;
 | 
			
		||||
struct CodeDefine;
 | 
			
		||||
struct CodeDestructor;
 | 
			
		||||
struct CodeEnum;
 | 
			
		||||
struct CodeExec;
 | 
			
		||||
struct CodeExtern;
 | 
			
		||||
struct CodeInclude;
 | 
			
		||||
struct CodeFriend;
 | 
			
		||||
struct CodeFn;
 | 
			
		||||
struct CodeModule;
 | 
			
		||||
struct CodeNS;
 | 
			
		||||
struct CodeOperator;
 | 
			
		||||
struct CodeOpCast;
 | 
			
		||||
struct CodeParam;
 | 
			
		||||
struct CodePreprocessCond;
 | 
			
		||||
struct CodePragma;
 | 
			
		||||
struct CodeSpecifiers;
 | 
			
		||||
 | 
			
		||||
#if GEN_EXECUTION_EXPRESSION_SUPPORT
 | 
			
		||||
struct CodeExpr;
 | 
			
		||||
struct CodeExpr_Assign;
 | 
			
		||||
struct CodeExpr_Alignof;
 | 
			
		||||
struct CodeExpr_Binary;
 | 
			
		||||
struct CodeExpr_CStyleCast;
 | 
			
		||||
struct CodeExpr_FunctionalCast;
 | 
			
		||||
struct CodeExpr_CppCast;
 | 
			
		||||
struct CodeExpr_Element;
 | 
			
		||||
struct CodeExpr_ProcCall;
 | 
			
		||||
struct CodeExpr_Decltype;
 | 
			
		||||
struct CodeExpr_Comma;
 | 
			
		||||
struct CodeExpr_AMS; // Access Member Symbol
 | 
			
		||||
struct CodeExpr_Sizeof;
 | 
			
		||||
struct CodeExpr_Subscript;
 | 
			
		||||
struct CodeExpr_Ternary;
 | 
			
		||||
struct CodeExpr_UnaryPrefix;
 | 
			
		||||
struct CodeExpr_UnaryPostfix;
 | 
			
		||||
 | 
			
		||||
struct CodeStmt;
 | 
			
		||||
struct CodeStmt_Break;
 | 
			
		||||
struct CodeStmt_Case;
 | 
			
		||||
struct CodeStmt_Continue;
 | 
			
		||||
struct CodeStmt_Decl;
 | 
			
		||||
struct CodeStmt_Do;
 | 
			
		||||
struct CodeStmt_Expr;
 | 
			
		||||
struct CodeStmt_Else;
 | 
			
		||||
struct CodeStmt_If;
 | 
			
		||||
struct CodeStmt_For;
 | 
			
		||||
struct CodeStmt_Goto;
 | 
			
		||||
struct CodeStmt_Label;
 | 
			
		||||
struct CodeStmt_Switch;
 | 
			
		||||
struct CodeStmt_While;
 | 
			
		||||
#if GEN_COMPILER_C
 | 
			
		||||
#define Define_Code(Type) typedef AST_##Type* Code##Type
 | 
			
		||||
#else
 | 
			
		||||
#define Define_Code(Type) struct Code##Type
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct CodeStruct;
 | 
			
		||||
struct CodeTemplate;
 | 
			
		||||
struct CodeType;
 | 
			
		||||
struct CodeTypedef;
 | 
			
		||||
struct CodeUnion;
 | 
			
		||||
struct CodeUsing;
 | 
			
		||||
struct CodeVar;
 | 
			
		||||
#if GEN_COMPILER_C
 | 
			
		||||
typedef AST* code;
 | 
			
		||||
#else
 | 
			
		||||
struct Code;
 | 
			
		||||
#endif
 | 
			
		||||
Define_Code(Body);
 | 
			
		||||
// These are to offer ease of use and optionally strong type safety for the AST.
 | 
			
		||||
Define_Code(Attributes);
 | 
			
		||||
// struct CodeBaseClass;
 | 
			
		||||
Define_Code(Comment);
 | 
			
		||||
Define_Code(Class);
 | 
			
		||||
Define_Code(Constructor);
 | 
			
		||||
Define_Code(Define);
 | 
			
		||||
Define_Code(Destructor);
 | 
			
		||||
Define_Code(Enum);
 | 
			
		||||
Define_Code(Exec);
 | 
			
		||||
Define_Code(Extern);
 | 
			
		||||
Define_Code(Include);
 | 
			
		||||
Define_Code(Friend);
 | 
			
		||||
Define_Code(Fn);
 | 
			
		||||
Define_Code(Module);
 | 
			
		||||
Define_Code(NS);
 | 
			
		||||
Define_Code(Operator);
 | 
			
		||||
Define_Code(OpCast);
 | 
			
		||||
Define_Code(Param);
 | 
			
		||||
Define_Code(PreprocessCond);
 | 
			
		||||
Define_Code(Pragma);
 | 
			
		||||
Define_Code(Specifiers);
 | 
			
		||||
 | 
			
		||||
#if GEN_EXECUTION_EXPRESSION_SUPPORT
 | 
			
		||||
Define_Code(Expr);
 | 
			
		||||
Define_Code(Expr_Assign);
 | 
			
		||||
Define_Code(Expr_Alignof);
 | 
			
		||||
Define_Code(Expr_Binary);
 | 
			
		||||
Define_Code(Expr_CStyleCast);
 | 
			
		||||
Define_Code(Expr_FunctionalCast);
 | 
			
		||||
Define_Code(Expr_CppCast);
 | 
			
		||||
Define_Code(Expr_Element);
 | 
			
		||||
Define_Code(Expr_ProcCall);
 | 
			
		||||
Define_Code(Expr_Decltype);
 | 
			
		||||
Define_Code(Expr_Comma);
 | 
			
		||||
Define_Code(Expr_AMS); // Access Member Symbol
 | 
			
		||||
Define_Code(Expr_Sizeof);
 | 
			
		||||
Define_Code(Expr_Subscript);
 | 
			
		||||
Define_Code(Expr_Ternary);
 | 
			
		||||
Define_Code(Expr_UnaryPrefix);
 | 
			
		||||
Define_Code(Expr_UnaryPostfix);
 | 
			
		||||
 | 
			
		||||
Define_Code(Stmt);
 | 
			
		||||
Define_Code(Stmt_Break);
 | 
			
		||||
Define_Code(Stmt_Case);
 | 
			
		||||
Define_Code(Stmt_Continue);
 | 
			
		||||
Define_Code(Stmt_Decl);
 | 
			
		||||
Define_Code(Stmt_Do);
 | 
			
		||||
Define_Code(Stmt_Expr);
 | 
			
		||||
Define_Code(Stmt_Else);
 | 
			
		||||
Define_Code(Stmt_If);
 | 
			
		||||
Define_Code(Stmt_For);
 | 
			
		||||
Define_Code(Stmt_Goto);
 | 
			
		||||
Define_Code(Stmt_Label);
 | 
			
		||||
Define_Code(Stmt_Switch);
 | 
			
		||||
Define_Code(Stmt_While);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
Define_Code(Struct);
 | 
			
		||||
Define_Code(Template);
 | 
			
		||||
Define_Code(Type);
 | 
			
		||||
Define_Code(Typedef);
 | 
			
		||||
Define_Code(Union);
 | 
			
		||||
Define_Code(Using);
 | 
			
		||||
Define_Code(Var);
 | 
			
		||||
#undef Define_Code
 | 
			
		||||
 | 
			
		||||
namespace parser
 | 
			
		||||
{
 | 
			
		||||
	struct Token;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if ! GEN_COMPILER_C
 | 
			
		||||
template< class Type> forceinline Type tmpl_cast( Code self ) { return * rcast( Type*, & self ); }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
char const* debug_str (Code code);
 | 
			
		||||
Code        duplicate (Code code);
 | 
			
		||||
bool        is_equal  (Code code, Code other);
 | 
			
		||||
bool        is_body   (Code code);
 | 
			
		||||
bool        is_valid  (Code code);
 | 
			
		||||
void        set_global(Code code);
 | 
			
		||||
String      to_string (Code code);
 | 
			
		||||
 | 
			
		||||
#if ! GEN_COMPILER_C
 | 
			
		||||
/*
 | 
			
		||||
	AST* wrapper
 | 
			
		||||
	- Not constantly have to append the '*' as this is written often..
 | 
			
		||||
@@ -153,39 +177,31 @@ namespace parser
 | 
			
		||||
*/
 | 
			
		||||
struct Code
 | 
			
		||||
{
 | 
			
		||||
#	pragma region Statics
 | 
			
		||||
	// Used to identify ASTs that should always be duplicated. (Global constant ASTs)
 | 
			
		||||
	static Code Global;
 | 
			
		||||
	AST* ast;
 | 
			
		||||
 | 
			
		||||
	// Used to identify invalid generated code.
 | 
			
		||||
	static Code Invalid;
 | 
			
		||||
#	pragma endregion Statics
 | 
			
		||||
#	define Using_Code( Typename )                                                     \
 | 
			
		||||
	char const* debug_str()                { return GEN_NS debug_str(* this); }       \
 | 
			
		||||
	Code        duplicate()                { return GEN_NS duplicate(* this); }	      \
 | 
			
		||||
	bool        is_equal( Code other )     { return GEN_NS is_equal(* this, other); } \
 | 
			
		||||
	bool        is_body()                  { return GEN_NS is_body(* this); }         \
 | 
			
		||||
	bool        is_valid()                 { return GEN_NS is_valid(* this); }        \
 | 
			
		||||
	void        set_global()               { return GEN_NS set_global(* this); }
 | 
			
		||||
 | 
			
		||||
#	define Using_Code( Typename )          \
 | 
			
		||||
	char const* debug_str();               \
 | 
			
		||||
	Code        duplicate();			   \
 | 
			
		||||
	bool        is_equal( Code other );    \
 | 
			
		||||
	bool        is_valid();                \
 | 
			
		||||
	void        set_global();              \
 | 
			
		||||
	String      to_string();               \
 | 
			
		||||
	Typename&   operator = ( AST* other ); \
 | 
			
		||||
	Typename&   operator = ( Code other ); \
 | 
			
		||||
	bool        operator ==( Code other ); \
 | 
			
		||||
	bool        operator !=( Code other ); \
 | 
			
		||||
#	define Using_CodeOps( Typename )                                         \
 | 
			
		||||
	Typename&   operator = ( AST* other );                                   \
 | 
			
		||||
	Typename&   operator = ( Code other );                                   \
 | 
			
		||||
	bool        operator ==( Code other ) { return (AST*)ast == other.ast; } \
 | 
			
		||||
	bool        operator !=( Code other ) { return (AST*)ast != other.ast; } \
 | 
			
		||||
	operator bool();
 | 
			
		||||
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES
 | 
			
		||||
	Using_Code( Code );
 | 
			
		||||
	String to_string() { return GEN_NS to_string(* this); }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	template< class Type >
 | 
			
		||||
	forceinline Type cast()
 | 
			
		||||
	{
 | 
			
		||||
		return * rcast( Type*, this );
 | 
			
		||||
	}
 | 
			
		||||
	Using_CodeOps( Code );
 | 
			
		||||
 | 
			
		||||
	AST* operator ->()
 | 
			
		||||
	{
 | 
			
		||||
		return ast;
 | 
			
		||||
	}
 | 
			
		||||
	AST* operator ->() { return ast; }
 | 
			
		||||
	Code& operator ++();
 | 
			
		||||
 | 
			
		||||
	// TODO(Ed) : Remove this overload.
 | 
			
		||||
@@ -200,8 +216,6 @@ struct Code
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	AST* ast;
 | 
			
		||||
 | 
			
		||||
#ifdef GEN_ENFORCE_STRONG_CODE_TYPES
 | 
			
		||||
#	define operator explicit operator
 | 
			
		||||
#endif
 | 
			
		||||
@@ -236,6 +250,15 @@ struct Code
 | 
			
		||||
	operator CodeVar() const;
 | 
			
		||||
	#undef operator
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#pragma region Statics
 | 
			
		||||
// Used to identify ASTs that should always be duplicated. (Global constant ASTs)
 | 
			
		||||
extern Code Code_Global;
 | 
			
		||||
 | 
			
		||||
// Used to identify invalid generated code.
 | 
			
		||||
extern Code Code_Invalid;
 | 
			
		||||
#pragma endregion Statics
 | 
			
		||||
 | 
			
		||||
struct Code_POD
 | 
			
		||||
{
 | 
			
		||||
@@ -247,31 +270,63 @@ static_assert( sizeof(Code) == sizeof(Code_POD), "ERROR: Code is not POD" );
 | 
			
		||||
// Desired width of the AST data structure.
 | 
			
		||||
constexpr int const AST_POD_Size = 128;
 | 
			
		||||
 | 
			
		||||
void        append       ( AST* self, AST* other );
 | 
			
		||||
char const* debug_str    ( AST* self );
 | 
			
		||||
AST*        duplicate    ( AST* self );
 | 
			
		||||
Code*       entry        ( AST* self, u32 idx );
 | 
			
		||||
bool        has_entries  ( AST* self );
 | 
			
		||||
bool        is_body      ( AST* self );
 | 
			
		||||
bool        is_equal     ( AST* self, AST* other );
 | 
			
		||||
String      to_string    ( AST* self );
 | 
			
		||||
void        to_string    ( AST* self, String* result );
 | 
			
		||||
char const* type_str     ( AST* self );
 | 
			
		||||
bool        validate_body( AST* self );
 | 
			
		||||
 | 
			
		||||
#if GEN_CPP_SUPPORT_REFERENCES
 | 
			
		||||
void        append   ( AST& self, AST& other ) { return append(& self, & other); }
 | 
			
		||||
bool        is_body  ( AST& self )             { return is_body(& self); }
 | 
			
		||||
bool        is_equal ( AST& self, AST& other ) { return is_equal(& self, & other); }
 | 
			
		||||
char const* debug_str( AST& self )             { return debug_str( & self ); }
 | 
			
		||||
String      to_string( AST& self )             { return to_string( & self ); }
 | 
			
		||||
char const* type_str ( AST& self )             { return type_str( & self ); }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
constexpr static
 | 
			
		||||
int AST_ArrSpecs_Cap =
 | 
			
		||||
(
 | 
			
		||||
		AST_POD_Size
 | 
			
		||||
		- sizeof(AST*) * 3
 | 
			
		||||
		- sizeof(parser::Token*)
 | 
			
		||||
		- sizeof(AST*)
 | 
			
		||||
		- sizeof(StringCached)
 | 
			
		||||
		- sizeof(CodeT)
 | 
			
		||||
		- sizeof(ModuleFlag)
 | 
			
		||||
		- sizeof(int)
 | 
			
		||||
)
 | 
			
		||||
/ sizeof(int) - 1; // -1 for 4 extra bytes
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Simple AST POD with functionality to seralize into C++ syntax.
 | 
			
		||||
*/
 | 
			
		||||
struct AST
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES
 | 
			
		||||
#	pragma region Member Functions
 | 
			
		||||
	void        append     ( AST* other );
 | 
			
		||||
	char const* debug_str  ();
 | 
			
		||||
	AST*        duplicate  ();
 | 
			
		||||
	Code&       entry      ( u32 idx );
 | 
			
		||||
	bool        has_entries();
 | 
			
		||||
	bool        is_equal   ( AST* other );
 | 
			
		||||
	char const* type_str();
 | 
			
		||||
	bool        validate_body();
 | 
			
		||||
	void        append     ( AST* other )  { GEN_NS append(this, other); }
 | 
			
		||||
	char const* debug_str  ()              { return GEN_NS debug_str(this); }
 | 
			
		||||
	AST*        duplicate  ()              { return GEN_NS duplicate(this); }
 | 
			
		||||
	Code*       entry      ( u32 idx )     { return GEN_NS entry(this, idx); }
 | 
			
		||||
	bool        has_entries()              { return GEN_NS has_entries(this); }
 | 
			
		||||
	bool        is_equal   ( AST* other )  { return GEN_NS is_equal(this, other); }
 | 
			
		||||
	bool        is_body()                  { return GEN_NS is_body(this); }
 | 
			
		||||
	char const* type_str()                 { return GEN_NS type_str(this); }
 | 
			
		||||
	bool        validate_body()            { return GEN_NS validate_body(this); }
 | 
			
		||||
 | 
			
		||||
	String to_string();
 | 
			
		||||
	String to_string()                 { return GEN_NS to_string(this); }
 | 
			
		||||
	void   to_string( String& result ) { return GEN_NS to_string(this, & result); }
 | 
			
		||||
 | 
			
		||||
	neverinline
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	template< class Type >
 | 
			
		||||
	forceinline Type cast()
 | 
			
		||||
	{
 | 
			
		||||
		return * this;
 | 
			
		||||
	}
 | 
			
		||||
#	pragma endregion Member Functions
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	operator Code();
 | 
			
		||||
	operator CodeBody();
 | 
			
		||||
@@ -303,21 +358,6 @@ struct AST
 | 
			
		||||
	operator CodeUnion();
 | 
			
		||||
	operator CodeUsing();
 | 
			
		||||
	operator CodeVar();
 | 
			
		||||
#	pragma endregion Member Functions
 | 
			
		||||
 | 
			
		||||
	constexpr static
 | 
			
		||||
	int ArrSpecs_Cap =
 | 
			
		||||
	(
 | 
			
		||||
			AST_POD_Size
 | 
			
		||||
			- sizeof(AST*) * 3
 | 
			
		||||
			- sizeof(parser::Token*)
 | 
			
		||||
			- sizeof(AST*)
 | 
			
		||||
			- sizeof(StringCached)
 | 
			
		||||
			- sizeof(CodeT)
 | 
			
		||||
			- sizeof(ModuleFlag)
 | 
			
		||||
			- sizeof(int)
 | 
			
		||||
	)
 | 
			
		||||
	/ sizeof(int) - 1; // -1 for 4 extra bytes
 | 
			
		||||
 | 
			
		||||
	union {
 | 
			
		||||
		struct
 | 
			
		||||
@@ -351,7 +391,7 @@ struct AST
 | 
			
		||||
		};
 | 
			
		||||
		StringCached  Content;          // Attributes, Comment, Execution, Include
 | 
			
		||||
		struct {
 | 
			
		||||
			SpecifierT ArrSpecs[ArrSpecs_Cap]; // Specifiers
 | 
			
		||||
			SpecifierT ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers
 | 
			
		||||
			AST*       NextSpecs;              // Specifiers; If ArrSpecs is full, then NextSpecs is used.
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
@@ -376,7 +416,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
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -414,7 +455,7 @@ struct AST_POD
 | 
			
		||||
		};
 | 
			
		||||
		StringCached  Content;          // Attributes, Comment, Execution, Include
 | 
			
		||||
		struct {
 | 
			
		||||
			SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers
 | 
			
		||||
			SpecifierT ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers
 | 
			
		||||
			AST*       NextSpecs;                   // Specifiers; If ArrSpecs is full, then NextSpecs is used.
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
@@ -443,13 +484,6 @@ struct AST_POD
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct test {
 | 
			
		||||
	SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers
 | 
			
		||||
	AST* NextSpecs;                         // Specifiers; If ArrSpecs is full, then NextSpecs is used.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr int pls = sizeof(test);
 | 
			
		||||
 | 
			
		||||
// Its intended for the AST to have equivalent size to its POD.
 | 
			
		||||
// All extra functionality within the AST namespace should just be syntatic sugar.
 | 
			
		||||
static_assert( sizeof(AST)     == sizeof(AST_POD), "ERROR: AST IS NOT POD" );
 | 
			
		||||
@@ -457,4 +491,4 @@ static_assert( sizeof(AST_POD) == AST_POD_Size,    "ERROR: AST POD is not size o
 | 
			
		||||
 | 
			
		||||
// Used when the its desired when omission is allowed in a definition.
 | 
			
		||||
#define NoCode      { nullptr }
 | 
			
		||||
#define CodeInvalid (* Code::Invalid.ast) // Uses an implicitly overloaded cast from the AST to the desired code type.
 | 
			
		||||
#define InvalidCode (* Code_Invalid.ast) // Uses an implicitly overloaded cast from the AST to the desired code type.
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
 | 
			
		||||
struct AST_Body
 | 
			
		||||
{
 | 
			
		||||
	char              _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	char              _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	Code              Front;
 | 
			
		||||
	Code              Back;
 | 
			
		||||
	parser::Token*    Tok;
 | 
			
		||||
@@ -27,7 +27,7 @@ static_assert( sizeof(AST_Body) == sizeof(AST), "ERROR: AST_Body is not the same
 | 
			
		||||
struct AST_Attributes
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		StringCached  Content;
 | 
			
		||||
	};
 | 
			
		||||
	Code              Prev;
 | 
			
		||||
@@ -44,7 +44,7 @@ static_assert( sizeof(AST_Attributes) == sizeof(AST), "ERROR: AST_Attributes is
 | 
			
		||||
struct AST_BaseClass
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	Code              Prev;
 | 
			
		||||
	Code              Next;
 | 
			
		||||
@@ -60,7 +60,7 @@ static_assert( sizeof(AST_BaseClass) == sizeof(AST), "ERROR: AST_BaseClass is no
 | 
			
		||||
struct AST_Comment
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		StringCached  Content;
 | 
			
		||||
	};
 | 
			
		||||
	Code              Prev;
 | 
			
		||||
@@ -76,7 +76,7 @@ static_assert( sizeof(AST_Comment) == sizeof(AST), "ERROR: AST_Comment is not th
 | 
			
		||||
struct AST_Class
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char                _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char                _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			CodeComment     InlineCmt; // Only supported by forward declarations
 | 
			
		||||
@@ -102,7 +102,7 @@ static_assert( sizeof(AST_Class) == sizeof(AST), "ERROR: AST_Class is not the sa
 | 
			
		||||
struct AST_Constructor
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			CodeComment    InlineCmt; // Only supported by forward declarations
 | 
			
		||||
@@ -127,7 +127,7 @@ static_assert( sizeof(AST_Constructor) == sizeof(AST), "ERROR: AST_Constructor i
 | 
			
		||||
struct AST_Define
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		StringCached  Content;
 | 
			
		||||
	};
 | 
			
		||||
	Code              Prev;
 | 
			
		||||
@@ -143,7 +143,7 @@ static_assert( sizeof(AST_Define) == sizeof(AST), "ERROR: AST_Define is not the
 | 
			
		||||
struct AST_Destructor
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			CodeComment    InlineCmt;
 | 
			
		||||
@@ -167,14 +167,14 @@ static_assert( sizeof(AST_Destructor) == sizeof(AST), "ERROR: AST_Destructor is
 | 
			
		||||
struct AST_Enum
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			CodeComment    InlineCmt;
 | 
			
		||||
			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,14 +186,14 @@ 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");
 | 
			
		||||
 | 
			
		||||
struct AST_Exec
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		StringCached  Content;
 | 
			
		||||
	};
 | 
			
		||||
	Code              Prev;
 | 
			
		||||
@@ -210,7 +210,7 @@ static_assert( sizeof(AST_Exec) == sizeof(AST), "ERROR: AST_Exec is not the same
 | 
			
		||||
struct AST_Expr
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -225,7 +225,7 @@ static_assert( sizeof(AST_Expr) == sizeof(AST), "ERROR: AST_Expr is not the same
 | 
			
		||||
struct AST_Expr_Assign
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -240,7 +240,7 @@ static_assert( sizeof(AST_Expr_Assign) == sizeof(AST), "ERROR: AST_Expr_Assign i
 | 
			
		||||
struct AST_Expr_Alignof
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -255,7 +255,7 @@ static_assert( sizeof(AST_Expr_Alignof) == sizeof(AST), "ERROR: AST_Expr_Alignof
 | 
			
		||||
struct AST_Expr_Binary
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -270,7 +270,7 @@ static_assert( sizeof(AST_Expr_Binary) == sizeof(AST), "ERROR: AST_Expr_Binary i
 | 
			
		||||
struct AST_Expr_CStyleCast
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -285,7 +285,7 @@ static_assert( sizeof(AST_Expr_CStyleCast) == sizeof(AST), "ERROR: AST_Expr_CSty
 | 
			
		||||
struct AST_Expr_FunctionalCast
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -300,7 +300,7 @@ static_assert( sizeof(AST_Expr_FunctionalCast) == sizeof(AST), "ERROR: AST_Expr_
 | 
			
		||||
struct AST_Expr_CppCast
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -315,7 +315,7 @@ static_assert( sizeof(AST_Expr_CppCast) == sizeof(AST), "ERROR: AST_Expr_CppCast
 | 
			
		||||
struct AST_Expr_ProcCall
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -330,7 +330,7 @@ static_assert( sizeof(AST_Expr_ProcCall) == sizeof(AST), "ERROR: AST_Expr_Identi
 | 
			
		||||
struct AST_Expr_Decltype
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -345,7 +345,7 @@ static_assert( sizeof(AST_Expr_Decltype) == sizeof(AST), "ERROR: AST_Expr_Declty
 | 
			
		||||
struct AST_Expr_Comma
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -360,7 +360,7 @@ static_assert( sizeof(AST_Expr_Comma) == sizeof(AST), "ERROR: AST_Expr_Comma is
 | 
			
		||||
struct AST_Expr_AMS
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -375,7 +375,7 @@ static_assert( sizeof(AST_Expr_AMS) == sizeof(AST), "ERROR: AST_Expr_AMS is not
 | 
			
		||||
struct AST_Expr_Sizeof
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -390,7 +390,7 @@ static_assert( sizeof(AST_Expr_Sizeof) == sizeof(AST), "ERROR: AST_Expr_Sizeof i
 | 
			
		||||
struct AST_Expr_Subscript
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -405,7 +405,7 @@ static_assert( sizeof(AST_Expr_Subscript) == sizeof(AST), "ERROR: AST_Expr_Subsc
 | 
			
		||||
struct AST_Expr_Ternary
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -420,7 +420,7 @@ static_assert( sizeof(AST_Expr_Ternary) == sizeof(AST), "ERROR: AST_Expr_Ternary
 | 
			
		||||
struct AST_Expr_UnaryPrefix
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -435,7 +435,7 @@ static_assert( sizeof(AST_Expr_UnaryPrefix) == sizeof(AST), "ERROR: AST_Expr_Una
 | 
			
		||||
struct AST_Expr_UnaryPostfix
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -450,7 +450,7 @@ static_assert( sizeof(AST_Expr_UnaryPostfix) == sizeof(AST), "ERROR: AST_Expr_Un
 | 
			
		||||
struct AST_Expr_Element
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -466,7 +466,7 @@ static_assert( sizeof(AST_Expr_Element) == sizeof(AST), "ERROR: AST_Expr_Element
 | 
			
		||||
struct AST_Extern
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			char      _PAD_PROPERTIES_[ sizeof(AST*) * 5 ];
 | 
			
		||||
@@ -487,7 +487,7 @@ static_assert( sizeof(AST_Extern) == sizeof(AST), "ERROR: AST_Extern is not the
 | 
			
		||||
struct AST_Include
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		StringCached  Content;
 | 
			
		||||
	};
 | 
			
		||||
	Code              Prev;
 | 
			
		||||
@@ -503,7 +503,7 @@ static_assert( sizeof(AST_Include) == sizeof(AST), "ERROR: AST_Include is not th
 | 
			
		||||
struct AST_Friend
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char            _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char            _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			CodeComment InlineCmt;
 | 
			
		||||
@@ -525,7 +525,7 @@ static_assert( sizeof(AST_Friend) == sizeof(AST), "ERROR: AST_Friend is not the
 | 
			
		||||
struct AST_Fn
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			CodeComment     InlineCmt;
 | 
			
		||||
@@ -550,7 +550,7 @@ static_assert( sizeof(AST_Fn) == sizeof(AST), "ERROR: AST_Fn is not the same siz
 | 
			
		||||
 | 
			
		||||
struct AST_Module
 | 
			
		||||
{
 | 
			
		||||
	char              _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	char              _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	Code              Prev;
 | 
			
		||||
	Code              Next;
 | 
			
		||||
	parser::Token*    Tok;
 | 
			
		||||
@@ -565,7 +565,7 @@ static_assert( sizeof(AST_Module) == sizeof(AST), "ERROR: AST_Module is not the
 | 
			
		||||
struct AST_NS
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct {
 | 
			
		||||
			char 	  _PAD_PROPERTIES_[ sizeof(AST*) * 5 ];
 | 
			
		||||
			CodeBody  Body;
 | 
			
		||||
@@ -586,7 +586,7 @@ static_assert( sizeof(AST_NS) == sizeof(AST), "ERROR: AST_NS is not the same siz
 | 
			
		||||
struct AST_Operator
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char                _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char                _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			CodeComment     InlineCmt;
 | 
			
		||||
@@ -612,7 +612,7 @@ static_assert( sizeof(AST_Operator) == sizeof(AST), "ERROR: AST_Operator is not
 | 
			
		||||
struct AST_OpCast
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			CodeComment    InlineCmt;
 | 
			
		||||
@@ -637,7 +637,7 @@ static_assert( sizeof(AST_OpCast) == sizeof(AST), "ERROR: AST_OpCast is not the
 | 
			
		||||
struct AST_Param
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			char 	  _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ];
 | 
			
		||||
@@ -662,7 +662,7 @@ static_assert( sizeof(AST_Param) == sizeof(AST), "ERROR: AST_Param is not the sa
 | 
			
		||||
struct AST_Pragma
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		StringCached  Content;
 | 
			
		||||
	};
 | 
			
		||||
	Code              Prev;
 | 
			
		||||
@@ -678,7 +678,7 @@ static_assert( sizeof(AST_Pragma) == sizeof(AST), "ERROR: AST_Pragma is not the
 | 
			
		||||
struct AST_PreprocessCond
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char          _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		StringCached  Content;
 | 
			
		||||
	};
 | 
			
		||||
	Code              Prev;
 | 
			
		||||
@@ -693,7 +693,7 @@ static_assert( sizeof(AST_PreprocessCond) == sizeof(AST), "ERROR: AST_Preprocess
 | 
			
		||||
 | 
			
		||||
struct AST_Specifiers
 | 
			
		||||
{
 | 
			
		||||
	SpecifierT        ArrSpecs[ AST::ArrSpecs_Cap ];
 | 
			
		||||
	SpecifierT        ArrSpecs[ AST_ArrSpecs_Cap ];
 | 
			
		||||
	CodeSpecifiers    NextSpecs;
 | 
			
		||||
	Code              Prev;
 | 
			
		||||
	Code              Next;
 | 
			
		||||
@@ -710,7 +710,7 @@ static_assert( sizeof(AST_Specifiers) == sizeof(AST), "ERROR: AST_Specifier is n
 | 
			
		||||
struct AST_Stmt
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -725,7 +725,7 @@ static_assert( sizeof(AST_Stmt) == sizeof(AST), "ERROR: AST_Stmt is not the same
 | 
			
		||||
struct AST_Stmt_Break
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -740,7 +740,7 @@ static_assert( sizeof(AST_Stmt_Break) == sizeof(AST), "ERROR: AST_Stmt_Break is
 | 
			
		||||
struct AST_Stmt_Case
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -755,7 +755,7 @@ static_assert( sizeof(AST_Stmt_Case) == sizeof(AST), "ERROR: AST_Stmt_Case is no
 | 
			
		||||
struct AST_Stmt_Continue
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -770,7 +770,7 @@ static_assert( sizeof(AST_Stmt_Continue) == sizeof(AST), "ERROR: AST_Stmt_Contin
 | 
			
		||||
struct AST_Stmt_Decl
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -785,7 +785,7 @@ static_assert( sizeof(AST_Stmt_Decl) == sizeof(AST), "ERROR: AST_Stmt_Decl is no
 | 
			
		||||
struct AST_Stmt_Do
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -800,7 +800,7 @@ static_assert( sizeof(AST_Stmt_Do) == sizeof(AST), "ERROR: AST_Stmt_Do is not th
 | 
			
		||||
struct AST_Stmt_Expr
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -815,7 +815,7 @@ static_assert( sizeof(AST_Stmt_Expr) == sizeof(AST), "ERROR: AST_Stmt_Expr is no
 | 
			
		||||
struct AST_Stmt_Else
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -830,7 +830,7 @@ static_assert( sizeof(AST_Stmt_Else) == sizeof(AST), "ERROR: AST_Stmt_Else is no
 | 
			
		||||
struct AST_Stmt_If
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -845,7 +845,7 @@ static_assert( sizeof(AST_Stmt_If) == sizeof(AST), "ERROR: AST_Stmt_If is not th
 | 
			
		||||
struct AST_Stmt_For
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -860,7 +860,7 @@ static_assert( sizeof(AST_Stmt_For) == sizeof(AST), "ERROR: AST_Stmt_For is not
 | 
			
		||||
struct AST_Stmt_Goto
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -875,7 +875,7 @@ static_assert( sizeof(AST_Stmt_Goto) == sizeof(AST), "ERROR: AST_Stmt_Goto is no
 | 
			
		||||
struct AST_Stmt_Label
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -890,7 +890,7 @@ static_assert( sizeof(AST_Stmt_Label) == sizeof(AST), "ERROR: AST_Stmt_Label is
 | 
			
		||||
struct AST_Stmt_Switch
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -905,7 +905,7 @@ static_assert( sizeof(AST_Stmt_Switch) == sizeof(AST), "ERROR: AST_Stmt_Switch i
 | 
			
		||||
struct AST_Stmt_While
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
	};
 | 
			
		||||
	CodeExpr       Prev;
 | 
			
		||||
	CodeExpr       Next;
 | 
			
		||||
@@ -921,7 +921,7 @@ static_assert( sizeof(AST_Stmt_While) == sizeof(AST), "ERROR: AST_Stmt_While is
 | 
			
		||||
struct AST_Struct
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			CodeComment    InlineCmt;
 | 
			
		||||
@@ -947,7 +947,7 @@ static_assert( sizeof(AST_Struct) == sizeof(AST), "ERROR: AST_Struct is not the
 | 
			
		||||
struct AST_Template
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			char 	       _PAD_PROPERTIES_[ sizeof(AST*) * 4 ];
 | 
			
		||||
@@ -972,7 +972,7 @@ static_assert( sizeof(AST_Template) == sizeof(AST), "ERROR: AST_Template is not
 | 
			
		||||
struct AST_Type
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			char           _PAD_INLINE_CMT_[ sizeof(AST*) ];
 | 
			
		||||
@@ -1000,7 +1000,7 @@ static_assert( sizeof(AST_Type) == sizeof(AST), "ERROR: AST_Type is not the same
 | 
			
		||||
struct AST_Type
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			char           _PAD_INLINE_CMT_[ sizeof(AST*) ];
 | 
			
		||||
@@ -1026,7 +1026,7 @@ static_assert( sizeof(AST_Type) == sizeof(AST), "ERROR: AST_Type is not the same
 | 
			
		||||
struct AST_Typedef
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			CodeComment    InlineCmt;
 | 
			
		||||
@@ -1049,7 +1049,7 @@ static_assert( sizeof(AST_Typedef) == sizeof(AST), "ERROR: AST_Typedef is not th
 | 
			
		||||
struct AST_Union
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			char           _PAD_INLINE_CMT_[ sizeof(AST*) ];
 | 
			
		||||
@@ -1073,7 +1073,7 @@ static_assert( sizeof(AST_Union) == sizeof(AST), "ERROR: AST_Union is not the sa
 | 
			
		||||
struct AST_Using
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char                _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char                _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			CodeComment     InlineCmt;
 | 
			
		||||
@@ -1097,7 +1097,7 @@ static_assert( sizeof(AST_Using) == sizeof(AST), "ERROR: AST_Using is not the sa
 | 
			
		||||
struct AST_Var
 | 
			
		||||
{
 | 
			
		||||
	union {
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		char               _PAD_[ sizeof(SpecifierT) * AST_ArrSpecs_Cap + sizeof(AST*) ];
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			CodeComment    InlineCmt;
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -3,47 +3,45 @@
 | 
			
		||||
#include "ast.hpp"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void   append           ( CodeBody body, Code     other );
 | 
			
		||||
void   append           ( CodeBody body, CodeBody other );
 | 
			
		||||
String to_string        ( CodeBody body );
 | 
			
		||||
void   to_string        ( CodeBody body, String* result );
 | 
			
		||||
void   to_string_export ( CodeBody body, String* result );
 | 
			
		||||
 | 
			
		||||
void   add_interface( CodeClass self, CodeType interface );
 | 
			
		||||
String to_string    ( CodeClass self );
 | 
			
		||||
void   to_string_def( CodeClass self, String* result );
 | 
			
		||||
void   to_string_fwd( CodeClass self, String* result );
 | 
			
		||||
 | 
			
		||||
#pragma region Code Types
 | 
			
		||||
// These structs are not used at all by the C vairant.
 | 
			
		||||
#if ! GEN_COMPILER_C
 | 
			
		||||
// stati_assert( GEN_COMPILER_C, "This should not be compiled with the C-library" );
 | 
			
		||||
 | 
			
		||||
struct CodeBody
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES
 | 
			
		||||
	Using_Code( CodeBody );
 | 
			
		||||
 | 
			
		||||
	void append( Code other )
 | 
			
		||||
	{
 | 
			
		||||
		raw()->append( other.ast );
 | 
			
		||||
	}
 | 
			
		||||
	void append( CodeBody body )
 | 
			
		||||
	{
 | 
			
		||||
		for ( Code entry : body )
 | 
			
		||||
		{
 | 
			
		||||
			append( entry );
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	bool has_entries()
 | 
			
		||||
	{
 | 
			
		||||
		return rcast( AST*, ast )->has_entries();
 | 
			
		||||
	}
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	void to_string_export( String& result );
 | 
			
		||||
	AST* raw()
 | 
			
		||||
	{
 | 
			
		||||
		return rcast( AST*, ast );
 | 
			
		||||
	}
 | 
			
		||||
	AST_Body* operator->()
 | 
			
		||||
	{
 | 
			
		||||
		return ast;
 | 
			
		||||
	}
 | 
			
		||||
	operator Code()
 | 
			
		||||
	{
 | 
			
		||||
		return * rcast( Code*, this );
 | 
			
		||||
	}
 | 
			
		||||
	void append( Code other )    { return GEN_NS append( *this, other ); }
 | 
			
		||||
	void append( CodeBody body ) { return GEN_NS append(*this, body); }
 | 
			
		||||
	bool has_entries()           { return GEN_NS has_entries(rcast( AST*, ast )); }
 | 
			
		||||
 | 
			
		||||
	String to_string()                        { return GEN_NS to_string(* this); }
 | 
			
		||||
	void   to_string( String& result )        { return GEN_NS to_string(* this, & result ); }
 | 
			
		||||
	void   to_string_export( String& result ) { return GEN_NS to_string_export(* this, & result); }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps( CodeBody );
 | 
			
		||||
	operator Code() { return * rcast( Code*, this ); }
 | 
			
		||||
	AST_Body* operator->() { return ast; }
 | 
			
		||||
 | 
			
		||||
#pragma region Iterator
 | 
			
		||||
	Code begin()
 | 
			
		||||
	{
 | 
			
		||||
		if ( ast )
 | 
			
		||||
			return { rcast( AST*, ast)->Front };
 | 
			
		||||
 | 
			
		||||
		return { nullptr };
 | 
			
		||||
	}
 | 
			
		||||
	Code end()
 | 
			
		||||
@@ -57,21 +55,18 @@ struct CodeBody
 | 
			
		||||
 | 
			
		||||
struct CodeClass
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 0
 | 
			
		||||
	Using_Code( CodeClass );
 | 
			
		||||
 | 
			
		||||
	void add_interface( CodeType interface );
 | 
			
		||||
 | 
			
		||||
	void to_string_def( String& result );
 | 
			
		||||
	void to_string_fwd( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string_def( String& result );
 | 
			
		||||
	void   to_string_fwd( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	AST* raw()
 | 
			
		||||
	{
 | 
			
		||||
		return rcast( AST*, ast );
 | 
			
		||||
	}
 | 
			
		||||
	operator Code()
 | 
			
		||||
	{
 | 
			
		||||
		return * rcast( Code*, this );
 | 
			
		||||
	}
 | 
			
		||||
	Using_CodeOps( CodeClass );
 | 
			
		||||
	operator Code() { return * rcast( Code*, this ); }
 | 
			
		||||
	AST_Class* operator->()
 | 
			
		||||
	{
 | 
			
		||||
		if ( ast == nullptr )
 | 
			
		||||
@@ -86,13 +81,17 @@ struct CodeClass
 | 
			
		||||
 | 
			
		||||
struct CodeParam
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeParam );
 | 
			
		||||
 | 
			
		||||
	void append( CodeParam other );
 | 
			
		||||
 | 
			
		||||
	void      append( CodeParam other );
 | 
			
		||||
	CodeParam get( s32 idx );
 | 
			
		||||
	bool has_entries();
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	bool      has_entries();
 | 
			
		||||
	String    to_string();
 | 
			
		||||
	void      to_string( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps( CodeParam );
 | 
			
		||||
	AST* raw()
 | 
			
		||||
	{
 | 
			
		||||
		return rcast( AST*, ast );
 | 
			
		||||
@@ -135,6 +134,7 @@ struct CodeParam
 | 
			
		||||
 | 
			
		||||
struct CodeSpecifiers
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeSpecifiers );
 | 
			
		||||
 | 
			
		||||
	bool append( SpecifierT spec )
 | 
			
		||||
@@ -145,9 +145,9 @@ struct CodeSpecifiers
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ( raw()->NumEntries == AST::ArrSpecs_Cap )
 | 
			
		||||
		if ( raw()->NumEntries == AST_ArrSpecs_Cap )
 | 
			
		||||
		{
 | 
			
		||||
			log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST::ArrSpecs_Cap );
 | 
			
		||||
			log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST_ArrSpecs_Cap );
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -165,7 +165,51 @@ struct CodeSpecifiers
 | 
			
		||||
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	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;
 | 
			
		||||
	}
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeSpecifiers);
 | 
			
		||||
	AST* raw()
 | 
			
		||||
	{
 | 
			
		||||
		return rcast( AST*, ast );
 | 
			
		||||
@@ -202,13 +246,17 @@ struct CodeSpecifiers
 | 
			
		||||
 | 
			
		||||
struct CodeStruct
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeStruct );
 | 
			
		||||
 | 
			
		||||
	void add_interface( CodeType interface );
 | 
			
		||||
 | 
			
		||||
	void to_string_def( String& result );
 | 
			
		||||
	void to_string_fwd( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string_fwd( String& result );
 | 
			
		||||
	void   to_string_def( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps( CodeStruct );
 | 
			
		||||
	AST* raw()
 | 
			
		||||
	{
 | 
			
		||||
		return rcast( AST*, ast );
 | 
			
		||||
@@ -229,27 +277,47 @@ struct CodeStruct
 | 
			
		||||
	AST_Struct* ast;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define Define_CodeType( Typename )     \
 | 
			
		||||
	struct Code##Typename               \
 | 
			
		||||
	{                                   \
 | 
			
		||||
		Using_Code( Code ## Typename ); \
 | 
			
		||||
		AST*            raw();          \
 | 
			
		||||
		operator        Code();         \
 | 
			
		||||
		AST_##Typename* operator->();   \
 | 
			
		||||
		AST_##Typename* ast;            \
 | 
			
		||||
	}
 | 
			
		||||
struct CodeAttributes
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code(CodeAttributes);
 | 
			
		||||
	String to_string();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeAttributes);
 | 
			
		||||
	AST *raw();
 | 
			
		||||
	operator Code();
 | 
			
		||||
	AST_Attributes *operator->();
 | 
			
		||||
	AST_Attributes *ast;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Define_CodeType( Attributes );
 | 
			
		||||
// Define_CodeType( BaseClass );
 | 
			
		||||
Define_CodeType( Comment );
 | 
			
		||||
 | 
			
		||||
struct CodeComment
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code(CodeComment);
 | 
			
		||||
	String to_string();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeComment);
 | 
			
		||||
	AST *raw();
 | 
			
		||||
	operator Code();
 | 
			
		||||
	AST_Comment *operator->();
 | 
			
		||||
	AST_Comment *ast;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct CodeConstructor
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeConstructor );
 | 
			
		||||
 | 
			
		||||
	void to_string_def( String& result );
 | 
			
		||||
	void to_string_fwd( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string_def( String& result );
 | 
			
		||||
	void   to_string_fwd( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeConstructor);
 | 
			
		||||
	AST*             raw();
 | 
			
		||||
	operator         Code();
 | 
			
		||||
	AST_Constructor* operator->();
 | 
			
		||||
@@ -258,10 +326,14 @@ struct CodeConstructor
 | 
			
		||||
 | 
			
		||||
struct CodeDefine
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeDefine );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeDefine);
 | 
			
		||||
	AST*        raw();
 | 
			
		||||
	operator    Code();
 | 
			
		||||
	AST_Define* operator->();
 | 
			
		||||
@@ -270,11 +342,15 @@ struct CodeDefine
 | 
			
		||||
 | 
			
		||||
struct CodeDestructor
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeDestructor );
 | 
			
		||||
 | 
			
		||||
	void to_string_def( String& result );
 | 
			
		||||
	void to_string_fwd( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string_def( String& result );
 | 
			
		||||
	void   to_string_fwd( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeDestructor);
 | 
			
		||||
	AST*             raw();
 | 
			
		||||
	operator         Code();
 | 
			
		||||
	AST_Destructor* operator->();
 | 
			
		||||
@@ -283,20 +359,36 @@ struct CodeDestructor
 | 
			
		||||
 | 
			
		||||
struct CodeEnum
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeEnum );
 | 
			
		||||
 | 
			
		||||
	void to_string_def( String& result );
 | 
			
		||||
	void to_string_fwd( String& result );
 | 
			
		||||
	void to_string_class_def( String& result );
 | 
			
		||||
	void to_string_class_fwd( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string_def( String& result );
 | 
			
		||||
	void   to_string_fwd( String& result );
 | 
			
		||||
	void   to_string_class_def( String& result );
 | 
			
		||||
	void   to_string_class_fwd( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeEnum);
 | 
			
		||||
	AST*      raw();
 | 
			
		||||
	operator  Code();
 | 
			
		||||
	AST_Enum* operator->();
 | 
			
		||||
	AST_Enum* ast;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Define_CodeType( Exec );
 | 
			
		||||
struct CodeExec
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code(CodeExec);
 | 
			
		||||
	String to_string();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeExec);
 | 
			
		||||
	AST *raw();
 | 
			
		||||
	operator Code();
 | 
			
		||||
	AST_Exec *operator->();
 | 
			
		||||
	AST_Exec *ast;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#if GEN_EXECUTION_EXPRESSION_SUPPORT
 | 
			
		||||
struct CodeExpr
 | 
			
		||||
@@ -506,10 +598,13 @@ struct CodeExpr_UnaryPostfix
 | 
			
		||||
 | 
			
		||||
struct CodeExtern
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeExtern );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeExtern);
 | 
			
		||||
	AST*        raw();
 | 
			
		||||
	operator    Code();
 | 
			
		||||
	AST_Extern* operator->();
 | 
			
		||||
@@ -518,10 +613,14 @@ struct CodeExtern
 | 
			
		||||
 | 
			
		||||
struct CodeInclude
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeInclude );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeInclude);
 | 
			
		||||
	AST*         raw();
 | 
			
		||||
	operator     Code();
 | 
			
		||||
	AST_Include* operator->();
 | 
			
		||||
@@ -530,10 +629,14 @@ struct CodeInclude
 | 
			
		||||
 | 
			
		||||
struct CodeFriend
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeFriend );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeFriend);
 | 
			
		||||
	AST*        raw();
 | 
			
		||||
	operator    Code();
 | 
			
		||||
	AST_Friend* operator->();
 | 
			
		||||
@@ -542,11 +645,15 @@ struct CodeFriend
 | 
			
		||||
 | 
			
		||||
struct CodeFn
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeFn );
 | 
			
		||||
 | 
			
		||||
	void to_string_def( String& result );
 | 
			
		||||
	void to_string_fwd( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string_def( String& result );
 | 
			
		||||
	void   to_string_fwd( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeFn);
 | 
			
		||||
	AST*     raw();
 | 
			
		||||
	operator Code();
 | 
			
		||||
	AST_Fn*  operator->();
 | 
			
		||||
@@ -555,10 +662,14 @@ struct CodeFn
 | 
			
		||||
 | 
			
		||||
struct CodeModule
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeModule );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeModule);
 | 
			
		||||
	AST*        raw();
 | 
			
		||||
	operator    Code();
 | 
			
		||||
	AST_Module* operator->();
 | 
			
		||||
@@ -567,10 +678,14 @@ struct CodeModule
 | 
			
		||||
 | 
			
		||||
struct CodeNS
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeNS );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeNS);
 | 
			
		||||
	AST*     raw();
 | 
			
		||||
	operator Code();
 | 
			
		||||
	AST_NS*  operator->();
 | 
			
		||||
@@ -579,11 +694,15 @@ struct CodeNS
 | 
			
		||||
 | 
			
		||||
struct CodeOperator
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeOperator );
 | 
			
		||||
 | 
			
		||||
	void to_string_def( String& result );
 | 
			
		||||
	void to_string_fwd( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string_def( String& result );
 | 
			
		||||
	void   to_string_fwd( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeOperator);
 | 
			
		||||
	AST*          raw();
 | 
			
		||||
	operator      Code();
 | 
			
		||||
	AST_Operator* operator->();
 | 
			
		||||
@@ -592,11 +711,15 @@ struct CodeOperator
 | 
			
		||||
 | 
			
		||||
struct CodeOpCast
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeOpCast );
 | 
			
		||||
 | 
			
		||||
	void to_string_def( String& result );
 | 
			
		||||
	void to_string_fwd( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string_def( String& result );
 | 
			
		||||
	void   to_string_fwd( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeOpCast);
 | 
			
		||||
	AST*        raw();
 | 
			
		||||
	operator    Code();
 | 
			
		||||
	AST_OpCast* operator->();
 | 
			
		||||
@@ -605,10 +728,14 @@ struct CodeOpCast
 | 
			
		||||
 | 
			
		||||
struct CodePragma
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodePragma );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps( CodePragma );
 | 
			
		||||
	AST*        raw();
 | 
			
		||||
	operator    Code();
 | 
			
		||||
	AST_Pragma* operator->();
 | 
			
		||||
@@ -617,15 +744,19 @@ struct CodePragma
 | 
			
		||||
 | 
			
		||||
struct CodePreprocessCond
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodePreprocessCond );
 | 
			
		||||
 | 
			
		||||
	void to_string_if( String& result );
 | 
			
		||||
	void to_string_ifdef( String& result );
 | 
			
		||||
	void to_string_ifndef( String& result );
 | 
			
		||||
	void to_string_elif( String& result );
 | 
			
		||||
	void to_string_else( String& result );
 | 
			
		||||
	void to_string_endif( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string_if( String& result );
 | 
			
		||||
	void   to_string_ifdef( String& result );
 | 
			
		||||
	void   to_string_ifndef( String& result );
 | 
			
		||||
	void   to_string_elif( String& result );
 | 
			
		||||
	void   to_string_else( String& result );
 | 
			
		||||
	void   to_string_endif( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps( CodePreprocessCond );
 | 
			
		||||
	AST*                raw();
 | 
			
		||||
	operator            Code();
 | 
			
		||||
	AST_PreprocessCond* operator->();
 | 
			
		||||
@@ -637,7 +768,8 @@ struct CodeStmt
 | 
			
		||||
{
 | 
			
		||||
	Using_Code( CodeStmt );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	AST*      raw();
 | 
			
		||||
	operator  Code();
 | 
			
		||||
@@ -649,7 +781,8 @@ struct CodeStmt_Break
 | 
			
		||||
{
 | 
			
		||||
	Using_Code( CodeStmt_Break );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	AST*            raw();
 | 
			
		||||
	operator        Code();
 | 
			
		||||
@@ -661,7 +794,8 @@ struct CodeStmt_Case
 | 
			
		||||
{
 | 
			
		||||
	Using_Code( CodeStmt_Case );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	AST*           raw();
 | 
			
		||||
	operator       Code();
 | 
			
		||||
@@ -673,7 +807,8 @@ struct CodeStmt_Continue
 | 
			
		||||
{
 | 
			
		||||
	Using_Code( CodeStmt_Continue );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	AST*               raw();
 | 
			
		||||
	operator           Code();
 | 
			
		||||
@@ -685,7 +820,8 @@ struct CodeStmt_Decl
 | 
			
		||||
{
 | 
			
		||||
	Using_Code( CodeStmt_Decl );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	AST*           raw();
 | 
			
		||||
	operator       Code();
 | 
			
		||||
@@ -697,7 +833,8 @@ struct CodeStmt_Do
 | 
			
		||||
{
 | 
			
		||||
	Using_Code( CodeStmt_Do );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	AST*         raw();
 | 
			
		||||
	operator     Code();
 | 
			
		||||
@@ -709,7 +846,8 @@ struct CodeStmt_Expr
 | 
			
		||||
{
 | 
			
		||||
	Using_Code( CodeStmt_Expr );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	AST*           raw();
 | 
			
		||||
	operator       Code();
 | 
			
		||||
@@ -721,7 +859,8 @@ struct CodeStmt_Else
 | 
			
		||||
{
 | 
			
		||||
	Using_Code( CodeStmt_Else );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	AST*           raw();
 | 
			
		||||
	operator       Code();
 | 
			
		||||
@@ -733,7 +872,8 @@ struct CodeStmt_If
 | 
			
		||||
{
 | 
			
		||||
	Using_Code( CodeStmt_If );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	AST*         raw();
 | 
			
		||||
	operator     Code();
 | 
			
		||||
@@ -745,7 +885,8 @@ struct CodeStmt_For
 | 
			
		||||
{
 | 
			
		||||
	Using_Code( CodeStmt_For );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	AST*          raw();
 | 
			
		||||
	operator      Code();
 | 
			
		||||
@@ -757,7 +898,8 @@ struct CodeStmt_Goto
 | 
			
		||||
{
 | 
			
		||||
	Using_Code( CodeStmt_Goto );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	AST*           raw();
 | 
			
		||||
	operator       Code();
 | 
			
		||||
@@ -769,7 +911,8 @@ struct CodeStmt_Label
 | 
			
		||||
{
 | 
			
		||||
	Using_Code( CodeStmt_Label );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	AST*            raw();
 | 
			
		||||
	operator        Code();
 | 
			
		||||
@@ -781,7 +924,8 @@ struct CodeStmt_Switch
 | 
			
		||||
{
 | 
			
		||||
	Using_Code( CodeStmt_Switch );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	AST*           raw();
 | 
			
		||||
	operator       Code();
 | 
			
		||||
@@ -793,7 +937,8 @@ struct CodeStmt_While
 | 
			
		||||
{
 | 
			
		||||
	Using_Code( CodeStmt_While );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
 | 
			
		||||
	AST*           raw();
 | 
			
		||||
	operator       Code();
 | 
			
		||||
@@ -804,10 +949,14 @@ struct CodeStmt_While
 | 
			
		||||
 | 
			
		||||
struct CodeTemplate
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeTemplate );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps( CodeTemplate );
 | 
			
		||||
	AST*          raw();
 | 
			
		||||
	operator      Code();
 | 
			
		||||
	AST_Template* operator->();
 | 
			
		||||
@@ -816,10 +965,14 @@ struct CodeTemplate
 | 
			
		||||
 | 
			
		||||
struct CodeType
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeType );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps( CodeType );
 | 
			
		||||
	AST*      raw();
 | 
			
		||||
	operator  Code();
 | 
			
		||||
	AST_Type* operator->();
 | 
			
		||||
@@ -828,10 +981,14 @@ struct CodeType
 | 
			
		||||
 | 
			
		||||
struct CodeTypedef
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeTypedef );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps( CodeTypedef );
 | 
			
		||||
	AST*         raw();
 | 
			
		||||
	operator     Code();
 | 
			
		||||
	AST_Typedef* operator->();
 | 
			
		||||
@@ -840,10 +997,14 @@ struct CodeTypedef
 | 
			
		||||
 | 
			
		||||
struct CodeUnion
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeUnion );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeUnion);
 | 
			
		||||
	AST*       raw();
 | 
			
		||||
	operator   Code();
 | 
			
		||||
	AST_Union* operator->();
 | 
			
		||||
@@ -852,11 +1013,15 @@ struct CodeUnion
 | 
			
		||||
 | 
			
		||||
struct CodeUsing
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeUsing );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	void to_string_ns( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
	void   to_string_ns( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeUsing);
 | 
			
		||||
	AST*       raw();
 | 
			
		||||
	operator   Code();
 | 
			
		||||
	AST_Using* operator->();
 | 
			
		||||
@@ -865,10 +1030,14 @@ struct CodeUsing
 | 
			
		||||
 | 
			
		||||
struct CodeVar
 | 
			
		||||
{
 | 
			
		||||
#if GEN_SUPPORT_CPP_MEMBER_FEATURES || 1
 | 
			
		||||
	Using_Code( CodeVar );
 | 
			
		||||
 | 
			
		||||
	void to_string( String& result );
 | 
			
		||||
	String to_string();
 | 
			
		||||
	void   to_string( String& result );
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	Using_CodeOps(CodeVar);
 | 
			
		||||
	AST*     raw();
 | 
			
		||||
	operator Code();
 | 
			
		||||
	AST_Var* operator->();
 | 
			
		||||
@@ -877,5 +1046,11 @@ struct CodeVar
 | 
			
		||||
 | 
			
		||||
#undef Define_CodeType
 | 
			
		||||
#undef Using_Code
 | 
			
		||||
#undef Using_CodeOps
 | 
			
		||||
 | 
			
		||||
#if GEN_SUPPORT_CPP_REFERENCES
 | 
			
		||||
void to_string_export( CodeBody body, String& result ) { return to_string_export(body, & result); };
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif //if ! GEN_COMPILER_C
 | 
			
		||||
#pragma endregion Code Types
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,56 +4,82 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
void AST::append( AST* other )
 | 
			
		||||
void append( AST* self, AST* other )
 | 
			
		||||
{
 | 
			
		||||
	GEN_ASSERT(self  != nullptr);
 | 
			
		||||
	GEN_ASSERT(other != nullptr);
 | 
			
		||||
 | 
			
		||||
	if ( other->Parent )
 | 
			
		||||
		other = other->duplicate();
 | 
			
		||||
		other = duplicate(other);
 | 
			
		||||
 | 
			
		||||
	other->Parent = this;
 | 
			
		||||
	other->Parent = self;
 | 
			
		||||
 | 
			
		||||
	if ( Front == nullptr )
 | 
			
		||||
	if ( self->Front == nullptr )
 | 
			
		||||
	{
 | 
			
		||||
		Front = other;
 | 
			
		||||
		Back  = other;
 | 
			
		||||
		self->Front = other;
 | 
			
		||||
		self->Back  = other;
 | 
			
		||||
 | 
			
		||||
		NumEntries++;
 | 
			
		||||
		self->NumEntries++;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	AST*
 | 
			
		||||
		Current       = Back;
 | 
			
		||||
	Current       = self->Back;
 | 
			
		||||
	Current->Next = other;
 | 
			
		||||
	other->Prev   = Current;
 | 
			
		||||
	Back          = other;
 | 
			
		||||
	NumEntries++;
 | 
			
		||||
	self->Back    = other;
 | 
			
		||||
	self->NumEntries++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
Code& AST::entry( u32 idx )
 | 
			
		||||
Code* entry( AST* self, u32 idx )
 | 
			
		||||
{
 | 
			
		||||
	AST** current = & Front;
 | 
			
		||||
	GEN_ASSERT(self != nullptr);
 | 
			
		||||
	AST** current = & self->Front;
 | 
			
		||||
	while ( idx >= 0 && current != nullptr )
 | 
			
		||||
	{
 | 
			
		||||
		if ( idx == 0 )
 | 
			
		||||
			return * rcast( Code*, current);
 | 
			
		||||
			return rcast( Code*, current);
 | 
			
		||||
 | 
			
		||||
		current = & ( * current )->Next;
 | 
			
		||||
		idx--;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return * rcast( Code*, current);
 | 
			
		||||
	return rcast( Code*, current);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
bool AST::has_entries()
 | 
			
		||||
bool has_entries(AST* self)
 | 
			
		||||
{
 | 
			
		||||
	return NumEntries > 0;
 | 
			
		||||
	GEN_ASSERT(self != nullptr);
 | 
			
		||||
	return self->NumEntries > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
char const* AST::type_str()
 | 
			
		||||
bool is_body(AST* self)
 | 
			
		||||
{
 | 
			
		||||
	return ECode::to_str( Type );
 | 
			
		||||
	GEN_ASSERT(self != nullptr);
 | 
			
		||||
	switch (self->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* type_str(AST* self)
 | 
			
		||||
{
 | 
			
		||||
	GEN_ASSERT(self != nullptr);
 | 
			
		||||
	return ECode::to_str( self->Type );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
@@ -62,6 +88,69 @@ AST::operator Code()
 | 
			
		||||
	return { this };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma region Code
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
char const* debug_str( Code code )
 | 
			
		||||
{
 | 
			
		||||
	if ( code.ast == nullptr )
 | 
			
		||||
		return "Code::debug_str: AST is null!";
 | 
			
		||||
 | 
			
		||||
	return debug_str( code.ast );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
Code duplicate( Code code )
 | 
			
		||||
{
 | 
			
		||||
	if ( code.ast == nullptr )
 | 
			
		||||
	{
 | 
			
		||||
		log_failure("Code::duplicate: Cannot duplicate code, AST is null!");
 | 
			
		||||
		return Code_Invalid;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return { duplicate(code.ast) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
bool is_body(Code code)
 | 
			
		||||
{
 | 
			
		||||
	if ( code.ast == nullptr )
 | 
			
		||||
	{
 | 
			
		||||
		return is_body(code.ast);
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
bool is_equal( Code self, Code other )
 | 
			
		||||
{
 | 
			
		||||
	if ( self.ast == nullptr || other.ast == nullptr )
 | 
			
		||||
	{
 | 
			
		||||
		// Just check if they're both null.
 | 
			
		||||
		// log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
 | 
			
		||||
		return self.ast == nullptr && other.ast == nullptr;
 | 
			
		||||
	}
 | 
			
		||||
	return is_equal( self.ast, other.ast );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
bool is_valid(Code self)
 | 
			
		||||
{
 | 
			
		||||
	return self.ast != nullptr && self.ast->Type != CodeT::Invalid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
void set_global(Code self)
 | 
			
		||||
{
 | 
			
		||||
	if ( self.ast == nullptr )
 | 
			
		||||
	{
 | 
			
		||||
		log_failure("Code::set_global: Cannot set code as global, AST is null!");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	self->Parent = Code_Global.ast;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
Code& Code::operator ++()
 | 
			
		||||
{
 | 
			
		||||
@@ -71,14 +160,38 @@ Code& Code::operator ++()
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma endregion Code
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
void CodeClass::add_interface( CodeType type )
 | 
			
		||||
void append( CodeBody self, Code other )
 | 
			
		||||
{
 | 
			
		||||
	CodeType possible_slot = ast->ParentType;
 | 
			
		||||
	GEN_ASSERT(other.ast != nullptr);
 | 
			
		||||
 | 
			
		||||
	if (is_body(other)) {
 | 
			
		||||
		append( self, cast(CodeBody, other) );
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	append( rcast(AST*, self.ast), other.ast );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
void append( CodeBody self, CodeBody body )
 | 
			
		||||
{
 | 
			
		||||
	for ( Code entry : body ) {
 | 
			
		||||
		append( self, entry );
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
void add_interface( CodeClass self, CodeType type )
 | 
			
		||||
{
 | 
			
		||||
	GEN_ASSERT(self.ast !=nullptr);
 | 
			
		||||
	CodeType possible_slot = self->ParentType;
 | 
			
		||||
	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;
 | 
			
		||||
		self->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.
 | 
			
		||||
	}
 | 
			
		||||
@@ -98,7 +211,7 @@ void CodeParam::append( CodeParam other )
 | 
			
		||||
	AST* entry = (AST*) other.ast;
 | 
			
		||||
 | 
			
		||||
	if ( entry->Parent )
 | 
			
		||||
		entry = entry->duplicate();
 | 
			
		||||
		entry = GEN_NS duplicate( entry );
 | 
			
		||||
 | 
			
		||||
	entry->Parent = self;
 | 
			
		||||
 | 
			
		||||
@@ -151,7 +264,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.
 | 
			
		||||
	}
 | 
			
		||||
@@ -183,7 +296,7 @@ CodeBody def_body( CodeT type )
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			log_failure( "def_body: Invalid type %s", (char const*)ECode::to_str(type) );
 | 
			
		||||
			return (CodeBody)Code::Invalid;
 | 
			
		||||
			return (CodeBody)Code_Invalid;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Code
 | 
			
		||||
 
 | 
			
		||||
@@ -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,74 +74,74 @@ 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();
 | 
			
		||||
	Code_Invalid = make_code();
 | 
			
		||||
	set_global(Code_Invalid);
 | 
			
		||||
 | 
			
		||||
	t_empty          = (CodeType) make_code();
 | 
			
		||||
	t_empty->Type    = ECode::Typename;
 | 
			
		||||
	t_empty->Name    = get_cached_string( txt("") );
 | 
			
		||||
	t_empty.set_global();
 | 
			
		||||
	t_empty       = (CodeType) make_code();
 | 
			
		||||
	t_empty->Type = ECode::Typename;
 | 
			
		||||
	t_empty->Name = get_cached_string( txt("") );
 | 
			
		||||
	set_global(t_empty);
 | 
			
		||||
 | 
			
		||||
	access_private       = make_code();
 | 
			
		||||
	access_private->Type = ECode::Access_Private;
 | 
			
		||||
	access_private->Name = get_cached_string( txt("private:\n") );
 | 
			
		||||
	access_private.set_global();
 | 
			
		||||
	set_global(access_private);
 | 
			
		||||
 | 
			
		||||
	access_protected       = make_code();
 | 
			
		||||
	access_protected->Type = ECode::Access_Protected;
 | 
			
		||||
	access_protected->Name = get_cached_string( txt("protected:\n") );
 | 
			
		||||
	access_protected.set_global();
 | 
			
		||||
	set_global(access_protected);
 | 
			
		||||
 | 
			
		||||
	access_public       = make_code();
 | 
			
		||||
	access_public->Type = ECode::Access_Public;
 | 
			
		||||
	access_public->Name = get_cached_string( txt("public:\n") );
 | 
			
		||||
	access_public.set_global();
 | 
			
		||||
	set_global(access_public);
 | 
			
		||||
 | 
			
		||||
	attrib_api_export = def_attributes( code(GEN_API_Export_Code));
 | 
			
		||||
	attrib_api_export.set_global();
 | 
			
		||||
	set_global(attrib_api_export);
 | 
			
		||||
 | 
			
		||||
	attrib_api_import = def_attributes( code(GEN_API_Import_Code));
 | 
			
		||||
	attrib_api_import.set_global();
 | 
			
		||||
	set_global(attrib_api_import);
 | 
			
		||||
 | 
			
		||||
	module_global_fragment          = make_code();
 | 
			
		||||
	module_global_fragment->Type    = ECode::Untyped;
 | 
			
		||||
	module_global_fragment->Name    = get_cached_string( txt("module;") );
 | 
			
		||||
	module_global_fragment->Content = module_global_fragment->Name;
 | 
			
		||||
	module_global_fragment.set_global();
 | 
			
		||||
	set_global(module_global_fragment);
 | 
			
		||||
 | 
			
		||||
	module_private_fragment          = make_code();
 | 
			
		||||
	module_private_fragment->Type    = ECode::Untyped;
 | 
			
		||||
	module_private_fragment->Name    = get_cached_string( txt("module : private;") );
 | 
			
		||||
	module_private_fragment->Content = module_private_fragment->Name;
 | 
			
		||||
	module_private_fragment.set_global();
 | 
			
		||||
	set_global(module_private_fragment);
 | 
			
		||||
 | 
			
		||||
	fmt_newline = make_code();
 | 
			
		||||
	fmt_newline->Type = ECode::NewLine;
 | 
			
		||||
	fmt_newline.set_global();
 | 
			
		||||
	set_global(fmt_newline);
 | 
			
		||||
 | 
			
		||||
	pragma_once          = (CodePragma) make_code();
 | 
			
		||||
	pragma_once->Type    = ECode::Preprocess_Pragma;
 | 
			
		||||
	pragma_once->Name    = get_cached_string( txt("once") );
 | 
			
		||||
	pragma_once->Content = pragma_once->Name;
 | 
			
		||||
	pragma_once.set_global();
 | 
			
		||||
	set_global(pragma_once);
 | 
			
		||||
 | 
			
		||||
	param_varadic            = (CodeType) make_code();
 | 
			
		||||
	param_varadic->Type      = ECode::Parameters;
 | 
			
		||||
	param_varadic->Name      = get_cached_string( txt("...") );
 | 
			
		||||
	param_varadic->ValueType = t_empty;
 | 
			
		||||
	param_varadic.set_global();
 | 
			
		||||
	set_global(param_varadic);
 | 
			
		||||
 | 
			
		||||
	preprocess_else = (CodePreprocessCond) make_code();
 | 
			
		||||
	preprocess_else->Type = ECode::Preprocess_Else;
 | 
			
		||||
	preprocess_else.set_global();
 | 
			
		||||
	set_global(preprocess_else);
 | 
			
		||||
 | 
			
		||||
	preprocess_endif = (CodePreprocessCond) make_code();
 | 
			
		||||
	preprocess_endif->Type = ECode::Preprocess_EndIf;
 | 
			
		||||
	preprocess_endif.set_global();
 | 
			
		||||
	set_global(preprocess_endif);
 | 
			
		||||
 | 
			
		||||
#	define def_constant_code_type( Type_ )   \
 | 
			
		||||
		t_##Type_ = def_type( name(Type_) ); \
 | 
			
		||||
@@ -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 );
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ CodeClass parse_class( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	push_scope();
 | 
			
		||||
@@ -31,7 +31,7 @@ CodeConstructor parse_constructor( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	// TODO(Ed): Constructors can have prefix attributes
 | 
			
		||||
 | 
			
		||||
@@ -61,7 +61,7 @@ CodeConstructor parse_constructor( StrC def )
 | 
			
		||||
			default :
 | 
			
		||||
				log_failure( "Invalid specifier %s for variable\n%s", ESpecifier::to_str( spec ), Context.to_string() );
 | 
			
		||||
				Context.pop();
 | 
			
		||||
				return CodeInvalid;
 | 
			
		||||
				return InvalidCode;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Every specifier after would be considered part of the type type signature
 | 
			
		||||
@@ -91,7 +91,7 @@ CodeDestructor parse_destructor( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	// TODO(Ed): Destructors can have prefix attributes
 | 
			
		||||
	// TODO(Ed): Destructors can have virtual
 | 
			
		||||
@@ -110,7 +110,7 @@ CodeEnum parse_enum( StrC def )
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
	{
 | 
			
		||||
		Context.pop();
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
@@ -124,7 +124,7 @@ CodeBody parse_export_body( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	return parse_export_body();
 | 
			
		||||
@@ -137,7 +137,7 @@ CodeExtern parse_extern_link( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	return parse_extern_link();
 | 
			
		||||
@@ -150,7 +150,7 @@ CodeFriend parse_friend( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	return parse_friend();
 | 
			
		||||
@@ -163,7 +163,7 @@ CodeFn parse_function( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	return (CodeFn) parse_function();
 | 
			
		||||
@@ -176,7 +176,7 @@ CodeBody parse_global_body( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	push_scope();
 | 
			
		||||
@@ -192,7 +192,7 @@ CodeNS parse_namespace( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	return parse_namespace();
 | 
			
		||||
@@ -205,7 +205,7 @@ CodeOperator parse_operator( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	return (CodeOperator) parse_operator();
 | 
			
		||||
@@ -218,7 +218,7 @@ CodeOpCast parse_operator_cast( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	return parse_operator_cast();
 | 
			
		||||
@@ -231,7 +231,7 @@ CodeStruct parse_struct( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	push_scope();
 | 
			
		||||
@@ -247,7 +247,7 @@ CodeTemplate parse_template( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	return parse_template();
 | 
			
		||||
@@ -260,7 +260,7 @@ CodeType parse_type( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	return parse_type();
 | 
			
		||||
@@ -273,7 +273,7 @@ CodeTypedef parse_typedef( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	return parse_typedef();
 | 
			
		||||
@@ -286,7 +286,7 @@ CodeUnion parse_union( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	return parse_union();
 | 
			
		||||
@@ -299,7 +299,7 @@ CodeUsing parse_using( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	return parse_using();
 | 
			
		||||
@@ -312,7 +312,7 @@ CodeVar parse_variable( StrC def )
 | 
			
		||||
 | 
			
		||||
	TokArray toks = lex( def );
 | 
			
		||||
	if ( toks.Arr == nullptr )
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
 | 
			
		||||
	Context.Tokens = toks;
 | 
			
		||||
	return parse_variable();
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
@@ -27,8 +27,7 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va )
 | 
			
		||||
			StrC        value = va_arg( va, StrC );
 | 
			
		||||
 | 
			
		||||
			u32 key = crc32( token, str_len(token) );
 | 
			
		||||
 | 
			
		||||
			tok_map.set( key, value );
 | 
			
		||||
			set(& tok_map, key, value );
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -64,7 +63,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 +93,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;
 | 
			
		||||
 | 
			
		||||
@@ -107,7 +106,7 @@ Code untyped_str( StrC content )
 | 
			
		||||
	if ( content.Len == 0 )
 | 
			
		||||
	{
 | 
			
		||||
		log_failure( "untyped_str: empty string" );
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Code
 | 
			
		||||
@@ -119,7 +118,7 @@ Code untyped_str( StrC content )
 | 
			
		||||
	if ( result->Name == nullptr )
 | 
			
		||||
	{
 | 
			
		||||
		log_failure( "untyped_str: could not cache string" );
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
@@ -130,7 +129,7 @@ Code untyped_fmt( char const* fmt, ...)
 | 
			
		||||
	if ( fmt == nullptr )
 | 
			
		||||
	{
 | 
			
		||||
		log_failure( "untyped_fmt: null format string" );
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	local_persist thread_local
 | 
			
		||||
@@ -150,7 +149,7 @@ Code untyped_fmt( char const* fmt, ...)
 | 
			
		||||
	if ( result->Name == nullptr )
 | 
			
		||||
	{
 | 
			
		||||
		log_failure( "untyped_fmt: could not cache string" );
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
@@ -161,7 +160,7 @@ Code untyped_token_fmt( s32 num_tokens, ... )
 | 
			
		||||
	if ( num_tokens == 0 )
 | 
			
		||||
	{
 | 
			
		||||
		log_failure( "untyped_token_fmt: zero tokens" );
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	local_persist thread_local
 | 
			
		||||
@@ -181,7 +180,7 @@ Code untyped_token_fmt( s32 num_tokens, ... )
 | 
			
		||||
	if ( result->Name == nullptr )
 | 
			
		||||
	{
 | 
			
		||||
		log_failure( "untyped_fmt: could not cache string" );
 | 
			
		||||
		return CodeInvalid;
 | 
			
		||||
		return InvalidCode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -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 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -579,14 +579,14 @@ TokArray lex( StrC content )
 | 
			
		||||
	if ( left <= 0 )
 | 
			
		||||
	{
 | 
			
		||||
		log_failure( "gen::lex: no tokens found (only whitespace provided)" );
 | 
			
		||||
		return { { nullptr }, 0 };
 | 
			
		||||
		return { {}, 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;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -652,7 +652,7 @@ TokArray lex( StrC content )
 | 
			
		||||
						continue;
 | 
			
		||||
 | 
			
		||||
					case Lex_ReturnNull:
 | 
			
		||||
						return { { nullptr }, 0 };
 | 
			
		||||
						return { {}, 0 };
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			case '.':
 | 
			
		||||
@@ -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 };
 | 
			
		||||
		return { {}, 0 };
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defines.clear();
 | 
			
		||||
	clear(defines);
 | 
			
		||||
	// defines_map_arena.free();
 | 
			
		||||
	return { Tokens, 0 };
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -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), "AccessSpec not u32 size" );
 | 
			
		||||
 | 
			
		||||
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), "CodeFlag not u32 size" );
 | 
			
		||||
 | 
			
		||||
// 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), "ModuleFlag not u32 size" );
 | 
			
		||||
 | 
			
		||||
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), "EPreprocessCond not u32 size" );
 | 
			
		||||
 
 | 
			
		||||
@@ -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,39 @@
 | 
			
		||||
#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 cast
 | 
			
		||||
#	define cast( type, value ) (tmpl_cast<type>( value ))
 | 
			
		||||
#	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 )
 | 
			
		||||
#	endif
 | 
			
		||||
#else
 | 
			
		||||
#	ifndef cast
 | 
			
		||||
#	define cast( type, value )  ( (type)(value) )
 | 
			
		||||
#	endif
 | 
			
		||||
#	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 +145,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 +173,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 +188,50 @@
 | 
			
		||||
#	endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if !defined(GEN_SUPPORT_CPP_REFERENCES) && (GEN_COMPILER_C || __STDC_VERSION__ < 202311L)
 | 
			
		||||
#	undef    GEN_SUPPORT_CPP_REFERENCES
 | 
			
		||||
#	define   GEN_SUPPORT_CPP_REFERENCES 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if !defined(GEN_SUPPORT_CPP_MEMBER_FEATURES) && (GEN_COMPILER_C || __STDC_VERSION__ < 202311L)
 | 
			
		||||
#	undef    GEN_SUPPORT_CPP_MEMBER_FEATURES
 | 
			
		||||
#	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
 | 
			
		||||
 | 
			
		||||
#if GEN_COMPILER_C
 | 
			
		||||
#	ifndef nullptr
 | 
			
		||||
#		define nullptr NULL
 | 
			
		||||
#	endif
 | 
			
		||||
#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 ) )
 | 
			
		||||
@@ -62,24 +62,23 @@ void zero_size( void* ptr, ssize size );
 | 
			
		||||
//! Clears up an array.
 | 
			
		||||
#define zero_array( a, count ) zero_size( ( a ), size_of( *( a ) ) * count )
 | 
			
		||||
 | 
			
		||||
enum AllocType : u8
 | 
			
		||||
enum AllocType_Def //enum_underlying(u8)
 | 
			
		||||
{
 | 
			
		||||
	EAllocation_ALLOC,
 | 
			
		||||
	EAllocation_FREE,
 | 
			
		||||
	EAllocation_FREE_ALL,
 | 
			
		||||
	EAllocation_RESIZE,
 | 
			
		||||
};
 | 
			
		||||
typedef enum AllocType_Def AllocType;
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
struct AllocatorInfo_Def
 | 
			
		||||
{
 | 
			
		||||
	AllocatorProc* Proc;
 | 
			
		||||
	void*          Data;
 | 
			
		||||
};
 | 
			
		||||
typedef struct AllocatorInfo_Def AllocatorInfo;
 | 
			
		||||
 | 
			
		||||
enum AllocFlag
 | 
			
		||||
{
 | 
			
		||||
@@ -135,7 +134,7 @@ void* default_resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize ne
 | 
			
		||||
void* heap_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags );
 | 
			
		||||
 | 
			
		||||
//! The heap allocator backed by operating system's memory manager.
 | 
			
		||||
constexpr AllocatorInfo heap( void ) { return { heap_allocator_proc, nullptr }; }
 | 
			
		||||
constexpr AllocatorInfo heap( void ) { AllocatorInfo allocator = { heap_allocator_proc, nullptr }; return allocator; }
 | 
			
		||||
 | 
			
		||||
//! Helper to allocate memory using heap allocator.
 | 
			
		||||
#define malloc( sz ) alloc( heap(), sz )
 | 
			
		||||
@@ -170,121 +169,206 @@ 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 );
 | 
			
		||||
	}
 | 
			
		||||
// 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 );
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
	}
 | 
			
		||||
Arena init_sub      (Arena* parent, ssize size);
 | 
			
		||||
ssize alignment_of  (Arena* arena, ssize alignment);
 | 
			
		||||
void  free          (Arena* arena);
 | 
			
		||||
ssize size_remaining(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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#if GEN_SUPPORT_CPP_REFERENCES
 | 
			
		||||
forceinline AllocatorInfo allocator_info(Arena& arena )                 { return allocator_info(& arena); }
 | 
			
		||||
forceinline Arena         init_sub      (Arena& parent, ssize size)     { return init_sub( & parent, size); }
 | 
			
		||||
forceinline ssize         alignment_of  (Arena& arena, ssize alignment) { return alignment_of( & arena, alignment); }
 | 
			
		||||
forceinline void          free          (Arena& arena)                  { return free(& arena); }
 | 
			
		||||
forceinline ssize         size_remaining(Arena& arena, ssize alignment) { return size_remaining(& arena, alignment); }
 | 
			
		||||
 | 
			
		||||
// This id is defined by Unreal for asserts
 | 
			
		||||
#pragma push_macro("check")
 | 
			
		||||
#undef check
 | 
			
		||||
forceinline void check(Arena& arena) { return check(& arena); };
 | 
			
		||||
#pragma pop_macro("check")
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
AllocatorInfo allocator_info( Arena* arena ) {
 | 
			
		||||
	GEN_ASSERT(arena != nullptr);
 | 
			
		||||
	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) {
 | 
			
		||||
	GEN_ASSERT(parent != nullptr);
 | 
			
		||||
	return arena_init_from_allocator(parent->Backing, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
ssize alignment_of(Arena* arena, ssize alignment)
 | 
			
		||||
{
 | 
			
		||||
	GEN_ASSERT(arena != nullptr);
 | 
			
		||||
	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 != nullptr );
 | 
			
		||||
    GEN_ASSERT(arena->TempCount == 0);
 | 
			
		||||
}
 | 
			
		||||
#pragma pop_macro("check")
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
void free(Arena* arena)
 | 
			
		||||
{
 | 
			
		||||
	GEN_ASSERT(arena != nullptr);
 | 
			
		||||
	if (arena->Backing.Proc)
 | 
			
		||||
	{
 | 
			
		||||
		GEN_NS free(arena->Backing, arena->PhysicalStart);
 | 
			
		||||
		arena->PhysicalStart = nullptr;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
ssize size_remaining(Arena* arena, ssize alignment)
 | 
			
		||||
{
 | 
			
		||||
	GEN_ASSERT(arena != nullptr);
 | 
			
		||||
	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> FixedArena<Size> fixed_arena_init();
 | 
			
		||||
template<s32 Size> AllocatorInfo    allocator_info(FixedArena<Size>* fixed_arena );
 | 
			
		||||
template<s32 Size> ssize            size_remaining(FixedArena<Size>* fixed_arena, ssize alignment);
 | 
			
		||||
 | 
			
		||||
#if GEN_SUPPORT_CPP_REFERENCES
 | 
			
		||||
template<s32 Size> AllocatorInfo    allocator_info( FixedArena<Size>& fixed_arena )                { return allocator_info(& fixed_arena); }
 | 
			
		||||
template<s32 Size> ssize            size_remaining(FixedArena<Size>& fixed_arena, ssize alignment) { return size_remaining( & fixed_arena, alignment); }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// 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 ) {
 | 
			
		||||
	GEN_ASSERT(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 +381,27 @@ 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;
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
AllocatorInfo allocator_info(Pool* pool);
 | 
			
		||||
void          clear(Pool* pool);
 | 
			
		||||
void          free(Pool* pool);
 | 
			
		||||
 | 
			
		||||
#if GEN_SUPPORT_CPP_REFERENCES
 | 
			
		||||
AllocatorInfo allocator_info(Pool& pool);
 | 
			
		||||
void          clear(Pool& pool);
 | 
			
		||||
void          free(Pool& pool);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
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 +410,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,15 +282,16 @@ 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;
 | 
			
		||||
	ADT_Node* node = & parent->nodes[index];
 | 
			
		||||
	return node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ADT_Node* adt_alloc( ADT_Node* parent )
 | 
			
		||||
@@ -303,7 +304,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 +358,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 +382,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 +390,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 +403,9 @@ 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 ) )
 | 
			
		||||
 | 
			
		||||
	ArrayHeader* node_header = get_header(parent->nodes);
 | 
			
		||||
	if ( adt_set_arr( o, name, node_header->Allocator ) )
 | 
			
		||||
	{
 | 
			
		||||
		adt_remove_node( o );
 | 
			
		||||
		return NULL;
 | 
			
		||||
@@ -447,7 +450,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 +479,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 +555,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 +751,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 +949,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 +982,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 +992,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 +1060,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;
 | 
			
		||||
 | 
			
		||||
@@ -1099,10 +1102,10 @@ String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delimi
 | 
			
		||||
	FileInfo tmp;
 | 
			
		||||
	file_stream_new( &tmp, a );
 | 
			
		||||
	csv_write_delimiter( &tmp, obj, delimiter );
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -83,7 +83,7 @@ struct ADT_Node
 | 
			
		||||
	union
 | 
			
		||||
	{
 | 
			
		||||
		char const*     string;
 | 
			
		||||
		Array<ADT_Node> nodes;    ///< zpl_array
 | 
			
		||||
		Array(ADT_Node) nodes;    ///< zpl_array
 | 
			
		||||
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -112,13 +125,29 @@
 | 
			
		||||
#		include <intrin.h>
 | 
			
		||||
#	endif
 | 
			
		||||
 | 
			
		||||
#if GEN_COMPILER_C
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#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 || GEN_COMPILER_C
 | 
			
		||||
#	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,572 @@ 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;
 | 
			
		||||
 | 
			
		||||
usize string_grow_formula(usize value);
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
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, String const 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
 | 
			
		||||
#if GEN_SUPPORT_CPP_REFERENCES
 | 
			
		||||
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, ...);
 | 
			
		||||
char&         back(String& str);
 | 
			
		||||
void          clear(String& str);
 | 
			
		||||
void          free(String& str);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
	GEN_ASSERT(str != nullptr);
 | 
			
		||||
	return append(str, &c, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
bool append(String* str, char const* str_to_append) {
 | 
			
		||||
	GEN_ASSERT(str != nullptr);
 | 
			
		||||
	return append(str, str_to_append, str_len(str_to_append));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
bool append(String* str, char const* str_to_append, ssize append_length)
 | 
			
		||||
{
 | 
			
		||||
	GEN_ASSERT(str != nullptr);
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
		char* Data = * str;
 | 
			
		||||
		mem_copy( Data + curr_len, str_to_append, append_length);
 | 
			
		||||
 | 
			
		||||
		Data[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) {
 | 
			
		||||
	GEN_ASSERT(str != nullptr);
 | 
			
		||||
	return append(str, str_to_append.Ptr, str_to_append.Len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
bool append(String* str, const String other) {
 | 
			
		||||
	GEN_ASSERT(str != nullptr);
 | 
			
		||||
	return append(str, other, length(other));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool append_fmt(String* str, char const* fmt, ...) {
 | 
			
		||||
	GEN_ASSERT(str != nullptr);
 | 
			
		||||
	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.Ptr[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)[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 + 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 + idx, substring, 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) {
 | 
			
		||||
	GEN_ASSERT(str != nullptr);
 | 
			
		||||
	if (! (* str))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	StringHeader* header = get_header(* str);
 | 
			
		||||
	GEN_NS free(header->Allocator, header);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline
 | 
			
		||||
StringHeader* get_header(String str) {
 | 
			
		||||
   return (StringHeader*)(scast(char*, str) - 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;
 | 
			
		||||
 | 
			
		||||
		char** Data = rcast(char**, 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;
 | 
			
		||||
   char* read_pos  = str;
 | 
			
		||||
 | 
			
		||||
   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,24 @@ 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 )
 | 
			
		||||
	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 +58,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 +68,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 +114,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 +124,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 +219,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 +238,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")
 | 
			
		||||
@@ -340,64 +343,22 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path )
 | 
			
		||||
 | 
			
		||||
CodeBody gen_ast_inlines()
 | 
			
		||||
{
 | 
			
		||||
#pragma push_macro("GEN_NS")
 | 
			
		||||
#pragma push_macro("rcast")
 | 
			
		||||
#pragma push_macro("log_failure")
 | 
			
		||||
#pragma push_macro("CodeInvalid")
 | 
			
		||||
#undef GEN_NS
 | 
			
		||||
#undef rcast
 | 
			
		||||
#undef log_failure
 | 
			
		||||
#undef CodeInvalid
 | 
			
		||||
	char const* code_impl_tmpl = stringize(
 | 
			
		||||
		\n
 | 
			
		||||
		inline
 | 
			
		||||
		char const* <typename>::debug_str()
 | 
			
		||||
		{
 | 
			
		||||
			if ( ast == nullptr )
 | 
			
		||||
				return "Code::debug_str: AST is null!";
 | 
			
		||||
 | 
			
		||||
			return rcast(AST*, ast)->debug_str();
 | 
			
		||||
		}
 | 
			
		||||
		inline
 | 
			
		||||
		Code <typename>::duplicate()
 | 
			
		||||
		{
 | 
			
		||||
			if ( ast == nullptr )
 | 
			
		||||
			{
 | 
			
		||||
				log_failure("Code::duplicate: Cannot duplicate code, AST is null!");
 | 
			
		||||
				return Code::Invalid;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return { rcast(AST*, ast)->duplicate() };
 | 
			
		||||
		}
 | 
			
		||||
		inline
 | 
			
		||||
		bool <typename>::is_equal( Code other )
 | 
			
		||||
		{
 | 
			
		||||
			if ( ast == nullptr || other.ast == nullptr )
 | 
			
		||||
			{
 | 
			
		||||
				// Just check if they're both null.
 | 
			
		||||
				// log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
 | 
			
		||||
				return ast == nullptr && other.ast == nullptr;
 | 
			
		||||
			}
 | 
			
		||||
			return rcast(AST*, ast)->is_equal( other.ast );
 | 
			
		||||
		}
 | 
			
		||||
		inline
 | 
			
		||||
		bool <typename>::is_valid()
 | 
			
		||||
		{
 | 
			
		||||
			return (AST*) ast != nullptr && rcast( AST*, ast)->Type != CodeT::Invalid;
 | 
			
		||||
		}
 | 
			
		||||
		inline
 | 
			
		||||
		void <typename>::set_global()
 | 
			
		||||
		{
 | 
			
		||||
			if ( ast == nullptr )
 | 
			
		||||
			{
 | 
			
		||||
				log_failure("Code::set_global: Cannot set code as global, AST is null!");
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			rcast(AST*, ast)->Parent = Code::Global.ast;
 | 
			
		||||
		}
 | 
			
		||||
		inline
 | 
			
		||||
		<typename>& <typename>::operator =( Code other )
 | 
			
		||||
		{
 | 
			
		||||
			if ( other.ast && other->Parent )
 | 
			
		||||
			{
 | 
			
		||||
				ast = rcast( decltype(ast), other.ast->duplicate() );
 | 
			
		||||
				ast = rcast( decltype(ast), GEN_NS duplicate(other.ast) );
 | 
			
		||||
				rcast( AST*, ast)->Parent = nullptr;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@@ -405,16 +366,6 @@ CodeBody gen_ast_inlines()
 | 
			
		||||
			return *this;
 | 
			
		||||
		}
 | 
			
		||||
		inline
 | 
			
		||||
		bool <typename>::operator ==( Code other )
 | 
			
		||||
		{
 | 
			
		||||
			return (AST*) ast == other.ast;
 | 
			
		||||
		}
 | 
			
		||||
		inline
 | 
			
		||||
		bool <typename>::operator !=( Code other )
 | 
			
		||||
		{
 | 
			
		||||
			return (AST*) ast != other.ast;
 | 
			
		||||
		}
 | 
			
		||||
		inline
 | 
			
		||||
		<typename>::operator bool()
 | 
			
		||||
		{
 | 
			
		||||
			return ast != nullptr;
 | 
			
		||||
@@ -444,6 +395,8 @@ CodeBody gen_ast_inlines()
 | 
			
		||||
		}
 | 
			
		||||
		\n
 | 
			
		||||
	);
 | 
			
		||||
#pragma pop_macro("GEN_NS")
 | 
			
		||||
#pragma pop_macro("CodeInvalid")
 | 
			
		||||
 | 
			
		||||
	CodeBody impl_code          = parse_global_body( token_fmt( "typename", StrC name(Code),               code_impl_tmpl ));
 | 
			
		||||
	CodeBody impl_code_body     = parse_global_body( token_fmt( "typename", StrC name(CodeBody),           code_impl_tmpl ));
 | 
			
		||||
@@ -475,29 +428,29 @@ CodeBody gen_ast_inlines()
 | 
			
		||||
	CodeBody impl_code_using    = parse_global_body( token_fmt( "typename", StrC name(CodeUsing),          code_impl_tmpl ));
 | 
			
		||||
	CodeBody impl_code_var      = parse_global_body( token_fmt( "typename", StrC name(CodeVar),            code_impl_tmpl ));
 | 
			
		||||
 | 
			
		||||
	impl_code_attr.    append( parse_global_body( token_fmt( "typename", StrC name(Attributes),     codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_cmt.     append( parse_global_body( token_fmt( "typename", StrC name(Comment),        codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_constr.  append( parse_global_body( token_fmt( "typename", StrC name(Constructor),    codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_define.  append( parse_global_body( token_fmt( "typename", StrC name(Define),         codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_destruct.append( parse_global_body( token_fmt( "typename", StrC name(Destructor),     codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_enum.    append( parse_global_body( token_fmt( "typename", StrC name(Enum),           codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_exec.    append( parse_global_body( token_fmt( "typename", StrC name(Exec),           codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_extern.  append( parse_global_body( token_fmt( "typename", StrC name(Extern),         codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_include. append( parse_global_body( token_fmt( "typename", StrC name(Include),        codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_friend.  append( parse_global_body( token_fmt( "typename", StrC name(Friend),         codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_fn.      append( parse_global_body( token_fmt( "typename", StrC name(Fn),             codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_module.  append( parse_global_body( token_fmt( "typename", StrC name(Module),         codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_ns.      append( parse_global_body( token_fmt( "typename", StrC name(NS),             codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_op.      append( parse_global_body( token_fmt( "typename", StrC name(Operator),       codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_opcast.  append( parse_global_body( token_fmt( "typename", StrC name(OpCast),         codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_pragma . append( parse_global_body( token_fmt( "typename", StrC name(Pragma),         codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_precond. append( parse_global_body( token_fmt( "typename", StrC name(PreprocessCond), codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_tmpl.    append( parse_global_body( token_fmt( "typename", StrC name(Template),       codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_type.    append( parse_global_body( token_fmt( "typename", StrC name(Type),           codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_typedef. append( parse_global_body( token_fmt( "typename", StrC name(Typedef),        codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_union.   append( parse_global_body( token_fmt( "typename", StrC name(Union),          codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_using.   append( parse_global_body( token_fmt( "typename", StrC name(Using),          codetype_impl_tmpl )));
 | 
			
		||||
	impl_code_var.     append( parse_global_body( token_fmt( "typename", StrC name(Var),            codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_attr,     parse_global_body( token_fmt( "typename", StrC name(Attributes),     codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_cmt,      parse_global_body( token_fmt( "typename", StrC name(Comment),        codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_constr,   parse_global_body( token_fmt( "typename", StrC name(Constructor),    codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_define,   parse_global_body( token_fmt( "typename", StrC name(Define),         codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_destruct, parse_global_body( token_fmt( "typename", StrC name(Destructor),     codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_enum,     parse_global_body( token_fmt( "typename", StrC name(Enum),           codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_exec,     parse_global_body( token_fmt( "typename", StrC name(Exec),           codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_extern,   parse_global_body( token_fmt( "typename", StrC name(Extern),         codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_include,  parse_global_body( token_fmt( "typename", StrC name(Include),        codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_friend,   parse_global_body( token_fmt( "typename", StrC name(Friend),         codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_fn,       parse_global_body( token_fmt( "typename", StrC name(Fn),             codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_module,   parse_global_body( token_fmt( "typename", StrC name(Module),         codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_ns,       parse_global_body( token_fmt( "typename", StrC name(NS),             codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_op,       parse_global_body( token_fmt( "typename", StrC name(Operator),       codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_opcast,   parse_global_body( token_fmt( "typename", StrC name(OpCast),         codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_pragma,   parse_global_body( token_fmt( "typename", StrC name(Pragma),         codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_precond,  parse_global_body( token_fmt( "typename", StrC name(PreprocessCond), codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_tmpl,     parse_global_body( token_fmt( "typename", StrC name(Template),       codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_type,     parse_global_body( token_fmt( "typename", StrC name(Type),           codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_typedef,  parse_global_body( token_fmt( "typename", StrC name(Typedef),        codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_union,    parse_global_body( token_fmt( "typename", StrC name(Union),          codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_using,    parse_global_body( token_fmt( "typename", StrC name(Using),          codetype_impl_tmpl )));
 | 
			
		||||
	append(impl_code_var,      parse_global_body( token_fmt( "typename", StrC name(Var),            codetype_impl_tmpl )));
 | 
			
		||||
 | 
			
		||||
	char const* cast_tmpl = stringize(
 | 
			
		||||
		inline	AST::operator Code<typename>()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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,68 @@ 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
 | 
			
		||||
 | 
			
		||||
	$unit       = join-path $path_c_library "gen.c"
 | 
			
		||||
	$executable = join-path $path_build     "gen_c_library_test.exe"
 | 
			
		||||
 | 
			
		||||
	if ($vendor -eq "clang") {
 | 
			
		||||
		$compiler_args += "-x"
 | 
			
		||||
		$compiler_args += "c"
 | 
			
		||||
	} elseif ($vendor -eq "msvc") {
 | 
			
		||||
		$compiler_args += "/TC"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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 test"
 | 
			
		||||
			$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