From a86a2cc77c4ac6bb9f117569f94ed5f9b157e4c2 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sat, 14 Dec 2024 08:02:47 -0500 Subject: [PATCH] update gencpp to latest Using this project to test latest ver... --- .vscode/settings.json | 22 +- project/codegen/engine_gen.cpp | 66 +- project/codegen/engine_postbuild_gen.cpp | 29 +- project/codegen/platform_gen.cpp | 27 +- project/dependencies/gen.hpp | 32067 +++++++++++--------- project/platform/win32/win32_platform.cpp | 4 +- 6 files changed, 17424 insertions(+), 14791 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a1c481c..20ea5fc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -84,5 +84,25 @@ "**/.vscode": true, "**/.vs": true, }, - "dimmer.enabled": true + "dimmer.enabled": false, + "workbench.colorCustomizations": { + "activityBar.activeBackground": "#ff6433", + "activityBar.background": "#ff6433", + "activityBar.foreground": "#15202b", + "activityBar.inactiveForeground": "#15202b99", + "activityBarBadge.background": "#00ff3d", + "activityBarBadge.foreground": "#15202b", + "commandCenter.border": "#e7e7e799", + "sash.hoverBorder": "#ff6433", + "statusBar.background": "#ff3d00", + "statusBar.foreground": "#e7e7e7", + "statusBarItem.hoverBackground": "#ff6433", + "statusBarItem.remoteBackground": "#ff3d00", + "statusBarItem.remoteForeground": "#e7e7e7", + "titleBar.activeBackground": "#ff3d00", + "titleBar.activeForeground": "#e7e7e7", + "titleBar.inactiveBackground": "#ff3d0099", + "titleBar.inactiveForeground": "#e7e7e799" + }, + "peacock.color": "#ff3d00" } diff --git a/project/codegen/engine_gen.cpp b/project/codegen/engine_gen.cpp index 1f3bc83..610b14a 100644 --- a/project/codegen/engine_gen.cpp +++ b/project/codegen/engine_gen.cpp @@ -14,7 +14,7 @@ #undef do_once #undef do_once_start #undef do_once_end -using namespace gen; +#undef cast #include "platform/platform_module.hpp" #include "platform/grime.hpp" @@ -23,7 +23,10 @@ using namespace gen; #include "platform/strings.hpp" #include "platform/platform.hpp" -constexpr StrC fname_vec_header = txt("vectors.hpp"); +using namespace gen; +using GStr = gen::Str; + +constexpr GStr fname_vec_header = txt("vectors.hpp"); #pragma push_macro("scast") #pragma push_macro("Zero") @@ -264,7 +267,7 @@ constexpr char const* vec2i_ops = stringize( #pragma pop_macro("Zero") #define gen_vec2f( vec_name, type ) gen__vec2f( txt( stringize(vec_name) ), txt( stringize(type) ) ) -CodeBody gen__vec2f( StrC vec_name, StrC type ) +CodeBody gen__vec2f( GStr vec_name, GStr type ) { CodeStruct vec_struct = parse_struct( token_fmt( "type", vec_name, "unit_type", type, stringize( struct @@ -290,7 +293,7 @@ CodeBody gen__vec2f( StrC vec_name, StrC type ) } #define gen_vec2i( vec_name, type ) gen__vec2i( txt( stringize(vec_name) ), txt( stringize(type) ) ) -CodeBody gen__vec2i( StrC vec_name, StrC type ) +CodeBody gen__vec2i( GStr vec_name, GStr type ) { CodeStruct vec_struct = parse_struct( token_fmt( "type", vec_name, "unit_type", type, stringize( struct @@ -316,14 +319,14 @@ CodeBody gen__vec2i( StrC vec_name, StrC type ) } #define gen_phys2( type ) gen__phys2( txt( stringize(type) ) ) -Code gen__phys2( StrC type ) +Code gen__phys2( GStr type ) { - String sym_vec = String::fmt_buf( GlobalAllocator, "Vec2_%s", type.Ptr ); - String sym_pos = String::fmt_buf( GlobalAllocator, "Pos2_%s", type.Ptr ); - String sym_dir = String::fmt_buf( GlobalAllocator, "Dir2_%s", type.Ptr); - String sym_dist = String::fmt_buf( GlobalAllocator, "Dist_%s", type.Ptr ); - String sym_vel = String::fmt_buf( GlobalAllocator, "Vel2_%s", type.Ptr ); - String sym_accel = String::fmt_buf( GlobalAllocator, "Accel2_%s", type.Ptr ); + StrBuilder sym_vec = StrBuilder::fmt_buf( _ctx->Allocator_Temp, "Vec2_%s", type.Ptr ); + StrBuilder sym_pos = StrBuilder::fmt_buf( _ctx->Allocator_Temp, "Pos2_%s", type.Ptr ); + StrBuilder sym_dir = StrBuilder::fmt_buf( _ctx->Allocator_Temp, "Dir2_%s", type.Ptr); + StrBuilder sym_dist = StrBuilder::fmt_buf( _ctx->Allocator_Temp, "Dist_%s", type.Ptr ); + StrBuilder sym_vel = StrBuilder::fmt_buf( _ctx->Allocator_Temp, "Vel2_%s", type.Ptr ); + StrBuilder sym_accel = StrBuilder::fmt_buf( _ctx->Allocator_Temp, "Accel2_%s", type.Ptr ); #pragma push_macro("pcast") #pragma push_macro("rcast") @@ -351,15 +354,15 @@ Code gen__phys2( StrC type ) return pcast( , vec ); } ); - CodeBody pos_struct = parse_global_body( token_fmt( "type", (StrC)sym_pos, "unit_type", type, "vec_type", (StrC)sym_vec, tmpl_struct )); - CodeBody pos_ops = parse_global_body( token_fmt( "type", (StrC)sym_pos, "unit_type", type, vec2f_ops )); + CodeBody pos_struct = parse_global_body( token_fmt( "type", (GStr)sym_pos, "unit_type", type, "vec_type", (GStr)sym_vec, tmpl_struct )); + CodeBody pos_ops = parse_global_body( token_fmt( "type", (GStr)sym_pos, "unit_type", type, vec2f_ops )); CodeBody dir_struct = parse_global_body( token_fmt( - "type", (StrC)sym_dir, + "type", (GStr)sym_dir, "unit_type", type, - "vec_type", (StrC)sym_vec, - "vel_type", (StrC)sym_vel, - "accel_type", (StrC)sym_accel, + "vec_type", (GStr)sym_vec, + "vel_type", (GStr)sym_vel, + "accel_type", (GStr)sym_accel, stringize( struct { @@ -396,10 +399,10 @@ Code gen__phys2( StrC type ) ))); CodeBody dist_def = parse_global_body( token_fmt( - "type", (StrC)sym_dist, + "type", (GStr)sym_dist, "unit_type", type, - "dist_type", (StrC)sym_dist, - "pos_type", (StrC)sym_pos, + "dist_type", (GStr)sym_dist, + "pos_type", (GStr)sym_pos, stringize( using = ; @@ -413,20 +416,20 @@ Code gen__phys2( StrC type ) } ))); - CodeBody vel_struct = parse_global_body( token_fmt( "type", (StrC)sym_vel, "unit_type", type, "vec_type", (StrC)sym_vec, tmpl_struct )); - CodeBody vel_ops = parse_global_body( token_fmt( "type", (StrC)sym_vel, "unit_type", type, vec2f_ops )); + CodeBody vel_struct = parse_global_body( token_fmt( "type", (GStr)sym_vel, "unit_type", type, "vec_type", (GStr)sym_vec, tmpl_struct )); + CodeBody vel_ops = parse_global_body( token_fmt( "type", (GStr)sym_vel, "unit_type", type, vec2f_ops )); - CodeBody accel_struct = parse_global_body( token_fmt( "type", (StrC)sym_accel, "unit_type", type, "vec_type", (StrC)sym_vec, tmpl_struct )); - CodeBody accel_ops = parse_global_body( token_fmt( "type", (StrC)sym_accel, "unit_type", type, vec2f_ops )); + CodeBody accel_struct = parse_global_body( token_fmt( "type", (GStr)sym_accel, "unit_type", type, "vec_type", (GStr)sym_vec, tmpl_struct )); + CodeBody accel_ops = parse_global_body( token_fmt( "type", (GStr)sym_accel, "unit_type", type, vec2f_ops )); // TODO(Ed): Is there a better name for this? Code ops = parse_global_body( token_fmt( - "unit_type", (StrC)type, - "vec_type", (StrC)sym_vec, - "pos_type", (StrC)sym_pos, - "dir_type", (StrC)sym_dir, - "vel_type", (StrC)sym_vel, - "accel_type", (StrC)sym_accel, + "unit_type", (GStr)type, + "vec_type", (GStr)sym_vec, + "pos_type", (GStr)sym_pos, + "dir_type", (GStr)sym_dir, + "vel_type", (GStr)sym_vel, + "accel_type", (GStr)sym_accel, stringize( inline velocity( a, b ) { @@ -508,7 +511,8 @@ Code gen__phys2( StrC type ) int gen_main() { - gen::init(); + gen::Context ctx {}; + gen::init( & ctx); log_fmt("Generating code for Handmade Hero: Engine Module\n"); CodeComment cmt_gen_notice = def_comment( txt("This was generated by project/codegen/engine_gen.cpp") ); diff --git a/project/codegen/engine_postbuild_gen.cpp b/project/codegen/engine_postbuild_gen.cpp index 383378c..f98ac37 100644 --- a/project/codegen/engine_postbuild_gen.cpp +++ b/project/codegen/engine_postbuild_gen.cpp @@ -15,7 +15,7 @@ #undef do_once_end #undef min #undef max -using namespace gen; +#undef cast #include @@ -37,9 +37,13 @@ using namespace gen; #include "engine/engine_to_platform_api.hpp" #include "engine/gen/physics.hpp" -constexpr StrC fname_handmade_engine_symbols = txt("handmade_engine.symbols"); +using namespace gen; -void get_symbols_from_module_table( FileContents symbol_table, Array symbols ) +using GStr = gen::Str; + +constexpr GStr fname_handmade_engine_symbols = txt("handmade_engine.symbols"); + +void get_symbols_from_module_table( FileContents symbol_table, Array symbols ) { struct Token { @@ -66,17 +70,18 @@ void get_symbols_from_module_table( FileContents symbol_table, Array sym ++ scanner; ++ token.Len; } - symbols.append( String::make_length( GlobalAllocator, token.Ptr, token.Len ) ); + symbols.append( StrBuilder::make_length( _ctx->Allocator_Temp, token.Ptr, token.Len ) ); } } } int gen_main() { - gen::init(); + gen::Context ctx {}; + gen::init( & ctx); log_fmt("Generating code for Handmade Hero: Engine Module (Post-Build)\n"); - FileContents symbol_table = file_read_contents( GlobalAllocator, true, fname_handmade_engine_symbols ); + FileContents symbol_table = file_read_contents( ctx.Allocator_Temp, true, fname_handmade_engine_symbols ); #pragma push_macro("str_ascii") #undef str_ascii @@ -86,24 +91,24 @@ int gen_main() builder.print( fmt_newline ); builder.print_fmt( "NS_ENGINE_BEGIN\n\n" ); - Array symbols = Array::init_reserve( GlobalAllocator, kilobytes(1) ); + Array symbols = Array::init_reserve( ctx.Allocator_Temp, kilobytes(1) ); get_symbols_from_module_table( symbol_table, symbols ); using ModuleAPI = engine::ModuleAPI; - builder.print( parse_variable( token_fmt( "symbol", (StrC)symbols[ModuleAPI::Sym_OnModuleReload], stringize( + builder.print( parse_variable( token_fmt( "symbol", (GStr)symbols[ModuleAPI::Sym_OnModuleReload], stringize( constexpr const Str symbol_on_module_load = str_ascii(""); )))); - builder.print( parse_variable( token_fmt( "symbol", (StrC)symbols[ModuleAPI::Sym_Startup], stringize( + builder.print( parse_variable( token_fmt( "symbol", (GStr)symbols[ModuleAPI::Sym_Startup], stringize( constexpr const Str symbol_startup = str_ascii(""); )))); - builder.print( parse_variable( token_fmt( "symbol", (StrC)symbols[ModuleAPI::Sym_Shutdown], stringize( + builder.print( parse_variable( token_fmt( "symbol", (GStr)symbols[ModuleAPI::Sym_Shutdown], stringize( constexpr const Str symbol_shutdown = str_ascii(""); )))); - builder.print( parse_variable( token_fmt( "symbol", (StrC)symbols[ModuleAPI::Sym_UpdateAndRender], stringize( + builder.print( parse_variable( token_fmt( "symbol", (GStr)symbols[ModuleAPI::Sym_UpdateAndRender], stringize( constexpr const Str symbol_update_and_render = str_ascii(""); )))); - builder.print( parse_variable( token_fmt( "symbol", (StrC)symbols[ModuleAPI::Sym_UpdateAudio], stringize( + builder.print( parse_variable( token_fmt( "symbol", (GStr)symbols[ModuleAPI::Sym_UpdateAudio], stringize( constexpr const Str symbol_update_audio = str_ascii(""); )))); diff --git a/project/codegen/platform_gen.cpp b/project/codegen/platform_gen.cpp index 83962db..de1dc04 100644 --- a/project/codegen/platform_gen.cpp +++ b/project/codegen/platform_gen.cpp @@ -6,14 +6,17 @@ #include "dependencies/gen.hpp" #undef min #undef max -using namespace gen; +#undef cast #define path_gen "./gen/" +using namespace gen; +using GStr = gen::Str; int gen_main() { - gen::init(); + gen::Context ctx {}; + gen::init( & ctx); log_fmt("Generating code for Handmade Hero: Platform Module\n"); CodeComment generation_notice = def_comment( txt("This was generated by project/codegen/platform_gen.cpp") ); @@ -22,15 +25,15 @@ int gen_main() builder.print( generation_notice ); builder.print( fmt_newline ); - FileContents h_context = file_read_contents(GlobalAllocator, true, "context.hpp"); - CodeBody code_context = parse_global_body( { h_context.size, rcast( char const*, h_context.data ) } ); + FileContents h_context = file_read_contents(ctx.Allocator_Temp, true, "context.hpp"); + CodeBody code_context = parse_global_body( { rcast( char const*, h_context.data ), h_context.size } ); CodeStruct context_struct = {}; for ( Code code : code_context ) { - if ( code->Type == ECode::Struct ) + if ( code->Type == CT_Struct ) { - if ( str_compare( code->Name, txt("Context") ) == 0 ) + if ( code->Name.is_equal(txt("Context")) ) { context_struct = code; break; @@ -39,10 +42,10 @@ int gen_main() } } - Array context_data_members = Array::init_reserve( GlobalAllocator, kilobytes( 1 ) ); + Array context_data_members = Array::init_reserve( ctx.Allocator_Temp, kilobytes( 1 ) ); for ( Code code : context_struct->Body ) { - if ( code->Type == ECode::Variable ) + if ( code->Type == CT_Variable ) { context_data_members.append( code ); } @@ -50,22 +53,22 @@ int gen_main() CodeDefine using_context; { - String using_context_content = String::make_reserve( GlobalAllocator, kilobytes( 1 ) ); + StrBuilder using_context_content = StrBuilder::make_reserve( ctx.Allocator_Temp, kilobytes( 1 ) ); { - String + StrBuilder content = using_context_content; content.append( "\\\n" ); for ( s32 id = 0; id < context_data_members.num() - 1; ++id ) { Code code = context_data_members[ id ]; - content.append( code.to_string() ); + content.append( code.to_strbuilder() ); // Default serializer inserts a newline at the end of the string, we need to insert a line continuation content[ content.length() - 1 ] = '\\'; content.append( "\n" ); } - content.append( context_data_members[ context_data_members.num() - 1 ]->to_string() ); + content.append( context_data_members[ context_data_members.num() - 1 ].to_strbuilder() ); } using_context = def_define( txt("using_context()"), using_context_content ); } diff --git a/project/dependencies/gen.hpp b/project/dependencies/gen.hpp index a0e43bc..879b462 100644 --- a/project/dependencies/gen.hpp +++ b/project/dependencies/gen.hpp @@ -2,540 +2,528 @@ #pragma once -#if __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-const-variable" -#pragma clang diagnostic ignored "-Wswitch" -#pragma clang diagnostic ignored "-Wunused-variable" -#pragma clang diagnostic ignored "-Wunknown-pragmas" -#pragma clang diagnostic ignored "-Wvarargs" -#pragma clang diagnostic ignored "-Wunused-function" +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-const-variable" +# pragma clang diagnostic ignored "-Wunused-but-set-variable" +# pragma clang diagnostic ignored "-Wswitch" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic ignored "-Wunknown-pragmas" +# pragma clang diagnostic ignored "-Wvarargs" +# pragma clang diagnostic ignored "-Wunused-function" +# pragma clang diagnostic ignored "-Wbraced-scalar-init" +# pragma clang diagnostic ignored "-W#pragma-messages" +# pragma clang diagnostic ignored "-Wstatic-in-inline" #endif -#if __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunknown-pragmas" -#pragma GCC diagnostic ignored "-Wcomment" -#pragma GCC diagnostic ignored "-Wswitch" -#pragma GCC diagnostic ignored "-Wunused-variable" +#ifdef __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunknown-pragmas" +# pragma GCC diagnostic ignored "-Wcomment" +# pragma GCC diagnostic ignored "-Wswitch" +# pragma GCC diagnostic ignored "-Wunused-variable" #endif /* - gencpp: An attempt at "simple" staged metaprogramming for c/c++. + gencpp: An attempt at "simple" staged metaprogramming for c/c++. - See Readme.md for more information from the project repository. + See Readme.md for more information from the project repository. - Public Address: - https://github.com/Ed94/gencpp + Define GEN_IMPLEMENTATION before including this file in a single compilation unit. - This is a single header variant of the library. - Define GEN_IMPLEMENTATION before including this file in a single compilation unit. + Public Address: + https://github.com/Ed94/gencpp --------------------------------------------------------------. + | _____ _____ _ _ | + | / ____) / ____} | | | | + | | / ___ ___ _ __ ___ _ __ _ __ | {___ | |__ _ _, __ _, ___ __| | | + | | |{_ |/ _ \ '_ \ / __} '_ l| '_ l `\___ \| __/ _` |/ _` |/ _ \/ _` | | + | | l__j | ___/ | | | {__; |+l } |+l | ____) | l| (_| | {_| | ___/ (_| | | + | \_____|\___}_l |_|\___} ,__/| ,__/ (_____/ \__\__/_|\__, |\___}\__,_l | + | Singleheader | | | | __} | | + | l_l l_l {___/ | + ! ----------------------------------------------------------------------- VERSION: v0.20-Alpha | + ! ============================================================================================ | + ! WARNING: THIS IS AN ALPHA VERSION OF THE LIBRARY, USE AT YOUR OWN DISCRETION | + ! NEVER DO CODE GENERATION WITHOUT AT LEAST HAVING CONTENT IN A CODEBASE UNDER VERSION CONTROL | + ! ============================================================================================ / */ -#if ! defined( GEN_DONT_ENFORCE_GEN_TIME_GUARD ) && ! defined( GEN_TIME ) -#error Gen.hpp : GEN_TIME not defined +#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 - - //! 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 -#pragma once - #pragma region Platform Detection /* Platform architecture */ -#if defined( _WIN64 ) || defined( __x86_64__ ) || defined( _M_X64 ) || defined( __64BIT__ ) || defined( __powerpc64__ ) || defined( __ppc64__ ) \ - || defined( __aarch64__ ) -#ifndef GEN_ARCH_64_BIT -#define GEN_ARCH_64_BIT 1 -#endif +#if defined( _WIN64 ) || defined( __x86_64__ ) || defined( _M_X64 ) || defined( __64BIT__ ) || defined( __powerpc64__ ) || defined( __ppc64__ ) || defined( __aarch64__ ) +# ifndef GEN_ARCH_64_BIT +# define GEN_ARCH_64_BIT 1 +# endif #else -#ifndef GEN_ARCH_32_BItxt_StrCaT -#define GEN_ARCH_32_BIT 1 -#endif +# ifndef GEN_ARCH_32_BItxt_StrCaT +# define GEN_ARCH_32_BIT 1 +# endif #endif /* Platform OS */ #if defined( _WIN32 ) || defined( _WIN64 ) -#ifndef GEN_SYSTEM_WINDOWS -#define GEN_SYSTEM_WINDOWS 1 -#endif +# ifndef GEN_SYSTEM_WINDOWS +# define GEN_SYSTEM_WINDOWS 1 +# endif #elif defined( __APPLE__ ) && defined( __MACH__ ) -#ifndef GEN_SYSTEM_OSX -#define GEN_SYSTEM_OSX 1 -#endif -#ifndef GEN_SYSTEM_MACOS -#define GEN_SYSTEM_MACOS 1 -#endif -#include -#if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1 -#ifndef GEN_SYSTEM_IOS -#define GEN_SYSTEM_IOS 1 -#endif -#endif +# ifndef GEN_SYSTEM_OSX +# define GEN_SYSTEM_OSX 1 +# endif +# ifndef GEN_SYSTEM_MACOS +# define GEN_SYSTEM_MACOS 1 +# endif #elif defined( __unix__ ) -#ifndef GEN_SYSTEM_UNIX -#define GEN_SYSTEM_UNIX 1 -#endif -#if defined( ANDROID ) || defined( __ANDROID__ ) -#ifndef GEN_SYSTEM_ANDROID -#define GEN_SYSTEM_ANDROID 1 -#endif -#ifndef GEN_SYSTEM_LINUX -#define GEN_SYSTEM_LINUX 1 -#endif -#elif defined( __linux__ ) -#ifndef GEN_SYSTEM_LINUX -#define GEN_SYSTEM_LINUX 1 -#endif -#elif defined( __FreeBSD__ ) || defined( __FreeBSD_kernel__ ) -#ifndef GEN_SYSTEM_FREEBSD -#define GEN_SYSTEM_FREEBSD 1 -#endif -#elif defined( __OpenBSD__ ) -#ifndef GEN_SYSTEM_OPENBSD -#define GEN_SYSTEM_OPENBSD 1 -#endif -#elif defined( __EMSCRIPTEN__ ) -#ifndef GEN_SYSTEM_EMSCRIPTEN -#define GEN_SYSTEM_EMSCRIPTEN 1 -#endif -#elif defined( __CYGWIN__ ) -#ifndef GEN_SYSTEM_CYGWIN -#define GEN_SYSTEM_CYGWIN 1 -#endif +# ifndef GEN_SYSTEM_UNIX +# define GEN_SYSTEM_UNIX 1 +# endif +# if defined( ANDROID ) || defined( __ANDROID__ ) +# ifndef GEN_SYSTEM_ANDROID +# define GEN_SYSTEM_ANDROID 1 +# endif +# ifndef GEN_SYSTEM_LINUX +# define GEN_SYSTEM_LINUX 1 +# endif +# elif defined( __linux__ ) +# ifndef GEN_SYSTEM_LINUX +# define GEN_SYSTEM_LINUX 1 +# endif +# elif defined( __FreeBSD__ ) || defined( __FreeBSD_kernel__ ) +# ifndef GEN_SYSTEM_FREEBSD +# define GEN_SYSTEM_FREEBSD 1 +# endif +# elif defined( __OpenBSD__ ) +# ifndef GEN_SYSTEM_OPENBSD +# define GEN_SYSTEM_OPENBSD 1 +# endif +# elif defined( __EMSCRIPTEN__ ) +# ifndef GEN_SYSTEM_EMSCRIPTEN +# define GEN_SYSTEM_EMSCRIPTEN 1 +# endif +# elif defined( __CYGWIN__ ) +# ifndef GEN_SYSTEM_CYGWIN +# define GEN_SYSTEM_CYGWIN 1 +# endif +# else +# error This UNIX operating system is not supported +# endif #else -#error This UNIX operating system is not supported -#endif -#else -#error This operating system is not supported +# error This operating system is not supported #endif /* Platform compiler */ #if defined( _MSC_VER ) -#define GEN_COMPILER_MSVC 1 +# pragma message("Detected MSVC") +// # define GEN_COMPILER_CLANG 0 +# define GEN_COMPILER_MSVC 1 +// # define GEN_COMPILER_GCC 0 #elif defined( __GNUC__ ) -#define GEN_COMPILER_GCC 1 +# pragma message("Detected GCC") +// # 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 -#error Unknown compiler +# pragma message("Detected CLANG") +# define GEN_COMPILER_CLANG 1 +// # define GEN_COMPILER_MSVC 0 +// # define GEN_COMPILER_GCC 0 +#else +# error Unknown compiler #endif #if defined( __has_attribute ) -#define GEN_HAS_ATTRIBUTE( attribute ) __has_attribute( attribute ) +# define GEN_HAS_ATTRIBUTE( attribute ) __has_attribute( attribute ) #else -#define GEN_HAS_ATTRIBUTE( attribute ) ( 0 ) +# define GEN_HAS_ATTRIBUTE( attribute ) ( 0 ) #endif -#if defined( GEN_GCC_VERSION_CHECK ) -#undef GEN_GCC_VERSION_CHECK +#if defined(GEN_GCC_VERSION_CHECK) +# undef GEN_GCC_VERSION_CHECK #endif -#if defined( GEN_GCC_VERSION ) -#define GEN_GCC_VERSION_CHECK( major, minor, patch ) ( GEN_GCC_VERSION >= GEN_VERSION_ENCODE( major, minor, patch ) ) +#if defined(GEN_GCC_VERSION) +# define GEN_GCC_VERSION_CHECK(major,minor,patch) (GEN_GCC_VERSION >= GEN_VERSION_ENCODE(major, minor, patch)) #else -#define GEN_GCC_VERSION_CHECK( major, minor, patch ) ( 0 ) +# define GEN_GCC_VERSION_CHECK(major,minor,patch) (0) #endif -#define GEN_DEF_INLINE static -#define GEN_IMPL_INLINE static inline +#if !defined(GEN_COMPILER_C) +# ifdef __cplusplus +# define GEN_COMPILER_C 0 +# define GEN_COMPILER_CPP 1 +# else +# if defined(__STDC__) +# define GEN_COMPILER_C 1 +# define GEN_COMPILER_CPP 0 +# else + // Fallback for very old C compilers +# define GEN_COMPILER_C 1 +# define GEN_COMPILER_CPP 0 +# endif +# endif +#endif + +#if GEN_COMPILER_C +#pragma message("GENCPP: Detected C") +#endif #pragma endregion Platform Detection #pragma region Mandatory Includes -#include -#include +# include +# include -#if defined( GEN_SYSTEM_WINDOWS ) -#include +# if defined( GEN_SYSTEM_WINDOWS ) +# include +# endif + +#if GEN_COMPILER_C +#include +#include #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 +# define GEN_NS_BEGIN +# define GEN_NS_END +# else +# define GEN_NS :: +# define GEN_NS_BEGIN +# define GEN_NS_END +# endif #else -#define GEN_NS gen:: -#define GEN_NS_BEGIN \ - namespace gen \ - { -#define GEN_NS_END } +# define GEN_NS gen:: +# define GEN_NS_BEGIN namespace gen { +# define GEN_NS_END } #endif GEN_NS_BEGIN #pragma region Macros -#define zpl_cast( Type ) ( Type ) - -// Keywords +#if GEN_COMPILER_MSVC + #ifdef GEN_DYN_LINK + #ifdef GEN_DYN_EXPORT + #define GEN_API __declspec(dllexport) + #else + #define GEN_API __declspec(dllimport) + #endif + #else + #define GEN_API // Empty for static builds + #endif +#else + #ifdef GEN_DYN_LINK + #define GEN_API __attribute__((visibility("default"))) + #else + #define GEN_API // Empty for static builds + #endif +#endif +#ifndef global #define global static // Global variables +#endif +#ifndef internal #define internal static // Internal linkage +#endif +#ifndef local_persist #define local_persist static // Local Persisting variables - -#ifdef GEN_COMPILER_MSVC -#define forceinline __forceinline -#define neverinline __declspec( noinline ) -#elif defined( GEN_COMPILER_GCC ) -#define forceinline inline __attribute__( ( __always_inline__ ) ) -#define neverinline __attribute__( ( __noinline__ ) ) -#elif defined( GEN_COMPILER_CLANG ) -#if __has_attribute( __always_inline__ ) -#define forceinline inline __attribute__( ( __always_inline__ ) ) -#define neverinline __attribute__( ( __noinline__ ) ) -#else -#define forceinline -#define neverinline -#endif -#else -#define forceinline -#define neverinline #endif -// Bits +#ifndef bit +#define bit( Value ) ( 1 << Value ) +#define bitfield_is_equal( Type, Field, Mask ) ( (scast(Type, Mask) & scast(Type, Field)) == scast(Type, Mask) ) +#endif -#define bit( Value ) ( 1 << Value ) -#define bitfield_is_equal( Type, Field, Mask ) ( ( Type( Mask ) & Type( Field ) ) == Type( Mask ) ) +// Mainly intended for forcing the base library to utilize only C-valid constructs or type coercion +#ifndef GEN_C_LIKE_CPP +#define GEN_C_LIKE_CPP 0 +#endif -// Casting +#if GEN_COMPILER_CPP +# ifndef cast +# define cast( type, value ) (tmpl_cast( value )) +# endif +#else +# ifndef cast +# define cast( type, value ) ( (type)(value) ) +# endif +#endif -#define ccast( Type, Value ) ( *const_cast< Type* >( &( Value ) ) ) -#define pcast( Type, Value ) ( *reinterpret_cast< Type* >( &( Value ) ) ) -#define rcast( Type, Value ) reinterpret_cast< Type >( Value ) -#define scast( Type, Value ) static_cast< Type >( Value ) +#if GEN_COMPILER_CPP +# ifndef ccast +# define ccast( type, value ) ( const_cast< type >( (value) ) ) +# endif +# ifndef pcast +# define pcast( type, value ) ( * reinterpret_cast< type* >( & ( value ) ) ) +# endif +# ifndef rcast +# define rcast( type, value ) reinterpret_cast< type >( value ) +# endif +# ifndef scast +# define scast( type, value ) static_cast< type >( value ) +# endif +#else +# ifndef ccast +# define ccast( type, value ) ( (type)(value) ) +# endif +# ifndef pcast +# define pcast( type, value ) ( * (type*)(& value) ) +# endif +# ifndef rcast +# define rcast( type, value ) ( (type)(value) ) +# endif +# ifndef scast +# define scast( type, value ) ( (type)(value) ) +# endif +#endif -// Num Arguments (Varadics) -// #if defined(__GNUC__) || defined(__clang__) -// Supports 0-50 arguments -#define num_args_impl( \ - _0, \ - _1, \ - _2, \ - _3, \ - _4, \ - _5, \ - _6, \ - _7, \ - _8, \ - _9, \ - _10, \ - _11, \ - _12, \ - _13, \ - _14, \ - _15, \ - _16, \ - _17, \ - _18, \ - _19, \ - _20, \ - _21, \ - _22, \ - _23, \ - _24, \ - _25, \ - _26, \ - _27, \ - _28, \ - _29, \ - _30, \ - _31, \ - _32, \ - _33, \ - _34, \ - _35, \ - _36, \ - _37, \ - _38, \ - _39, \ - _40, \ - _41, \ - _42, \ - _43, \ - _44, \ - _45, \ - _46, \ - _47, \ - _48, \ - _49, \ - _50, \ - _51, \ - _52, \ - _53, \ - _54, \ - _55, \ - _56, \ - _57, \ - _58, \ - _59, \ - _60, \ - _61, \ - _62, \ - _63, \ - _64, \ - _65, \ - _66, \ - _67, \ - _68, \ - _69, \ - _70, \ - _71, \ - _72, \ - _73, \ - _74, \ - _75, \ - _76, \ - _77, \ - _78, \ - _79, \ - _80, \ - _81, \ - _82, \ - _83, \ - _84, \ - _85, \ - _86, \ - _87, \ - _88, \ - _89, \ - _90, \ - _91, \ - _92, \ - _93, \ - _94, \ - _95, \ - _96, \ - _97, \ - _98, \ - _99, \ - _100, \ - N, \ - ... \ -) \ - N - -// ## deletes preceding comma if _VA_ARGS__ is empty (GCC, Clang) -#define num_args( ... ) \ - num_args_impl( \ - _, \ - ##__VA_ARGS__, \ - 100, \ - 99, \ - 98, \ - 97, \ - 96, \ - 95, \ - 94, \ - 93, \ - 92, \ - 91, \ - 90, \ - 89, \ - 88, \ - 87, \ - 86, \ - 85, \ - 84, \ - 83, \ - 82, \ - 81, \ - 80, \ - 79, \ - 78, \ - 77, \ - 76, \ - 75, \ - 74, \ - 73, \ - 72, \ - 71, \ - 70, \ - 69, \ - 68, \ - 67, \ - 66, \ - 65, \ - 64, \ - 63, \ - 62, \ - 61, \ - 60, \ - 59, \ - 58, \ - 57, \ - 56, \ - 55, \ - 54, \ - 53, \ - 52, \ - 51, \ - 50, \ - 49, \ - 48, \ - 47, \ - 46, \ - 45, \ - 44, \ - 43, \ - 42, \ - 41, \ - 40, \ - 39, \ - 38, \ - 37, \ - 36, \ - 35, \ - 34, \ - 33, \ - 32, \ - 31, \ - 30, \ - 29, \ - 28, \ - 27, \ - 26, \ - 25, \ - 24, \ - 23, \ - 22, \ - 21, \ - 20, \ - 19, \ - 18, \ - 17, \ - 16, \ - 15, \ - 14, \ - 13, \ - 12, \ - 11, \ - 10, \ - 9, \ - 8, \ - 7, \ - 6, \ - 5, \ - 4, \ - 3, \ - 2, \ - 1, \ - 0 \ - ) - -// #else -// This doesn't work on latest msvc so I had to use /Zc:preprocessor flag. - -// Supports 1-50 arguments -// #define num_args_impl( \ -// _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ -// _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ -// _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ -// _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ -// _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ -// _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ -// _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, \ -// _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, \ -// _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, \ -// _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, \ -// N, ... \ -// ) N - -// #define num_args(...) \ -// num_args_impl( __VA_ARGS__, \ -// 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, \ -// 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, \ -// 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, \ -// 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, \ -// 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, \ -// 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \ -// 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \ -// 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \ -// 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \ -// 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ -// 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 \ -// ) -// #endif - -// Stringizing +#ifndef stringize #define stringize_va( ... ) #__VA_ARGS__ #define stringize( ... ) stringize_va( __VA_ARGS__ ) - -// Function do once - -#define do_once() \ - do \ - { \ - static bool Done = false; \ - if ( Done ) \ - return; \ - Done = true; \ - } while ( 0 ) - -#define do_once_start \ - do \ - { \ - static bool Done = false; \ - if ( Done ) \ - break; \ - Done = true; - -#define do_once_end \ - } \ - while ( 0 ) \ - ; - -#define labeled_scope_start \ - if ( false ) \ - { -#define labeled_scope_end } - -#define clamp( x, lower, upper ) min( max( ( x ), ( lower ) ), ( upper ) ) -#define count_of( x ) ( ( size_of( x ) / size_of( 0 [ x ] ) ) / ( ( sw )( ! ( size_of( x ) % size_of( 0 [ x ] ) ) ) ) ) -#define is_between( x, lower, upper ) ( ( ( lower ) <= ( x ) ) && ( ( x ) <= ( upper ) ) ) -#define max( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) ) -#define min( a, b ) ( ( a ) < ( b ) ? ( a ) : ( b ) ) -#define size_of( x ) ( sw )( sizeof( x ) ) - -#if defined( _MSC_VER ) || defined( GEN_COMPILER_TINYC ) -#define offset_of( Type, element ) ( ( GEN_NS( gen_sw ) ) & ( ( ( Type* )0 )->element ) ) -#else -#define offset_of( Type, element ) __builtin_offsetof( Type, element ) #endif -template< class Type > -void swap( Type& a, Type& b ) -{ - Type tmp = a; - a = b; - b = tmp; -} +#ifndef do_once +#define do_once() \ + static int __do_once_counter_##__LINE__ = 0; \ + for(; __do_once_counter_##__LINE__ != 1; __do_once_counter_##__LINE__ = 1 ) \ + +#define do_once_defer( expression ) \ + static int __do_once_counter_##__LINE__ = 0; \ + for(; __do_once_counter_##__LINE__ != 1; __do_once_counter_##__LINE__ = 1, (expression)) \ + +#define do_once_start \ + do \ + { \ + local_persist \ + bool done = false; \ + if ( done ) \ + break; \ + done = true; + +#define do_once_end \ + } \ + while(0); +#endif + +#ifndef labeled_scope_start +#define labeled_scope_start if ( false ) { +#define labeled_scope_end } +#endif + +#ifndef compiler_decorated_func_name +# ifdef COMPILER_CLANG +# define compiler_decorated_func_name __PRETTY_NAME__ +# elif defined(COMPILER_MSVC) +# define compiler_decorated_func_name __FUNCDNAME__ +# endif +#endif + +#ifndef num_args_impl + +// This is essentially an arg couneter version of GEN_SELECT_ARG macros +// See section : _Generic function overloading for that usage (explains this heavier case) + +#define num_args_impl( _0, \ + _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ + _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ + _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ + _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ + _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ + _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, \ + _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, \ + _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, \ + _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, \ + N, ... \ + ) N + +// ## deletes preceding comma if _VA_ARGS__ is empty (GCC, Clang) +#define num_args(...) \ + num_args_impl(_, ## __VA_ARGS__, \ + 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, \ + 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, \ + 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, \ + 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, \ + 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, \ + 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \ + 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \ + 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \ + 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ + 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, \ + 0 \ + ) +#endif + +#ifndef clamp +#define clamp( x, lower, upper ) min( max( ( x ), ( lower ) ), ( upper ) ) +#endif +#ifndef count_of +#define count_of( x ) ( ( size_of( x ) / size_of( 0 [ x ] ) ) / ( ( ssize )( ! ( size_of( x ) % size_of( 0 [ x ] ) ) ) ) ) +#endif +#ifndef is_between +#define is_between( x, lower, upper ) ( ( ( lower ) <= ( x ) ) && ( ( x ) <= ( upper ) ) ) +#endif +#ifndef size_of +#define size_of( x ) ( ssize )( sizeof( x ) ) +#endif + +#ifndef max +#define max( a, b ) ( (a > b) ? (a) : (b) ) +#endif +#ifndef min +#define min( a, b ) ( (a < b) ? (a) : (b) ) +#endif + +#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 +# if GEN_COMPILER_MSVC +# define forceinline __forceinline +# define neverinline __declspec( noinline ) +# elif GEN_COMPILER_GCC +# define forceinline inline __attribute__((__always_inline__)) +# define neverinline __attribute__( ( __noinline__ ) ) +# elif GEN_COMPILER_CLANG +# if __has_attribute(__always_inline__) +# define forceinline inline __attribute__((__always_inline__)) +# define neverinline __attribute__( ( __noinline__ ) ) +# else +# define forceinline +# define neverinline +# endif +# else +# define forceinline +# define neverinline +# endif +#endif + +#ifndef neverinline +# if GEN_COMPILER_MSVC +# define neverinline __declspec( noinline ) +# elif GEN_COMPILER_GCC +# define neverinline __attribute__( ( __noinline__ ) ) +# elif GEN_COMPILER_CLANG +# if __has_attribute(__always_inline__) +# define neverinline __attribute__( ( __noinline__ ) ) +# else +# define neverinline +# endif +# else +# define neverinline +# endif +#endif + +#if GEN_COMPILER_C +#ifndef static_assert +#undef static_assert + #if GEN_COMPILER_C && __STDC_VERSION__ >= 201112L + #define static_assert(condition, message) _Static_assert(condition, message) + #else + #define static_assert(condition, message) typedef char static_assertion_##__LINE__[(condition)?1:-1] + #endif +#endif +#endif + +#if GEN_COMPILER_CPP +// Already Defined +#elif GEN_COMPILER_C && __STDC_VERSION__ >= 201112L +# define thread_local _Thread_local +#elif GEN_COMPILER_MSVC +# define thread_local __declspec(thread) +#elif GEN_COMPILER_CLANG +# define thread_local __thread +#else +# error "No thread local support" +#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 + +#ifndef GEN_API_C_BEGIN +# if GEN_COMPILER_C +# define GEN_API_C_BEGIN +# define GEN_API_C_END +# else +# define GEN_API_C_BEGIN extern "C" { +# define GEN_API_C_END } +# endif +#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 + +# ifndef GEN_REMOVE_PTR +# define GEN_REMOVE_PTR(type) typeof(* ( (type) NULL) ) +# endif +#endif + +#if ! defined(GEN_PARAM_DEFAULT) && GEN_COMPILER_CPP +# define GEN_PARAM_DEFAULT = {} +#else +# define GEN_PARAM_DEFAULT +#endif + +#if GEN_COMPILER_CPP + #define struct_init(type, value) {value} +#else + #define struct_init(type, value) {value} +#endif + +#if 0 +#ifndef GEN_OPTIMIZE_MAPPINGS_BEGIN +# define GEN_OPTIMIZE_MAPPINGS_BEGIN _pragma(optimize("gt", on)) +# define GEN_OPITMIZE_MAPPINGS_END _pragma(optimize("", on)) +#endif +#else +# define GEN_OPTIMIZE_MAPPINGS_BEGIN +# define GEN_OPITMIZE_MAPPINGS_END +#endif #pragma endregion Macros #pragma region Basic Types -#define GEN_U8_MIN 0u -#define GEN_U8_MAX 0xffu -#define GEN_I8_MIN ( -0x7f - 1 ) -#define GEN_I8_MAX 0x7f +#define GEN_U8_MIN 0u +#define GEN_U8_MAX 0xffu +#define GEN_I8_MIN ( -0x7f - 1 ) +#define GEN_I8_MAX 0x7f #define GEN_U16_MIN 0u #define GEN_U16_MAX 0xffffu @@ -553,17 +541,17 @@ void swap( Type& a, Type& b ) #define GEN_I64_MAX 0x7fffffffffffffffll #if defined( GEN_ARCH_32_BIT ) -#define GEN_USIZE_MIN GEN_U32_MIN -#define GEN_USIZE_MAX GEN_U32_MAX -#define GEN_ISIZE_MIN GEN_S32_MIN -#define GEN_ISIZE_MAX GEN_S32_MAX +# define GEN_USIZE_MIN GEN_U32_MIN +# define GEN_USIZE_MAX GEN_U32_MAX +# define GEN_ISIZE_MIN GEN_S32_MIN +# define GEN_ISIZE_MAX GEN_S32_MAX #elif defined( GEN_ARCH_64_BIT ) -#define GEN_USIZE_MIN GEN_U64_MIN -#define GEN_USIZE_MAX GEN_U64_MAX -#define GEN_ISIZE_MIN GEN_I64_MIN -#define GEN_ISIZE_MAX GEN_I64_MAX +# define GEN_USIZE_MIN GEN_U64_MIN +# define GEN_USIZE_MAX GEN_U64_MAX +# define GEN_ISIZE_MIN GEN_I64_MIN +# define GEN_ISIZE_MAX GEN_I64_MAX #else -#error Unknown architecture size. This library only supports 32 bit and 64 bit architectures. +# error Unknown architecture size. This library only supports 32 bit and 64 bit architectures. #endif #define GEN_F32_MIN 1.17549435e-38f @@ -572,25 +560,25 @@ void swap( Type& a, Type& b ) #define GEN_F64_MAX 1.7976931348623157e+308 #if defined( GEN_COMPILER_MSVC ) -#if _MSC_VER < 1300 +# if _MSC_VER < 1300 typedef unsigned char u8; -typedef signed char s8; +typedef signed char s8; typedef unsigned short u16; -typedef signed short s16; +typedef signed short s16; typedef unsigned int u32; -typedef signed int s32; -#else +typedef signed int s32; +# else typedef unsigned __int8 u8; -typedef signed __int8 s8; +typedef signed __int8 s8; typedef unsigned __int16 u16; -typedef signed __int16 s16; +typedef signed __int16 s16; typedef unsigned __int32 u32; -typedef signed __int32 s32; -#endif +typedef signed __int32 s32; +# endif typedef unsigned __int64 u64; -typedef signed __int64 s64; +typedef signed __int64 s64; #else -#include +# include typedef uint8_t u8; typedef int8_t s8; @@ -602,20 +590,20 @@ typedef uint64_t u64; typedef int64_t s64; #endif -static_assert( sizeof( u8 ) == sizeof( s8 ), "sizeof(u8) != sizeof(s8)" ); +static_assert( sizeof( u8 ) == sizeof( s8 ), "sizeof(u8) != sizeof(s8)" ); static_assert( sizeof( u16 ) == sizeof( s16 ), "sizeof(u16) != sizeof(s16)" ); static_assert( sizeof( u32 ) == sizeof( s32 ), "sizeof(u32) != sizeof(s32)" ); static_assert( sizeof( u64 ) == sizeof( s64 ), "sizeof(u64) != sizeof(s64)" ); -static_assert( sizeof( u8 ) == 1, "sizeof(u8) != 1" ); +static_assert( sizeof( u8 ) == 1, "sizeof(u8) != 1" ); static_assert( sizeof( u16 ) == 2, "sizeof(u16) != 2" ); static_assert( sizeof( u32 ) == 4, "sizeof(u32) != 4" ); static_assert( sizeof( u64 ) == 8, "sizeof(u64) != 8" ); -typedef size_t uw; -typedef ptrdiff_t sw; +typedef size_t usize; +typedef ptrdiff_t ssize; -static_assert( sizeof( uw ) == sizeof( sw ), "sizeof(uw) != sizeof(sw)" ); +static_assert( sizeof( usize ) == sizeof( ssize ), "sizeof(usize) != sizeof(ssize)" ); // NOTE: (u)zpl_intptr is only here for semantic reasons really as this library will only support 32/64 bit OSes. #if defined( _WIN64 ) @@ -623,13 +611,13 @@ typedef signed __int64 sptr; typedef unsigned __int64 uptr; #elif defined( _WIN32 ) // NOTE; To mark types changing their size, e.g. zpl_intptr -#ifndef _W64 -#if ! defined( __midl ) && ( defined( _X86_ ) || defined( _M_IX86 ) ) && _MSC_VER >= 1300 -#define _W64 __w64 -#else -#define _W64 -#endif -#endif +# ifndef _W64 +# if ! defined( __midl ) && ( defined( _X86_ ) || defined( _M_IX86 ) ) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +# endif typedef _W64 signed int sptr; typedef _W64 unsigned int uptr; #else @@ -649,32 +637,56 @@ typedef s8 b8; typedef s16 b16; typedef s32 b32; +typedef void* mem_ptr; +typedef void const* mem_ptr_const ; + +#if GEN_COMPILER_CPP +template uptr to_uptr( Type* ptr ) { return (uptr)ptr; } +template sptr to_sptr( Type* ptr ) { return (sptr)ptr; } + +template mem_ptr to_mem_ptr ( Type ptr ) { return (mem_ptr) ptr; } +template mem_ptr_const to_mem_ptr_const( Type ptr ) { return (mem_ptr_const)ptr; } +#else +#define to_uptr( ptr ) ((uptr)(ptr)) +#define to_sptr( 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 #pragma region Debug -#if defined( _MSC_VER ) -#if _MSC_VER < 1300 -#define GEN_DEBUG_TRAP() __asm int 3 /* Trap to debugger! */ +#if GEN_BUILD_DEBUG +# if defined( GEN_COMPILER_MSVC ) +# if _MSC_VER < 1300 +#pragma message("GEN_BUILD_DEBUG: __asm int 3") +# define GEN_DEBUG_TRAP() __asm int 3 /* Trap to debugger! */ +# else +#pragma message("GEN_BUILD_DEBUG: __debugbreak()") +# define GEN_DEBUG_TRAP() __debugbreak() +# endif +# elif defined( GEN_COMPILER_TINYC ) +# define GEN_DEBUG_TRAP() process_exit( 1 ) +# else +# define GEN_DEBUG_TRAP() __builtin_trap() +# endif #else -#define GEN_DEBUG_TRAP() __debugbreak() -#endif -#elif defined( GEN_COMPILER_TINYC ) -#define GEN_DEBUG_TRAP() process_exit( 1 ) -#else -#define GEN_DEBUG_TRAP() __builtin_trap() +#pragma message("GEN_BUILD_DEBUG: omitted") +# define GEN_DEBUG_TRAP() #endif #define GEN_ASSERT( cond ) GEN_ASSERT_MSG( cond, NULL ) -#define GEN_ASSERT_MSG( cond, msg, ... ) \ - do \ - { \ - if ( ! ( cond ) ) \ - { \ - assert_handler( #cond, __FILE__, zpl_cast( s64 ) __LINE__, msg, ##__VA_ARGS__ ); \ - GEN_DEBUG_TRAP(); \ - } \ +#define GEN_ASSERT_MSG( cond, msg, ... ) \ + do \ + { \ + if ( ! ( cond ) ) \ + { \ + assert_handler( #cond, __FILE__, __func__, scast( s64, __LINE__ ), msg, ##__VA_ARGS__ ); \ + GEN_DEBUG_TRAP(); \ + } \ } while ( 0 ) #define GEN_ASSERT_NOT_NULL( ptr ) GEN_ASSERT_MSG( ( ptr ) != NULL, #ptr " must not be NULL" ) @@ -682,75 +694,87 @@ typedef s32 b32; // NOTE: Things that shouldn't happen with a message! #define GEN_PANIC( msg, ... ) GEN_ASSERT_MSG( 0, msg, ##__VA_ARGS__ ) -void assert_handler( char const* condition, char const* file, s32 line, char const* msg, ... ); -s32 assert_crash( char const* condition ); -void process_exit( u32 code ); - -#if Build_Debug -#define GEN_FATAL( ... ) \ - do \ - { \ - local_persist thread_local char buf[ GEN_PRINTF_MAXLEN ] = { 0 }; \ - \ - str_fmt( buf, GEN_PRINTF_MAXLEN, __VA_ARGS__ ); \ - GEN_PANIC( buf ); \ - } while ( 0 ) +#if GEN_BULD_DEBUG + #define GEN_FATAL( ... ) \ + do \ + { \ + local_persist thread_local \ + char buf[GEN_PRINTF_MAXLEN] = { 0 }; \ + \ + c_str_fmt(buf, GEN_PRINTF_MAXLEN, __VA_ARGS__); \ + GEN_PANIC(buf); \ + } \ + while (0) #else -#define GEN_FATAL( ... ) \ - do \ - { \ - str_fmt_out_err( __VA_ARGS__ ); \ - process_exit( 1 ); \ - } while ( 0 ) +# define GEN_FATAL( ... ) \ + do \ + { \ + c_str_fmt_out_err( __VA_ARGS__ ); \ + GEN_DEBUG_TRAP(); \ + process_exit(1); \ + } \ + while (0) #endif +void assert_handler( char const* condition, char const* file, char const* function, s32 line, char const* msg, ... ); +s32 assert_crash( char const* condition ); +void process_exit( u32 code ); + #pragma endregion Debug #pragma region Memory -#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 ) ) +#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 ) ) -#define GEN__ONES ( zpl_cast( uw ) - 1 / GEN_U8_MAX ) +#define GEN__ONES ( scast( GEN_NS usize, - 1) / GEN_U8_MAX ) #define GEN__HIGHS ( GEN__ONES * ( GEN_U8_MAX / 2 + 1 ) ) -#define GEN__HAS_ZERO( x ) ( ( ( x )-GEN__ONES ) & ~( x ) & GEN__HIGHS ) +#define GEN__HAS_ZERO( x ) ( ( ( x ) - GEN__ONES ) & ~( x ) & GEN__HIGHS ) + +template< class Type > +void swap( Type& a, Type& b ) +{ + Type tmp = a; + a = b; + b = tmp; +} //! Checks if value is power of 2. -GEN_DEF_INLINE b32 is_power_of_two( sw x ); +b32 is_power_of_two( ssize x ); //! Aligns address to specified alignment. -GEN_DEF_INLINE void* align_forward( void* ptr, sw alignment ); +void* align_forward( void* ptr, ssize alignment ); //! Aligns value to a specified alignment. -GEN_DEF_INLINE s64 align_forward_i64( s64 value, sw alignment ); +s64 align_forward_by_value( s64 value, ssize alignment ); //! Moves pointer forward by bytes. -GEN_DEF_INLINE void* pointer_add( void* ptr, sw bytes ); +void* pointer_add( void* ptr, ssize bytes ); //! Moves pointer forward by bytes. -GEN_DEF_INLINE void const* pointer_add_const( void const* ptr, sw bytes ); +void const* pointer_add_const( void const* ptr, ssize bytes ); //! Calculates difference between two addresses. -GEN_DEF_INLINE sw pointer_diff( void const* begin, void const* end ); +ssize pointer_diff( void const* begin, void const* end ); //! Copy non-overlapping memory from source to destination. -void* mem_copy( void* dest, void const* source, sw size ); +void* mem_copy( void* dest, void const* source, ssize size ); //! Search for a constant value within the size limit at memory location. -void const* mem_find( void const* data, u8 byte_value, sw size ); +void const* mem_find( void const* data, u8 byte_value, ssize size ); //! Copy memory from source to destination. -GEN_DEF_INLINE void* mem_move( void* dest, void const* source, sw size ); +void* mem_move( void* dest, void const* source, ssize size ); //! Set constant value at memory location with specified size. -GEN_DEF_INLINE void* mem_set( void* data, u8 byte_value, sw size ); +void* mem_set( void* data, u8 byte_value, ssize size ); //! @param ptr Memory location to clear up. //! @param size The size to clear up with. -GEN_DEF_INLINE void zero_size( void* ptr, sw size ); +void zero_size( void* ptr, ssize size ); //! Clears up an item. #define zero_item( t ) zero_size( ( t ), size_of( *( t ) ) ) // NOTE: Pass pointer of struct @@ -766,7 +790,7 @@ enum AllocType : u8 EAllocation_RESIZE, }; -using AllocatorProc = void*( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw 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 { @@ -780,30 +804,30 @@ enum AllocFlag }; #ifndef GEN_DEFAULT_MEMORY_ALIGNMENT -#define GEN_DEFAULT_MEMORY_ALIGNMENT ( 2 * size_of( void* ) ) +# define GEN_DEFAULT_MEMORY_ALIGNMENT ( 2 * size_of( void* ) ) #endif #ifndef GEN_DEFAULT_ALLOCATOR_FLAGS -#define GEN_DEFAULT_ALLOCATOR_FLAGS ( ALLOCATOR_FLAG_CLEAR_TO_ZERO ) +# define GEN_DEFAULT_ALLOCATOR_FLAGS ( ALLOCATOR_FLAG_CLEAR_TO_ZERO ) #endif //! Allocate memory with default alignment. -GEN_DEF_INLINE void* alloc( AllocatorInfo a, sw size ); +void* alloc( AllocatorInfo a, ssize size ); //! Allocate memory with specified alignment. -GEN_DEF_INLINE void* alloc_align( AllocatorInfo a, sw size, sw alignment ); +void* alloc_align( AllocatorInfo a, ssize size, ssize alignment ); //! Free allocated memory. -GEN_DEF_INLINE void free( AllocatorInfo a, void* ptr ); +void allocator_free( AllocatorInfo a, void* ptr ); //! Free all memory allocated by an allocator. -GEN_DEF_INLINE void free_all( AllocatorInfo a ); +void free_all( AllocatorInfo a ); //! Resize an allocated memory. -GEN_DEF_INLINE void* resize( AllocatorInfo a, void* ptr, sw old_size, sw new_size ); +void* resize( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size ); //! Resize an allocated memory with specified alignment. -GEN_DEF_INLINE void* resize_align( AllocatorInfo a, void* ptr, sw old_size, sw new_size, sw alignment ); +void* resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size, ssize alignment ); //! Allocate memory for an item. #define alloc_item( allocator_, Type ) ( Type* )alloc( allocator_, size_of( Type ) ) @@ -815,23 +839,20 @@ GEN_DEF_INLINE void* resize_align( AllocatorInfo a, void* ptr, sw old_size, sw n /* define GEN_HEAP_ANALYSIS to enable this feature */ /* call zpl_heap_stats_init at the beginning of the entry point */ /* you can call zpl_heap_stats_check near the end of the execution to validate any possible leaks */ -void heap_stats_init( void ); -sw heap_stats_used_memory( void ); -sw heap_stats_alloc_count( void ); -void heap_stats_check( void ); +void heap_stats_init( void ); +ssize heap_stats_used_memory( void ); +ssize heap_stats_alloc_count( void ); +void heap_stats_check( void ); //! Allocate/Resize memory using default options. //! Use this if you don't need a "fancy" resize allocation -GEN_DEF_INLINE void* default_resize_align( AllocatorInfo a, void* ptr, sw old_size, sw new_size, sw alignment ); +void* default_resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size, ssize alignment ); -void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ); +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 ) @@ -839,210 +860,509 @@ constexpr AllocatorInfo heap( void ) //! Helper to free memory allocated by heap allocator. #define mfree( ptr ) free( heap(), ptr ) -GEN_IMPL_INLINE b32 is_power_of_two( sw x ) +struct VirtualMemory { + void* data; + ssize size; +}; + +//! Initialize virtual memory from existing data. +VirtualMemory vm_from_memory( void* data, ssize size ); + +//! Allocate virtual memory at address with size. + +//! @param addr The starting address of the region to reserve. If NULL, it lets operating system to decide where to allocate it. +//! @param size The size to serve. +VirtualMemory vm_alloc( void* addr, ssize size ); + +//! Release the virtual memory. +b32 vm_free( VirtualMemory vm ); + +//! Trim virtual memory. +VirtualMemory vm_trim( VirtualMemory vm, ssize lead_size, ssize size ); + +//! Purge virtual memory. +b32 vm_purge( VirtualMemory vm ); + +//! Retrieve VM's page size and alignment. +ssize virtual_memory_page_size( ssize* alignment_out ); + +#pragma region Arena +struct Arena; + +AllocatorInfo arena_allocator_info( Arena* arena ); + +// 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); + +// Add these declarations after the Arena struct +Arena arena_init_from_allocator(AllocatorInfo backing, ssize size); +Arena arena_init_from_memory ( void* start, ssize size ); + +Arena arena_init_sub (Arena* parent, ssize size); +ssize arena_alignment_of (Arena* arena, ssize alignment); +void arena_check (Arena* arena); +void arena_free (Arena* arena); +ssize arena_size_remaining(Arena* arena, ssize alignment); + +struct Arena +{ + AllocatorInfo Backing; + void* PhysicalStart; + ssize TotalSize; + ssize TotalUsed; + ssize TempCount; + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +#pragma region Member Mapping + forceinline operator AllocatorInfo() { return arena_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 arena_allocator_proc( allocator_data, type, size, alignment, old_memory, old_size, flags ); } + forceinline static Arena init_from_memory( void* start, ssize size ) { return arena_init_from_memory( start, size ); } + forceinline static Arena init_from_allocator( AllocatorInfo backing, ssize size ) { return arena_init_from_allocator( backing, size ); } + forceinline static Arena init_sub( Arena& parent, ssize size ) { return arena_init_from_allocator( parent.Backing, size ); } + forceinline ssize alignment_of( ssize alignment ) { return arena_alignment_of(this, alignment); } + forceinline void free() { return arena_free(this); } + forceinline ssize size_remaining( ssize alignment ) { return arena_size_remaining(this, alignment); } + +// This id is defined by Unreal for asserts +#pragma push_macro("check") +#undef check + forceinline void check() { arena_check(this); } +#pragma pop_macro("check") + +#pragma endregion Member Mapping +#endif +}; + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +forceinline AllocatorInfo allocator_info(Arena& arena ) { return arena_allocator_info(& arena); } +forceinline Arena init_sub (Arena& parent, ssize size) { return arena_init_sub( & parent, size); } +forceinline ssize alignment_of (Arena& arena, ssize alignment) { return arena_alignment_of( & arena, alignment); } +forceinline void free (Arena& arena) { return arena_free(& arena); } +forceinline ssize size_remaining(Arena& arena, ssize alignment) { return arena_size_remaining(& arena, alignment); } + +// This id is defined by Unreal for asserts +#pragma push_macro("check") +#undef check +forceinline void check(Arena& arena) { return arena_check(& arena); }; +#pragma pop_macro("check") +#endif + + +inline +AllocatorInfo arena_allocator_info( Arena* arena ) { + GEN_ASSERT(arena != nullptr); + AllocatorInfo info = { arena_allocator_proc, arena }; + return info; +} + +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 arena_init_sub(Arena* parent, ssize size) { + GEN_ASSERT(parent != nullptr); + return arena_init_from_allocator(parent->Backing, size); +} + +inline +ssize arena_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; +} + +inline +void arena_check(Arena* arena) +{ + GEN_ASSERT(arena != nullptr ); + GEN_ASSERT(arena->TempCount == 0); +} + +inline +void arena_free(Arena* arena) +{ + GEN_ASSERT(arena != nullptr); + if (arena->Backing.Proc) + { + allocator_free(arena->Backing, arena->PhysicalStart); + arena->PhysicalStart = nullptr; + } +} + +inline +ssize arena_size_remaining(Arena* arena, ssize alignment) +{ + GEN_ASSERT(arena != nullptr); + ssize result = arena->TotalSize - (arena->TotalUsed + arena_alignment_of(arena, alignment)); + return result; +} +#pragma endregion Arena + +#pragma region FixedArena +template +struct FixedArena; + +template FixedArena fixed_arena_init(); +template AllocatorInfo fixed_arena_allocator_info(FixedArena* fixed_arena ); +template ssize fixed_arena_size_remaining(FixedArena* fixed_arena, ssize alignment); +template void fixed_arena_free(FixedArena* fixed_arena); + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +template AllocatorInfo allocator_info( FixedArena& fixed_arena ) { return allocator_info(& fixed_arena); } +template ssize size_remaining(FixedArena& 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 +{ + char memory[Size]; + Arena arena; + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +#pragma region Member Mapping + forceinline operator AllocatorInfo() { return fixed_arena_allocator_info(this); } + + forceinline static FixedArena init() { FixedArena result; fixed_arena_init(result); return result; } + forceinline ssize size_remaining(ssize alignment) { fixed_arena_size_remaining(this, alignment); } +#pragma endregion Member Mapping +#endif +}; + +template inline +AllocatorInfo fixed_arena_allocator_info( FixedArena* fixed_arena ) { + GEN_ASSERT(fixed_arena); + return { arena_allocator_proc, & fixed_arena->arena }; +} + +template inline +void fixed_arena_init(FixedArena* result) { + zero_size(& result->memory[0], Size); + result->arena = arena_init_from_memory(& result->memory[0], Size); +} + +template inline +void fixed_arena_free(FixedArena* fixed_arena) { + arena_free( & fixed_arena->arena); +} + +template inline +ssize fixed_arena_size_remaining(FixedArena* fixed_arena, ssize alignment) { + return size_remaining(fixed_arena->arena, alignment); +} + +using FixedArena_1KB = FixedArena< kilobytes( 1 ) >; +using FixedArena_4KB = FixedArena< kilobytes( 4 ) >; +using FixedArena_8KB = FixedArena< kilobytes( 8 ) >; +using FixedArena_16KB = FixedArena< kilobytes( 16 ) >; +using FixedArena_32KB = FixedArena< kilobytes( 32 ) >; +using FixedArena_64KB = FixedArena< kilobytes( 64 ) >; +using FixedArena_128KB = FixedArena< kilobytes( 128 ) >; +using FixedArena_256KB = FixedArena< kilobytes( 256 ) >; +using FixedArena_512KB = FixedArena< kilobytes( 512 ) >; +using FixedArena_1MB = FixedArena< megabytes( 1 ) >; +using FixedArena_2MB = FixedArena< megabytes( 2 ) >; +using FixedArena_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 pool_allocator_info(Pool* pool); +void pool_clear(Pool* pool); +void pool_free(Pool* pool); + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +AllocatorInfo allocator_info(Pool& pool) { return pool_allocator_info(& pool); } +void clear(Pool& pool) { return pool_clear(& pool); } +void free(Pool& pool) { return pool_free(& pool); } +#endif + +struct Pool +{ + AllocatorInfo Backing; + void* PhysicalStart; + void* FreeList; + ssize BlockSize; + ssize BlockAlign; + ssize TotalSize; + ssize NumBlocks; + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +#pragma region Member Mapping + forceinline operator AllocatorInfo() { return pool_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 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 pool_init(backing, num_blocks, block_size); } + forceinline static Pool init_align(AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align) { return pool_init_align(backing, num_blocks, block_size, block_align); } + forceinline void clear() { pool_clear( this); } + forceinline void free() { pool_free( this); } +#pragma endregion +#endif +}; + +inline +AllocatorInfo pool_allocator_info(Pool* pool) { + AllocatorInfo info = { pool_allocator_proc, pool }; + return info; +} + +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 pool_free(Pool* pool) { + if(pool->Backing.Proc) { + allocator_free(pool->Backing, pool->PhysicalStart); + } +} +#pragma endregion Pool + +inline +b32 is_power_of_two( ssize x ) { if ( x <= 0 ) return false; return ! ( x & ( x - 1 ) ); } -GEN_IMPL_INLINE void* align_forward( void* ptr, sw alignment ) +inline +mem_ptr align_forward( void* ptr, ssize alignment ) { - uptr p; - GEN_ASSERT( is_power_of_two( alignment ) ); + uptr p = to_uptr(ptr); + uptr forward = (p + ( alignment - 1 ) ) & ~( alignment - 1 ); - p = zpl_cast( uptr ) ptr; - return zpl_cast( void* )( ( p + ( alignment - 1 ) ) & ~( alignment - 1 ) ); + return to_mem_ptr(forward); } -GEN_IMPL_INLINE s64 align_forward_i64( s64 value, sw alignment ) -{ - return value + ( alignment - value % alignment ) % alignment; +inline s64 align_forward_s64( s64 value, ssize alignment ) { return value + ( alignment - value % alignment ) % alignment; } + +inline void* pointer_add ( void* ptr, ssize bytes ) { return rcast(void*, rcast( u8*, ptr) + bytes ); } +inline void const* pointer_add_const( void const* ptr, ssize bytes ) { return rcast(void const*, rcast( u8 const*, ptr) + bytes ); } + +inline sptr pointer_diff( mem_ptr_const begin, mem_ptr_const end ) { + return scast( ssize, rcast( u8 const*, end) - rcast(u8 const*, begin) ); } -GEN_IMPL_INLINE void* pointer_add( void* ptr, sw bytes ) +inline +void* mem_move( void* destination, void const* source, ssize byte_count ) { - return zpl_cast( void* )( zpl_cast( u8* ) ptr + bytes ); -} - -GEN_IMPL_INLINE void const* pointer_add_const( void const* ptr, sw bytes ) -{ - return zpl_cast( void const* )( zpl_cast( u8 const* ) ptr + bytes ); -} - -GEN_IMPL_INLINE sw pointer_diff( void const* begin, void const* end ) -{ - return zpl_cast( sw )( zpl_cast( u8 const* ) end - zpl_cast( u8 const* ) begin ); -} - -GEN_IMPL_INLINE void* mem_move( void* dest, void const* source, sw n ) -{ - if ( dest == NULL ) + if ( destination == NULL ) { return NULL; } - u8* d = zpl_cast( u8* ) dest; - u8 const* s = zpl_cast( u8 const* ) source; + u8* dest_ptr = rcast( u8*, destination); + u8 const* src_ptr = rcast( u8 const*, source); - if ( d == s ) - return d; - if ( s + n <= d || d + n <= s ) // NOTE: Non-overlapping - return mem_copy( d, s, n ); + if ( dest_ptr == src_ptr ) + return dest_ptr; - if ( d < s ) + if ( src_ptr + byte_count <= dest_ptr || dest_ptr + byte_count <= src_ptr ) // NOTE: Non-overlapping + return mem_copy( dest_ptr, src_ptr, byte_count ); + + if ( dest_ptr < src_ptr ) { - if ( zpl_cast( uptr ) s % size_of( sw ) == zpl_cast( uptr ) d % size_of( sw ) ) + if ( to_uptr(src_ptr) % size_of( ssize ) == to_uptr(dest_ptr) % size_of( ssize ) ) { - while ( zpl_cast( uptr ) d % size_of( sw ) ) + while ( pcast( uptr, dest_ptr) % size_of( ssize ) ) { - if ( ! n-- ) - return dest; - *d++ = *s++; + if ( ! byte_count-- ) + return destination; + + *dest_ptr++ = *src_ptr++; } - while ( n >= size_of( sw ) ) + while ( byte_count >= size_of( ssize ) ) { - *zpl_cast( sw* ) d = *zpl_cast( sw* ) s; - n -= size_of( sw ); - d += size_of( sw ); - s += size_of( sw ); + * rcast(ssize*, dest_ptr) = * rcast(ssize const*, src_ptr); + byte_count -= size_of( ssize ); + dest_ptr += size_of( ssize ); + src_ptr += size_of( ssize ); } } - for ( ; n; n-- ) - *d++ = *s++; + for ( ; byte_count; byte_count-- ) + *dest_ptr++ = *src_ptr++; } else { - if ( ( zpl_cast( uptr ) s % size_of( sw ) ) == ( zpl_cast( uptr ) d % size_of( sw ) ) ) + if ( ( to_uptr(src_ptr) % size_of( ssize ) ) == ( to_uptr(dest_ptr) % size_of( ssize ) ) ) { - while ( zpl_cast( uptr )( d + n ) % size_of( sw ) ) + while ( to_uptr( dest_ptr + byte_count ) % size_of( ssize ) ) { - if ( ! n-- ) - return dest; - d[ n ] = s[ n ]; + if ( ! byte_count-- ) + return destination; + + dest_ptr[ byte_count ] = src_ptr[ byte_count ]; } - while ( n >= size_of( sw ) ) + while ( byte_count >= size_of( ssize ) ) { - n -= size_of( sw ); - *zpl_cast( sw* )( d + n ) = *zpl_cast( sw* )( s + n ); + byte_count -= size_of( ssize ); + * rcast(ssize*, dest_ptr + byte_count ) = * rcast( ssize const*, src_ptr + byte_count ); } } - while ( n ) - n--, d[ n ] = s[ n ]; + while ( byte_count ) + byte_count--, dest_ptr[ byte_count ] = src_ptr[ byte_count ]; } - return dest; + return destination; } -GEN_IMPL_INLINE void* mem_set( void* dest, u8 c, sw n ) +inline +void* mem_set( void* destination, u8 fill_byte, ssize byte_count ) { - if ( dest == NULL ) + if ( destination == NULL ) { return NULL; } - u8* s = zpl_cast( u8* ) dest; - sw k; - u32 c32 = ( ( u32 )-1 ) / 255 * c; + ssize align_offset; + u8* dest_ptr = rcast( u8*, destination); + u32 fill_word = ( ( u32 )-1 ) / 255 * fill_byte; - if ( n == 0 ) - return dest; - s[ 0 ] = s[ n - 1 ] = c; - if ( n < 3 ) - return dest; - s[ 1 ] = s[ n - 2 ] = c; - s[ 2 ] = s[ n - 3 ] = c; - if ( n < 7 ) - return dest; - s[ 3 ] = s[ n - 4 ] = c; - if ( n < 9 ) - return dest; + if ( byte_count == 0 ) + return destination; - k = -zpl_cast( sptr ) s & 3; - s += k; - n -= k; - n &= -4; + dest_ptr[ 0 ] = dest_ptr[ byte_count - 1 ] = fill_byte; + if ( byte_count < 3 ) + return destination; - *zpl_cast( u32* )( s + 0 ) = c32; - *zpl_cast( u32* )( s + n - 4 ) = c32; - if ( n < 9 ) - return dest; - *zpl_cast( u32* )( s + 4 ) = c32; - *zpl_cast( u32* )( s + 8 ) = c32; - *zpl_cast( u32* )( s + n - 12 ) = c32; - *zpl_cast( u32* )( s + n - 8 ) = c32; - if ( n < 25 ) - return dest; - *zpl_cast( u32* )( s + 12 ) = c32; - *zpl_cast( u32* )( s + 16 ) = c32; - *zpl_cast( u32* )( s + 20 ) = c32; - *zpl_cast( u32* )( s + 24 ) = c32; - *zpl_cast( u32* )( s + n - 28 ) = c32; - *zpl_cast( u32* )( s + n - 24 ) = c32; - *zpl_cast( u32* )( s + n - 20 ) = c32; - *zpl_cast( u32* )( s + n - 16 ) = c32; + dest_ptr[ 1 ] = dest_ptr[ byte_count - 2 ] = fill_byte; + dest_ptr[ 2 ] = dest_ptr[ byte_count - 3 ] = fill_byte; + if ( byte_count < 7 ) + return destination; - k = 24 + ( zpl_cast( uptr ) s & 4 ); - s += k; - n -= k; + dest_ptr[ 3 ] = dest_ptr[ byte_count - 4 ] = fill_byte; + if ( byte_count < 9 ) + return destination; + + align_offset = -to_sptr( dest_ptr ) & 3; + dest_ptr += align_offset; + byte_count -= align_offset; + byte_count &= -4; + + * rcast( u32*, ( dest_ptr + 0 ) ) = fill_word; + * rcast( u32*, ( dest_ptr + byte_count - 4 ) ) = fill_word; + if ( byte_count < 9 ) + return destination; + + * rcast( u32*, dest_ptr + 4 ) = fill_word; + * rcast( u32*, dest_ptr + 8 ) = fill_word; + * rcast( u32*, dest_ptr + byte_count - 12 ) = fill_word; + * rcast( u32*, dest_ptr + byte_count - 8 ) = fill_word; + if ( byte_count < 25 ) + return destination; + + * rcast( u32*, dest_ptr + 12 ) = fill_word; + * rcast( u32*, dest_ptr + 16 ) = fill_word; + * rcast( u32*, dest_ptr + 20 ) = fill_word; + * rcast( u32*, dest_ptr + 24 ) = fill_word; + * rcast( u32*, dest_ptr + byte_count - 28 ) = fill_word; + * rcast( u32*, dest_ptr + byte_count - 24 ) = fill_word; + * rcast( u32*, dest_ptr + byte_count - 20 ) = fill_word; + * rcast( u32*, dest_ptr + byte_count - 16 ) = fill_word; + + align_offset = 24 + to_uptr( dest_ptr ) & 4; + dest_ptr += align_offset; + byte_count -= align_offset; { - u64 c64 = ( zpl_cast( u64 ) c32 << 32 ) | c32; - while ( n > 31 ) + u64 fill_doubleword = ( scast( u64, fill_word) << 32 ) | fill_word; + while ( byte_count > 31 ) { - *zpl_cast( u64* )( s + 0 ) = c64; - *zpl_cast( u64* )( s + 8 ) = c64; - *zpl_cast( u64* )( s + 16 ) = c64; - *zpl_cast( u64* )( s + 24 ) = c64; + * rcast( u64*, dest_ptr + 0 ) = fill_doubleword; + * rcast( u64*, dest_ptr + 8 ) = fill_doubleword; + * rcast( u64*, dest_ptr + 16 ) = fill_doubleword; + * rcast( u64*, dest_ptr + 24 ) = fill_doubleword; - n -= 32; - s += 32; + byte_count -= 32; + dest_ptr += 32; } } - return dest; + return destination; } -GEN_IMPL_INLINE void* alloc_align( AllocatorInfo a, sw size, sw alignment ) -{ +inline +void* alloc_align( AllocatorInfo a, ssize size, ssize alignment ) { return a.Proc( a.Data, EAllocation_ALLOC, size, alignment, nullptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS ); } -GEN_IMPL_INLINE void* alloc( AllocatorInfo a, sw size ) -{ +inline +void* alloc( AllocatorInfo a, ssize size ) { return alloc_align( a, size, GEN_DEFAULT_MEMORY_ALIGNMENT ); } -GEN_IMPL_INLINE void free( AllocatorInfo a, void* ptr ) -{ +inline +void allocator_free( AllocatorInfo a, void* ptr ) { if ( ptr != nullptr ) a.Proc( a.Data, EAllocation_FREE, 0, 0, ptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS ); } -GEN_IMPL_INLINE void free_all( AllocatorInfo a ) -{ +inline +void free_all( AllocatorInfo a ) { a.Proc( a.Data, EAllocation_FREE_ALL, 0, 0, nullptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS ); } -GEN_IMPL_INLINE void* resize( AllocatorInfo a, void* ptr, sw old_size, sw new_size ) -{ +inline +void* resize( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size ) { return resize_align( a, ptr, old_size, new_size, GEN_DEFAULT_MEMORY_ALIGNMENT ); } -GEN_IMPL_INLINE void* resize_align( AllocatorInfo a, void* ptr, sw old_size, sw new_size, sw alignment ) -{ +inline +void* resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size, ssize alignment ) { return a.Proc( a.Data, EAllocation_RESIZE, new_size, alignment, ptr, old_size, GEN_DEFAULT_ALLOCATOR_FLAGS ); } -GEN_IMPL_INLINE void* default_resize_align( AllocatorInfo a, void* old_memory, sw old_size, sw new_size, sw alignment ) +inline +void* default_resize_align( AllocatorInfo a, void* old_memory, ssize old_size, ssize new_size, ssize alignment ) { if ( ! old_memory ) return alloc_align( a, new_size, alignment ); if ( new_size == 0 ) { - free( a, old_memory ); + allocator_free( a, old_memory ); return nullptr; } @@ -1055,232 +1375,60 @@ GEN_IMPL_INLINE void* default_resize_align( AllocatorInfo a, void* old_memory, s } else { - void* new_memory = alloc_align( a, new_size, alignment ); + void* new_memory = alloc_align( a, new_size, alignment ); if ( ! new_memory ) return nullptr; + mem_move( new_memory, old_memory, min( new_size, old_size ) ); - free( a, old_memory ); + allocator_free( a, old_memory ); return new_memory; } } -GEN_IMPL_INLINE void zero_size( void* ptr, sw size ) -{ +inline +void zero_size( void* ptr, ssize size ) { mem_set( ptr, 0, size ); } -struct VirtualMemory -{ - void* data; - sw size; -}; - -//! Initialize virtual memory from existing data. -VirtualMemory vm_from_memory( void* data, sw size ); - -//! Allocate virtual memory at address with size. - -//! @param addr The starting address of the region to reserve. If NULL, it lets operating system to decide where to allocate it. -//! @param size The size to serve. -VirtualMemory vm_alloc( void* addr, sw size ); - -//! Release the virtual memory. -b32 vm_free( VirtualMemory vm ); - -//! Trim virtual memory. -VirtualMemory vm_trim( VirtualMemory vm, sw lead_size, sw size ); - -//! Purge virtual memory. -b32 gen_vm_purge( VirtualMemory vm ); - -//! Retrieve VM's page size and alignment. -sw gen_virtual_memory_page_size( sw* alignment_out ); - -struct Arena -{ - static void* allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ); - - static Arena init_from_memory( void* start, sw size ) - { - return { - {nullptr, nullptr}, - start, - size, - 0, - 0 - }; - } - - static Arena init_from_allocator( AllocatorInfo backing, sw size ) - { - Arena result = { backing, alloc( backing, size ), size, 0, 0 }; - return result; - } - - static Arena init_sub( Arena& parent, sw size ) - { - return init_from_allocator( parent.Backing, size ); - } - - sw alignment_of( sw alignment ) - { - sw alignment_offset, result_pointer, mask; - GEN_ASSERT( is_power_of_two( alignment ) ); - - alignment_offset = 0; - result_pointer = ( sw )PhysicalStart + TotalUsed; - mask = alignment - 1; - - if ( result_pointer & mask ) - alignment_offset = alignment - ( result_pointer & mask ); - - return alignment_offset; - } - - void check() - { - GEN_ASSERT( TempCount == 0 ); - } - - void free() - { - if ( Backing.Proc ) - { - gen::free( Backing, PhysicalStart ); - PhysicalStart = nullptr; - } - } - - sw size_remaining( sw alignment ) - { - sw result = TotalSize - ( TotalUsed + alignment_of( alignment ) ); - return result; - } - - AllocatorInfo Backing; - void* PhysicalStart; - sw TotalSize; - sw TotalUsed; - sw TempCount; - - operator AllocatorInfo() - { - return { allocator_proc, this }; - } -}; - -// 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; - } - - sw size_remaining( sw alignment ) - { - return arena.size_remaining( alignment ); - } - - operator AllocatorInfo() - { - return { Arena::allocator_proc, &arena }; - } - - Arena arena; - char memory[ Size ]; -}; - -using Arena_1KB = FixedArena< kilobytes( 1 ) >; -using Arena_4KB = FixedArena< kilobytes( 4 ) >; -using Arena_8KB = FixedArena< kilobytes( 8 ) >; -using Arena_16KB = FixedArena< kilobytes( 16 ) >; -using Arena_32KB = FixedArena< kilobytes( 32 ) >; -using Arena_64KB = FixedArena< kilobytes( 64 ) >; -using Arena_128KB = FixedArena< kilobytes( 128 ) >; -using Arena_256KB = FixedArena< kilobytes( 256 ) >; -using Arena_512KB = FixedArena< kilobytes( 512 ) >; -using Arena_1MB = FixedArena< megabytes( 1 ) >; -using Arena_2MB = FixedArena< megabytes( 2 ) >; -using Arena_4MB = FixedArena< megabytes( 4 ) >; - -struct Pool -{ - static void* allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ); - - static Pool init( AllocatorInfo backing, sw num_blocks, sw block_size ) - { - return init_align( backing, num_blocks, block_size, GEN_DEFAULT_MEMORY_ALIGNMENT ); - } - - static Pool init_align( AllocatorInfo backing, sw num_blocks, sw block_size, sw block_align ); - - void clear(); - - void free() - { - if ( Backing.Proc ) - { - gen::free( Backing, PhysicalStart ); - } - } - - AllocatorInfo Backing; - void* PhysicalStart; - void* FreeList; - sw BlockSize; - sw BlockAlign; - sw TotalSize; - sw NumBlocks; - - operator AllocatorInfo() - { - return { allocator_proc, this }; - } -}; - #pragma endregion Memory #pragma region String Ops -GEN_DEF_INLINE const char* char_first_occurence( const char* str, char c ); -constexpr auto str_find = &char_first_occurence; +const char* char_first_occurence( const char* str, char c ); -GEN_DEF_INLINE b32 char_is_alpha( char c ); -GEN_DEF_INLINE b32 char_is_alphanumeric( char c ); -GEN_DEF_INLINE b32 char_is_digit( char c ); -GEN_DEF_INLINE b32 char_is_hex_digit( char c ); -GEN_DEF_INLINE b32 char_is_space( char c ); -GEN_DEF_INLINE char char_to_lower( char c ); -GEN_DEF_INLINE char char_to_upper( char c ); +b32 char_is_alpha( char c ); +b32 char_is_alphanumeric( char c ); +b32 char_is_digit( char c ); +b32 char_is_hex_digit( char c ); +b32 char_is_space( char c ); +char char_to_lower( char c ); +char char_to_upper( char c ); -GEN_DEF_INLINE s32 digit_to_int( char c ); -GEN_DEF_INLINE s32 hex_digit_to_int( char c ); +s32 digit_to_int( char c ); +s32 hex_digit_to_int( char c ); -GEN_DEF_INLINE s32 str_compare( const char* s1, const char* s2 ); -GEN_DEF_INLINE s32 str_compare( const char* s1, const char* s2, sw len ); -GEN_DEF_INLINE char* str_copy( char* dest, const char* source, sw len ); -GEN_DEF_INLINE sw str_copy_nulpad( char* dest, const char* source, sw len ); -GEN_DEF_INLINE sw str_len( const char* str ); -GEN_DEF_INLINE sw str_len( const char* str, sw max_len ); -GEN_DEF_INLINE char* str_reverse( char* str ); // NOTE: ASCII only -GEN_DEF_INLINE char const* str_skip( char const* str, char c ); -GEN_DEF_INLINE char const* str_skip_any( char const* str, char const* char_list ); -GEN_DEF_INLINE char const* str_trim( char const* str, b32 catch_newline ); +s32 c_str_compare( const char* s1, const char* s2 ); +s32 c_str_compare_len( const char* s1, const char* s2, ssize len ); +char* c_str_copy( char* dest, const char* source, ssize len ); +ssize c_str_copy_nulpad( char* dest, const char* source, ssize len ); +ssize c_str_len( const char* str ); +ssize c_str_len_capped( const char* str, ssize max_len ); +char* c_str_reverse( char* str ); // NOTE: ASCII only +char const* c_str_skip( char const* str, char c ); +char const* c_str_skip_any( char const* str, char const* char_list ); +char const* c_str_trim( char const* str, b32 catch_newline ); // NOTE: ASCII only -GEN_DEF_INLINE void str_to_lower( char* str ); -GEN_DEF_INLINE void str_to_upper( char* str ); +void c_str_to_lower( char* str ); +void c_str_to_upper( char* str ); -s64 str_to_i64( const char* str, char** end_ptr, s32 base ); +s64 c_str_to_i64( const char* str, char** end_ptr, s32 base ); void i64_to_str( s64 value, char* string, s32 base ); void u64_to_str( u64 value, char* string, s32 base ); -f64 str_to_f64( const char* str, char** end_ptr ); +f64 c_str_to_f64( const char* str, char** end_ptr ); -GEN_IMPL_INLINE const char* char_first_occurence( const char* s, char c ) +inline +const char* char_first_occurence( const char* s, char c ) { char ch = c; for ( ; *s != ch; s++ ) @@ -1291,59 +1439,67 @@ GEN_IMPL_INLINE const char* char_first_occurence( const char* s, char c ) return s; } -GEN_IMPL_INLINE b32 char_is_alpha( char c ) +inline +b32 char_is_alpha( char c ) { if ( ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) ) return true; return false; } -GEN_IMPL_INLINE b32 char_is_alphanumeric( char c ) +inline +b32 char_is_alphanumeric( char c ) { return char_is_alpha( c ) || char_is_digit( c ); } -GEN_IMPL_INLINE b32 char_is_digit( char c ) +inline +b32 char_is_digit( char c ) { if ( c >= '0' && c <= '9' ) return true; return false; } -GEN_IMPL_INLINE b32 char_is_hex_digit( char c ) +inline +b32 char_is_hex_digit( char c ) { if ( char_is_digit( c ) || ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) ) return true; return false; } -GEN_IMPL_INLINE b32 char_is_space( char c ) +inline +b32 char_is_space( char c ) { if ( c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v' ) return true; return false; } -GEN_IMPL_INLINE char char_to_lower( char c ) +inline +char char_to_lower( char c ) { if ( c >= 'A' && c <= 'Z' ) return 'a' + ( c - 'A' ); return c; } -GEN_IMPL_INLINE char char_to_upper( char c ) +inline char char_to_upper( char c ) { if ( c >= 'a' && c <= 'z' ) return 'A' + ( c - 'a' ); return c; } -GEN_IMPL_INLINE s32 digit_to_int( char c ) +inline +s32 digit_to_int( char c ) { return char_is_digit( c ) ? c - '0' : c - 'W'; } -GEN_IMPL_INLINE s32 hex_digit_to_int( char c ) +inline +s32 hex_digit_to_int( char c ) { if ( char_is_digit( c ) ) return digit_to_int( c ); @@ -1354,7 +1510,8 @@ GEN_IMPL_INLINE s32 hex_digit_to_int( char c ) return -1; } -GEN_IMPL_INLINE s32 str_compare( const char* s1, const char* s2 ) +inline +s32 c_str_compare( const char* s1, const char* s2 ) { while ( *s1 && ( *s1 == *s2 ) ) { @@ -1363,7 +1520,8 @@ GEN_IMPL_INLINE s32 str_compare( const char* s1, const char* s2 ) return *( u8* )s1 - *( u8* )s2; } -GEN_IMPL_INLINE s32 str_compare( const char* s1, const char* s2, sw len ) +inline +s32 c_str_compare_len( const char* s1, const char* s2, ssize len ) { for ( ; len > 0; s1++, s2++, len-- ) { @@ -1375,7 +1533,8 @@ GEN_IMPL_INLINE s32 str_compare( const char* s1, const char* s2, sw len ) return 0; } -GEN_IMPL_INLINE char* str_copy( char* dest, const char* source, sw len ) +inline +char* c_str_copy( char* dest, const char* source, ssize len ) { GEN_ASSERT_NOT_NULL( dest ); if ( source ) @@ -1395,9 +1554,10 @@ GEN_IMPL_INLINE char* str_copy( char* dest, const char* source, sw len ) return dest; } -GEN_IMPL_INLINE sw str_copy_nulpad( char* dest, const char* source, sw len ) +inline +ssize c_str_copy_nulpad( char* dest, const char* source, ssize len ) { - sw result = 0; + ssize result = 0; GEN_ASSERT_NOT_NULL( dest ); if ( source ) { @@ -1419,7 +1579,8 @@ GEN_IMPL_INLINE sw str_copy_nulpad( char* dest, const char* source, sw len ) return result; } -GEN_IMPL_INLINE sw str_len( const char* str ) +inline +ssize c_str_len( const char* str ) { if ( str == NULL ) { @@ -1431,17 +1592,19 @@ GEN_IMPL_INLINE sw str_len( const char* str ) return str - p; } -GEN_IMPL_INLINE sw str_len( const char* str, sw max_len ) +inline +ssize c_str_len_capped( const char* str, ssize max_len ) { - const char* end = zpl_cast( const char* ) mem_find( str, 0, max_len ); + const char* end = rcast(const char*, mem_find( str, 0, max_len )); if ( end ) return end - str; return max_len; } -GEN_IMPL_INLINE char* str_reverse( char* str ) +inline +char* c_str_reverse( char* str ) { - sw len = str_len( str ); + ssize len = c_str_len( str ); char* a = str + 0; char* b = str + len - 1; len /= 2; @@ -1453,7 +1616,8 @@ GEN_IMPL_INLINE char* str_reverse( char* str ) return str; } -GEN_IMPL_INLINE char const* str_skip( char const* str, char c ) +inline +char const* c_str_skip( char const* str, char c ) { while ( *str && *str != c ) { @@ -1462,19 +1626,21 @@ GEN_IMPL_INLINE char const* str_skip( char const* str, char c ) return str; } -GEN_IMPL_INLINE char const* str_skip_any( char const* str, char const* char_list ) +inline +char const* c_str_skip_any( char const* str, char const* char_list ) { - char const* closest_ptr = zpl_cast( char const* ) pointer_add( ( void* )str, str_len( str ) ); - sw char_list_count = str_len( char_list ); - for ( sw i = 0; i < char_list_count; i++ ) + char const* closest_ptr = rcast( char const*, pointer_add_const( rcast(mem_ptr_const, str), c_str_len( str ) )); + ssize char_list_count = c_str_len( char_list ); + for ( ssize i = 0; i < char_list_count; i++ ) { - char const* p = str_skip( str, char_list[ i ] ); + char const* p = c_str_skip( str, char_list[ i ] ); closest_ptr = min( closest_ptr, p ); } return closest_ptr; } -GEN_IMPL_INLINE char const* str_trim( char const* str, b32 catch_newline ) +inline +char const* c_str_trim( char const* str, b32 catch_newline ) { while ( *str && char_is_space( *str ) && ( ! catch_newline || ( catch_newline && *str != '\n' ) ) ) { @@ -1483,7 +1649,8 @@ GEN_IMPL_INLINE char const* str_trim( char const* str, b32 catch_newline ) return str; } -GEN_IMPL_INLINE void str_to_lower( char* str ) +inline +void c_str_to_lower( char* str ) { if ( ! str ) return; @@ -1494,7 +1661,8 @@ GEN_IMPL_INLINE void str_to_lower( char* str ) } } -GEN_IMPL_INLINE void str_to_upper( char* str ) +inline +void c_str_to_upper( char* str ) { if ( ! str ) return; @@ -1509,33 +1677,36 @@ GEN_IMPL_INLINE void str_to_upper( char* str ) #pragma region Printing -struct FileInfo; +typedef struct FileInfo FileInfo; #ifndef GEN_PRINTF_MAXLEN -#define GEN_PRINTF_MAXLEN kilobytes( 128 ) +# define GEN_PRINTF_MAXLEN kilobytes(128) #endif +typedef char PrintF_Buffer[GEN_PRINTF_MAXLEN]; // NOTE: A locally persisting buffer is used internally -char* str_fmt_buf( char const* fmt, ... ); -char* str_fmt_buf_va( char const* fmt, va_list va ); -sw str_fmt( char* str, sw n, char const* fmt, ... ); -sw str_fmt_va( char* str, sw n, char const* fmt, va_list va ); -sw str_fmt_out_va( char const* fmt, va_list va ); -sw str_fmt_out_err( char const* fmt, ... ); -sw str_fmt_out_err_va( char const* fmt, va_list va ); -sw str_fmt_file( FileInfo* f, char const* fmt, ... ); -sw str_fmt_file_va( FileInfo* f, char const* fmt, va_list va ); +char* c_str_fmt_buf ( char const* fmt, ... ); +char* c_str_fmt_buf_va ( char const* fmt, va_list va ); +ssize c_str_fmt ( char* str, ssize n, char const* fmt, ... ); +ssize c_str_fmt_va ( char* str, ssize n, char const* fmt, va_list va ); +ssize c_str_fmt_out_va ( char const* fmt, va_list va ); +ssize c_str_fmt_out_err ( char const* fmt, ... ); +ssize c_str_fmt_out_err_va( char const* fmt, va_list va ); +ssize c_str_fmt_file ( FileInfo* f, char const* fmt, ... ); +ssize c_str_fmt_file_va ( FileInfo* f, char const* fmt, va_list va ); -constexpr char const* Msg_Invalid_Value = "INVALID VALUE PROVIDED"; +constexpr +char const* Msg_Invalid_Value = "INVALID VALUE PROVIDED"; -inline sw log_fmt( char const* fmt, ... ) +inline +ssize log_fmt(char const* fmt, ...) { - sw res; + ssize res; va_list va; - va_start( va, fmt ); - res = str_fmt_out_va( fmt, va ); - va_end( va ); + va_start(va, fmt); + res = c_str_fmt_out_va(fmt, va); + va_end(va); return res; } @@ -1544,925 +1715,1544 @@ inline sw log_fmt( char const* fmt, ... ) #pragma region Containers -template< class Type > +template struct RemoveConst { typedef TType Type; }; +template struct RemoveConst { typedef TType Type; }; +template struct RemoveConst { typedef TType Type[]; }; +template struct RemoveConst { typedef TType Type[Size]; }; + +template using TRemoveConst = typename RemoveConst::Type; + +template struct RemovePtr { typedef TType Type; }; +template struct RemovePtr { typedef TType Type; }; + +template using TRemovePtr = typename RemovePtr::Type; + + +#pragma region Array +#define Array(Type) Array + +// #define array_init(Type, ...) array_init (__VA_ARGS__) +// #define array_init_reserve(Type, ...) array_init_reserve(__VA_ARGS__) + +struct ArrayHeader; + +#if GEN_COMPILER_CPP + template struct Array; +# define get_array_underlying_type(array) typename TRemovePtr:: DataType +#endif + +usize array_grow_formula(ssize value); + +template Array array_init (AllocatorInfo allocator); +template Array array_init_reserve (AllocatorInfo allocator, ssize capacity); +template bool array_append_array (Array* array, Array other); +template bool array_append (Array* array, Type value); +template bool array_append_items (Array* array, Type* items, usize item_num); +template bool array_append_at (Array* array, Type item, usize idx); +template bool array_append_items_at(Array* array, Type* items, usize item_num, usize idx); +template Type* array_back (Array array); +template void array_clear (Array array); +template bool array_fill (Array array, usize begin, usize end, Type value); +template void array_free (Array* array); +template bool arary_grow (Array* array, usize min_capacity); +template usize array_num (Array array); +template void arary_pop (Array array); +template void arary_remove_at (Array array, usize idx); +template bool arary_reserve (Array* array, usize new_capacity); +template bool arary_resize (Array* array, usize num); +template bool arary_set_capacity (Array* array, usize new_capacity); +template ArrayHeader* arary_get_header (Array array); + +struct ArrayHeader { + AllocatorInfo Allocator; + usize Capacity; + usize Num; +}; + +#if GEN_COMPILER_CPP +template struct Array { - struct Header - { - AllocatorInfo Allocator; - uw Capacity; - uw Num; - }; - - static Array init( AllocatorInfo allocator ) - { - return init_reserve( allocator, grow_formula( 0 ) ); - } - - static Array init_reserve( AllocatorInfo allocator, sw capacity ) - { - Header* header = rcast( Header*, alloc( allocator, sizeof( Header ) + sizeof( Type ) * capacity ) ); - - if ( header == nullptr ) - return { nullptr }; - - header->Allocator = allocator; - header->Capacity = capacity; - header->Num = 0; - - return { rcast( Type*, header + 1 ) }; - } - - static uw grow_formula( uw value ) - { - return 2 * value + 8; - } - - bool append( Type value ) - { - Header* header = get_header(); - - if ( header->Num == header->Capacity ) - { - if ( ! grow( header->Capacity ) ) - return false; - - header = get_header(); - } - - Data[ header->Num ] = value; - header->Num++; - - return true; - } - - bool append( Type* items, uw item_num ) - { - Header* header = get_header(); - - if ( header->Num + item_num > header->Capacity ) - { - if ( ! grow( header->Capacity + item_num ) ) - return false; - - header = get_header(); - } - - mem_copy( Data + header->Num, items, item_num * sizeof( Type ) ); - header->Num += item_num; - - return true; - } - - bool append_at( Type item, uw idx ) - { - Header* header = get_header(); - - if ( idx >= header->Num ) - idx = header->Num - 1; - - if ( idx < 0 ) - idx = 0; - - if ( header->Capacity < header->Num + 1 ) - { - if ( ! grow( header->Capacity + 1 ) ) - return false; - - header = get_header(); - } - - Type* target = Data + idx; - - mem_move( target + 1, target, ( header->Num - idx ) * sizeof( Type ) ); - header->Num++; - - return true; - } - - bool append_at( Type* items, uw item_num, uw idx ) - { - Header* header = get_header(); - - if ( idx >= header->Num ) - { - return append( items, item_num ); - } - - if ( item_num > header->Capacity ) - { - if ( ! grow( header->Capacity + item_num ) ) - return false; - - header = get_header(); - } - - Type* target = Data + idx + item_num; - Type* src = Data + 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& back( void ) - { - Header& header = *get_header(); - return Data[ header.Num - 1 ]; - } - - void clear( void ) - { - Header& header = *get_header(); - header.Num = 0; - } - - bool fill( uw begin, uw end, Type value ) - { - Header& header = *get_header(); - - if ( begin < 0 || end >= header.Num ) - return false; - - for ( sw idx = begin; idx < end; idx++ ) - { - Data[ idx ] = value; - } - - return true; - } - - void free( void ) - { - Header& header = *get_header(); - gen::free( header.Allocator, &header ); - Data = nullptr; - } - - Header* get_header( void ) - { - return rcast( Header*, Data ) - 1; - } - - bool grow( uw min_capacity ) - { - Header& header = *get_header(); - uw new_capacity = grow_formula( header.Capacity ); - - if ( new_capacity < min_capacity ) - new_capacity = min_capacity; - - return set_capacity( new_capacity ); - } - - uw num( void ) - { - return get_header()->Num; - } - - bool pop( void ) - { - Header& header = *get_header(); - - GEN_ASSERT( header.Num > 0 ); - header.Num--; - } - - void remove_at( uw idx ) - { - Header* header = get_header(); - GEN_ASSERT( idx < header->Num ); - - mem_move( header + idx, header + idx + 1, sizeof( Type ) * ( header->Num - idx - 1 ) ); - header->Num--; - } - - bool reserve( uw new_capacity ) - { - Header& header = *get_header(); - - if ( header.Capacity < new_capacity ) - return set_capacity( new_capacity ); - - return true; - } - - bool resize( uw num ) - { - Header* header = get_header(); - - if ( header->Capacity < num ) - { - if ( ! grow( num ) ) - return false; - - header = get_header(); - } - - header->Num = num; - return true; - } - - bool set_capacity( uw new_capacity ) - { - Header& header = *get_header(); - - if ( new_capacity == header.Capacity ) - return true; - - if ( new_capacity < header.Num ) - header.Num = new_capacity; - - sw size = sizeof( Header ) + sizeof( Type ) * new_capacity; - Header* new_header = rcast( Header*, alloc( header.Allocator, size ) ); - - if ( new_header == nullptr ) - return false; - - mem_move( new_header, &header, sizeof( Header ) + sizeof( Type ) * header.Num ); - - new_header->Capacity = new_capacity; - - gen::free( header.Allocator, &header ); - - Data = rcast( Type*, new_header + 1 ); - return true; - } - Type* Data; - operator Type*() +#pragma region Member Mapping + forceinline static Array init(AllocatorInfo allocator) { return array_init(allocator); } + forceinline static Array init_reserve(AllocatorInfo allocator, ssize capacity) { return array_init_reserve(allocator, capacity); } + forceinline static usize grow_formula(ssize value) { return array_grow_formula(value); } + + forceinline bool append(Array other) { return array_append_array(this, other); } + forceinline bool append(Type value) { return array_append(this, value); } + forceinline bool append(Type* items, usize item_num) { return array_append_items(this, items, item_num); } + forceinline bool append_at(Type item, usize idx) { return array_append_at(this, item, idx); } + forceinline bool append_at(Type* items, usize item_num, usize idx) { return array_append_items_at(this, items, item_num, idx); } + forceinline Type* back() { return array_back(* this); } + forceinline void clear() { array_clear(* this); } + forceinline bool fill(usize begin, usize end, Type value) { return array_fill(* this, begin, end, value); } + forceinline void free() { array_free(this); } + forceinline ArrayHeader* get_header() { return array_get_header(* this); } + forceinline bool grow(usize min_capacity) { return array_grow(this, min_capacity); } + forceinline usize num() { return array_num(*this); } + forceinline void pop() { array_pop(* this); } + forceinline void remove_at(usize idx) { array_remove_at(* this, idx); } + forceinline bool reserve(usize new_capacity) { return array_reserve(this, new_capacity); } + forceinline bool resize(usize num) { return array_resize(this, num); } + forceinline bool set_capacity(usize new_capacity) { return array_set_capacity(this, new_capacity); } +#pragma endregion Member Mapping + + forceinline operator Type*() { return Data; } + forceinline operator Type const*() const { return Data; } + forceinline Type* begin() { return Data; } + forceinline Type* end() { return Data + get_header()->Num; } + + forceinline Type& operator[](ssize index) { return Data[index]; } + forceinline Type const& operator[](ssize index) const { return Data[index]; } + + using DataType = Type; +}; +#endif + +#if GEN_COMPILER_CPP && 0 +template bool append(Array& array, Array other) { return append( & array, other ); } +template bool append(Array& array, Type value) { return append( & array, value ); } +template bool append(Array& array, Type* items, usize item_num) { return append( & array, items, item_num ); } +template bool append_at(Array& array, Type item, usize idx) { return append_at( & array, item, idx ); } +template bool append_at(Array& array, Type* items, usize item_num, usize idx) { return append_at( & array, items, item_num, idx ); } +template void free(Array& array) { return free( & array ); } +template bool grow(Array& array, usize min_capacity) { return grow( & array, min_capacity); } +template bool reserve(Array& array, usize new_capacity) { return reserve( & array, new_capacity); } +template bool resize(Array& array, usize num) { return resize( & array, num); } +template bool set_capacity(Array& array, usize new_capacity) { return set_capacity( & array, new_capacity); } + +template forceinline Type* begin(Array& array) { return array; } +template forceinline Type* end(Array& array) { return array + array_get_header(array)->Num; } +template forceinline Type* next(Array& array, Type* entry) { return entry + 1; } +#endif + +template forceinline Type* array_begin(Array array) { return array; } +template forceinline Type* array_end(Array array) { return array + array_get_header(array)->Num; } +template forceinline Type* array_next(Array array, Type* entry) { return ++ entry; } + +template inline +Array array_init(AllocatorInfo allocator) { + return array_init_reserve(allocator, array_grow_formula(0)); +} + +template inline +Array array_init_reserve(AllocatorInfo allocator, ssize capacity) +{ + GEN_ASSERT(capacity > 0); + ArrayHeader* header = rcast(ArrayHeader*, alloc(allocator, sizeof(ArrayHeader) + sizeof(Type) * capacity)); + + if (header == nullptr) + return {nullptr}; + + header->Allocator = allocator; + header->Capacity = capacity; + header->Num = 0; + + return {rcast(Type*, header + 1)}; +} + +usize array_grow_formula(ssize value) { + return 2 * value + 8; +} + +template inline +bool array_append_array(Array* array, Array other) { + return array_append_items(array, (Type*)other, num(other)); +} + +template inline +bool array_append(Array* array, Type value) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + ArrayHeader* header = array_get_header(* array); + + if (header->Num == header->Capacity) { - return Data; + if ( ! array_grow(array, header->Capacity)) + return false; + header = array_get_header(* array); } - operator Type const*() const + (*array)[ header->Num] = value; + header->Num++; + + return true; +} + +template inline +bool array_append_items(Array* array, Type* items, usize item_num) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + GEN_ASSERT(items != nullptr); + GEN_ASSERT(item_num > 0); + ArrayHeader* header = array_get_header(array); + + if (header->Num + item_num > header->Capacity) { - return Data; + if ( ! grow(array, header->Capacity + item_num)) + return false; + header = array_get_header(array); } - // For-range based support + mem_copy((Type*)array + header->Num, items, item_num * sizeof(Type)); + header->Num += item_num; - Type* begin() + return true; +} + +template inline +bool array_append_at(Array* array, Type item, usize idx) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + ArrayHeader* header = array_get_header(* array); + + ssize slot = idx; + if (slot >= header->Num) + slot = header->Num - 1; + + if (slot < 0) + slot = 0; + + if (header->Capacity < header->Num + 1) { - return Data; + if ( ! array_grow(array, header->Capacity + 1)) + return false; + + header = array_get_header(* array); } - Type* end() + Type* target = &(*array)[slot]; + + mem_move(target + 1, target, (header->Num - slot) * sizeof(Type)); + header->Num++; + + return true; +} + +template inline +bool array_append_items_at(Array* array, Type* items, usize item_num, usize idx) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + ArrayHeader* header = get_header(array); + + if (idx >= header->Num) { - return Data + get_header()->Num; + return array_append_items(array, items, item_num); } + + if (item_num > header->Capacity) + { + if (! grow(array, header->Capacity + item_num)) + return false; + + header = get_header(array); + } + + Type* target = array.Data + idx + item_num; + Type* src = array.Data + idx; + + mem_move(target, src, (header->Num - idx) * sizeof(Type)); + mem_copy(src, items, item_num * sizeof(Type)); + header->Num += item_num; + + return true; +} + +template inline +Type* array_back(Array array) +{ + GEN_ASSERT(array != nullptr); + + ArrayHeader* header = array_get_header(array); + if (header->Num <= 0) + return nullptr; + + return & (array)[header->Num - 1]; +} + +template inline +void array_clear(Array array) { + GEN_ASSERT(array != nullptr); + ArrayHeader* header = array_get_header(array); + header->Num = 0; +} + +template inline +bool array_fill(Array array, usize begin, usize end, Type value) +{ + GEN_ASSERT(array != nullptr); + GEN_ASSERT(begin <= end); + ArrayHeader* header = array_get_header(array); + + if (begin < 0 || end > header->Num) + return false; + + for (ssize idx = ssize(begin); idx < ssize(end); idx++) + { + array[idx] = value; + } + + return true; +} + +template forceinline +void array_free(Array* array) { + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + ArrayHeader* header = array_get_header(* array); + allocator_free(header->Allocator, header); + Type** Data = (Type**)array; + *Data = nullptr; +} + +template forceinline +ArrayHeader* array_get_header(Array array) { + GEN_ASSERT(array != nullptr); + Type* Data = array; + + using NonConstType = TRemoveConst; + return rcast(ArrayHeader*, const_cast(Data)) - 1; +} +template forceinline +bool array_grow(Array* array, usize min_capacity) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + GEN_ASSERT( min_capacity > 0 ); + ArrayHeader* header = array_get_header(* array); + usize new_capacity = array_grow_formula(header->Capacity); + + if (new_capacity < min_capacity) + new_capacity = min_capacity; + + return array_set_capacity(array, new_capacity); +} + +template forceinline +usize array_num(Array array) { + GEN_ASSERT(array != nullptr); + return array_get_header(array)->Num; +} + +template forceinline +void array_pop(Array array) { + GEN_ASSERT(array != nullptr); + ArrayHeader* header = array_get_header(array); + GEN_ASSERT(header->Num > 0); + header->Num--; +} + +template inline +void array_remove_at(Array array, usize idx) +{ + GEN_ASSERT(array != nullptr); + ArrayHeader* header = array_get_header(array); + GEN_ASSERT(idx < header->Num); + + mem_move(array + idx, array + idx + 1, sizeof(Type) * (header->Num - idx - 1)); + header->Num--; +} + +template inline +bool array_reserve(Array* array, usize new_capacity) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + GEN_ASSERT(num > 0) + ArrayHeader* header = array_get_header(array); + + if (header->Capacity < new_capacity) + return set_capacity(array, new_capacity); + + return true; +} + +template inline +bool array_resize(Array* array, usize num) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + ArrayHeader* header = array_get_header(* array); + + if (header->Capacity < num) { + if (! array_grow( array, num)) + return false; + header = array_get_header(* array); + } + + header->Num = num; + return true; +} + +template inline +bool array_set_capacity(Array* array, usize new_capacity) +{ + GEN_ASSERT( array != nullptr); + GEN_ASSERT(* array != nullptr); + ArrayHeader* header = array_get_header(* array); + + if (new_capacity == header->Capacity) + return true; + + if (new_capacity < header->Num) + { + header->Num = new_capacity; + return true; + } + + ssize size = sizeof(ArrayHeader) + sizeof(Type) * new_capacity; + ArrayHeader* new_header = rcast(ArrayHeader*, alloc(header->Allocator, size)); + + if (new_header == nullptr) + return false; + + mem_move(new_header, header, sizeof(ArrayHeader) + sizeof(Type) * header->Num); + + new_header->Capacity = new_capacity; + + allocator_free(header->Allocator, header); + + Type** Data = (Type**)array; + * Data = rcast(Type*, new_header + 1); + return true; +} + +// These are intended for use in the base library of gencpp and the C-variant of the library +// It provides a interoperability between the C++ and C implementation of arrays. (not letting these do any crazy substiution though) +// They are undefined in gen.hpp and gen.cpp at the end of the files. +// We cpp library expects the user to use the regular calls as they can resolve the type fine. + +#define array_init(type, allocator) array_init (allocator ) +#define array_init_reserve(type, allocator, cap) array_init_reserve (allocator, cap) +#define array_append_array(array, other) array_append_array < get_array_underlying_type(array) > (& array, other ) +#define array_append(array, value) array_append < get_array_underlying_type(array) > (& array, value ) +#define array_append_items(array, items, item_num) array_append_items < get_array_underlying_type(array) > (& array, items, item_num ) +#define array_append_at(array, item, idx ) array_append_at < get_array_underlying_type(array) > (& array, item, idx ) +#define array_append_at_items(array, items, item_num, idx) array_append_at_items< get_array_underlying_type(array) > (& items, item_num, idx ) +#define array_back(array) array_back < get_array_underlying_type(array) > (array ) +#define array_clear(array) array_clear < get_array_underlying_type(array) > (array ) +#define array_fill(array, begin, end, value) array_fill < get_array_underlying_type(array) > (array, begin, end, value ) +#define array_free(array) array_free < get_array_underlying_type(array) > (& array ) +#define arary_grow(array, min_capacity) arary_grow < get_array_underlying_type(array) > (& array, min_capacity) +#define array_num(array) array_num < get_array_underlying_type(array) > (array ) +#define arary_pop(array) arary_pop < get_array_underlying_type(array) > (array ) +#define arary_remove_at(array, idx) arary_remove_at < get_array_underlying_type(array) > (idx) +#define arary_reserve(array, new_capacity) arary_reserve < get_array_underlying_type(array) > (& array, new_capacity ) +#define arary_resize(array, num) arary_resize < get_array_underlying_type(array) > (& array, num) +#define arary_set_capacity(new_capacity) arary_set_capacity < get_array_underlying_type(array) > (& array, new_capacity ) +#define arary_get_header(array) arary_get_header < get_array_underlying_type(array) > (array ) + +#pragma endregion Array + +#pragma region HashTable +#define HashTable(Type) HashTable + +template struct HashTable; + +#ifndef get_hashtable_underlying_type +#define get_hashtable_underlying_type(table) typename TRemovePtr:: DataType +#endif + +struct HashTableFindResult { + ssize HashIndex; + ssize PrevIndex; + ssize EntryIndex; }; -template< typename Type > +template +struct HashTableEntry { + u64 Key; + ssize Next; + Type Value; +}; + +#define HashTableEntry(Type) HashTableEntry + +template HashTable hashtable_init (AllocatorInfo allocator); +template HashTable hashtable_init_reserve(AllocatorInfo allocator, usize num); +template void hashtable_clear (HashTable table); +template void hashtable_destroy (HashTable* table); +template Type* hashtable_get (HashTable table, u64 key); +template void hashtable_grow (HashTable* table); +template void hashtable_rehash (HashTable* table, ssize new_num); +template void hashtable_rehash_fast (HashTable table); +template void hashtable_remove (HashTable table, u64 key); +template void hashtable_remove_entry(HashTable table, ssize idx); +template void hashtable_set (HashTable* table, u64 key, Type value); +template ssize hashtable_slot (HashTable table, u64 key); +template void hashtable_map (HashTable table, void (*map_proc)(u64 key, Type value)); +template void hashtable_map_mut (HashTable table, void (*map_proc)(u64 key, Type* value)); + +template ssize hashtable__add_entry (HashTable* table, u64 key); +template HashTableFindResult hashtable__find (HashTable table, u64 key); +template bool hashtable__full (HashTable table); + +static constexpr f32 HashTable_CriticalLoadScale = 0.7f; + +template struct HashTable { - struct FindResult - { - sw HashIndex; - sw PrevIndex; - sw EntryIndex; - }; + Array Hashes; + Array> Entries; - struct Entry - { - u64 Key; - sw Next; - Type Value; - }; +#if ! GEN_C_LIKE_CPP +#pragma region Member Mapping + forceinline static HashTable init(AllocatorInfo allocator) { return hashtable_init(allocator); } + forceinline static HashTable init_reserve(AllocatorInfo allocator, usize num) { return hashtable_init_reserve(allocator, num); } - static HashTable init( AllocatorInfo allocator ) - { - HashTable< Type > result = { { nullptr }, { nullptr } }; + forceinline void clear() { clear(*this); } + forceinline void destroy() { destroy(*this); } + forceinline Type* get(u64 key) { return get(*this, key); } + forceinline void grow() { grow(*this); } + forceinline void rehash(ssize new_num) { rehash(*this, new_num); } + forceinline void rehash_fast() { rehash_fast(*this); } + forceinline void remove(u64 key) { remove(*this, key); } + forceinline void remove_entry(ssize idx) { remove_entry(*this, idx); } + forceinline void set(u64 key, Type value) { set(*this, key, value); } + forceinline ssize slot(u64 key) { return slot(*this, key); } + forceinline void map(void (*proc)(u64, Type)) { map(*this, proc); } + forceinline void map_mut(void (*proc)(u64, Type*)) { map_mut(*this, proc); } +#pragma endregion Member Mapping +#endif - result.Hashes = Array< sw >::init( allocator ); - result.Entries = Array< Entry >::init( allocator ); - - return result; - } - - static HashTable init_reserve( AllocatorInfo allocator, uw num ) - { - HashTable< Type > result = { { nullptr }, { nullptr } }; - - result.Hashes = Array< sw >::init_reserve( allocator, num ); - result.Hashes.get_header()->Num = num; - - result.Entries = Array< Entry >::init_reserve( allocator, num ); - - return result; - } - - void clear( void ) - { - for ( sw idx = 0; idx < Hashes.num(); idx++ ) - Hashes[ idx ] = -1; - - Hashes.clear(); - Entries.clear(); - } - - void destroy( void ) - { - if ( Hashes && Hashes.get_header()->Capacity ) - { - Hashes.free(); - Entries.free(); - } - } - - Type* get( u64 key ) - { - sw idx = find( key ).EntryIndex; - if ( idx >= 0 ) - return &Entries[ idx ].Value; - - return nullptr; - } - - using MapProc = void ( * )( u64 key, Type value ); - - void map( MapProc map_proc ) - { - GEN_ASSERT_NOT_NULL( map_proc ); - - for ( sw idx = 0; idx < Entries.num(); idx++ ) - { - map_proc( Entries[ idx ].Key, Entries[ idx ].Value ); - } - } - - using MapMutProc = void ( * )( u64 key, Type* value ); - - void map_mut( MapMutProc map_proc ) - { - GEN_ASSERT_NOT_NULL( map_proc ); - - for ( sw idx = 0; idx < Entries.num(); idx++ ) - { - map_proc( Entries[ idx ].Key, &Entries[ idx ].Value ); - } - } - - void grow() - { - sw new_num = Array< Entry >::grow_formula( Entries.num() ); - rehash( new_num ); - } - - void rehash( sw new_num ) - { - sw idx; - sw last_added_index; - - HashTable< Type > new_ht = init_reserve( Hashes.get_header()->Allocator, new_num ); - - Array< sw >::Header* hash_header = new_ht.Hashes.get_header(); - - for ( idx = 0; idx < new_ht.Hashes.num(); ++idx ) - new_ht.Hashes[ idx ] = -1; - - for ( idx = 0; idx < Entries.num(); ++idx ) - { - Entry& entry = Entries[ idx ]; - - FindResult find_result; - - if ( new_ht.Hashes.num() == 0 ) - new_ht.grow(); - - entry = Entries[ idx ]; - find_result = new_ht.find( entry.Key ); - last_added_index = new_ht.add_entry( entry.Key ); - - if ( find_result.PrevIndex < 0 ) - new_ht.Hashes[ find_result.HashIndex ] = last_added_index; - - else - new_ht.Entries[ find_result.PrevIndex ].Next = last_added_index; - - new_ht.Entries[ last_added_index ].Next = find_result.EntryIndex; - new_ht.Entries[ last_added_index ].Value = entry.Value; - } - - destroy(); - *this = new_ht; - } - - void rehash_fast() - { - sw idx; - - for ( idx = 0; idx < Entries.num(); idx++ ) - Entries[ idx ].Next = -1; - - for ( idx = 0; idx < Hashes.num(); idx++ ) - Hashes[ idx ] = -1; - - for ( idx = 0; idx < Entries.num(); idx++ ) - { - Entry* entry; - FindResult find_result; - - entry = &Entries[ idx ]; - find_result = find( entry->Key ); - - if ( find_result.PrevIndex < 0 ) - Hashes[ find_result.HashIndex ] = idx; - else - Entries[ find_result.PrevIndex ].Next = idx; - } - } - - void remove( u64 key ) - { - FindResult find_result = find( key ); - - if ( find_result.EntryIndex >= 0 ) - { - Entries.remove_at( find_result.EntryIndex ); - rehash_fast(); - } - } - - void remove_entry( sw idx ) - { - Entries.remove_at( idx ); - } - - void set( u64 key, Type value ) - { - sw idx; - FindResult find_result; - - if ( Hashes.num() == 0 ) - grow(); - - find_result = find( key ); - - if ( find_result.EntryIndex >= 0 ) - { - idx = find_result.EntryIndex; - } - else - { - idx = add_entry( key ); - - if ( find_result.PrevIndex >= 0 ) - { - Entries[ find_result.PrevIndex ].Next = idx; - } - else - { - Hashes[ find_result.HashIndex ] = idx; - } - } - - Entries[ idx ].Value = value; - - if ( full() ) - grow(); - } - - sw slot( u64 key ) - { - for ( sw idx = 0; idx < Hashes.num(); ++idx ) - if ( Hashes[ idx ] == key ) - return idx; - - return -1; - } - - Array< sw > Hashes; - Array< Entry > Entries; - -protected: - sw add_entry( u64 key ) - { - sw idx; - Entry entry = { key, -1 }; - - idx = Entries.num(); - Entries.append( entry ); - return idx; - } - - FindResult find( u64 key ) - { - FindResult result = { -1, -1, -1 }; - - if ( Hashes.num() > 0 ) - { - result.HashIndex = key % Hashes.num(); - result.EntryIndex = Hashes[ result.HashIndex ]; - - while ( result.EntryIndex >= 0 ) - { - if ( Entries[ result.EntryIndex ].Key == key ) - break; - - result.PrevIndex = result.EntryIndex; - result.EntryIndex = Entries[ result.EntryIndex ].Next; - } - } - - return result; - } - - b32 full() - { - return 0.75f * Hashes.num() < Entries.num(); - } + using DataType = Type; }; +#if GEN_SUPPORT_CPP_REFERENCES +template void destroy (HashTable& table) { destroy(& table); } +template void grow (HashTable& table) { grow(& table); } +template void rehash (HashTable& table, ssize new_num) { rehash(& table, new_num); } +template void set (HashTable& table, u64 key, Type value) { set(& table, key, value); } +template ssize add_entry(HashTable& table, u64 key) { add_entry(& table, key); } +#endif + +template inline +HashTable hashtable_init(AllocatorInfo allocator) { + HashTable result = hashtable_init_reserve(allocator, 8); + return result; +} + +template inline +HashTable hashtable_init_reserve(AllocatorInfo allocator, usize num) +{ + HashTable result = { { nullptr }, { nullptr } }; + + result.Hashes = array_init_reserve(allocator, num); + array_get_header(result.Hashes)->Num = num; + array_resize(& result.Hashes, num); + array_fill(result.Hashes, 0, num, (ssize)-1); + + result.Entries = array_init_reserve>(allocator, num); + return result; +} + +template forceinline +void hashtable_clear(HashTable table) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + array_clear(table.Entries); + array_fill(table.Hashes, 0, array_num(table.Hashes), (ssize)-1); +} + +template forceinline +void hashtable_destroy(HashTable* table) { + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); + if (table->Hashes && array_get_header(table->Hashes)->Capacity) { + array_free(table->Hashes); + array_free(table->Entries); + } +} + +template forceinline +Type* hashtable_get(HashTable table, u64 key) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + ssize idx = hashtable__find(table, key).EntryIndex; + if (idx >= 0) + return & table.Entries[idx].Value; + + return nullptr; +} + +template forceinline +void hashtable_map(HashTable table, void (*map_proc)(u64 key, Type value)) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + GEN_ASSERT_NOT_NULL(map_proc); + + for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) { + map_proc(table.Entries[idx].Key, table.Entries[idx].Value); + } +} + +template forceinline +void hashtable_map_mut(HashTable table, void (*map_proc)(u64 key, Type* value)) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + GEN_ASSERT_NOT_NULL(map_proc); + + for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) { + map_proc(table.Entries[idx].Key, & table.Entries[idx].Value); + } +} + +template forceinline +void hashtable_grow(HashTable* table) { + GEN_ASSERT_NOT_NULL(table); + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); + ssize new_num = array_grow_formula( array_num(table->Entries)); + hashtable_rehash(table, new_num); +} + +template inline +void hashtable_rehash(HashTable* table, ssize new_num) +{ + GEN_ASSERT_NOT_NULL(table); + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); + ssize last_added_index; + HashTable new_ht = hashtable_init_reserve( array_get_header(table->Hashes)->Allocator, new_num); + + for (ssize idx = 0; idx < ssize( array_num(table->Entries)); ++idx) + { + HashTableFindResult find_result; + HashTableEntry& entry = table->Entries[idx]; + + find_result = hashtable__find(new_ht, entry.Key); + last_added_index = hashtable__add_entry(& new_ht, entry.Key); + + if (find_result.PrevIndex < 0) + new_ht.Hashes[find_result.HashIndex] = last_added_index; + else + new_ht.Entries[find_result.PrevIndex].Next = last_added_index; + + new_ht.Entries[last_added_index].Next = find_result.EntryIndex; + new_ht.Entries[last_added_index].Value = entry.Value; + } + + hashtable_destroy(table); + * table = new_ht; +} + +template inline +void hashtable_rehash_fast(HashTable table) +{ + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + ssize idx; + + for (idx = 0; idx < ssize(num(table.Entries)); idx++) + table.Entries[idx].Next = -1; + + for (idx = 0; idx < ssize(num(table.Hashes)); idx++) + table.Hashes[idx] = -1; + + for (idx = 0; idx < ssize(num(table.Entries)); idx++) + { + HashTableEntry* entry; + HashTableFindResult find_result; + + entry = &table.Entries[idx]; + find_result = find(table, entry->Key); + + if (find_result.PrevIndex < 0) + table.Hashes[find_result.HashIndex] = idx; + else + table.Entries[find_result.PrevIndex].Next = idx; + } +} + +template forceinline +void hashtable_remove(HashTable table, u64 key) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + HashTableFindResult find_result = find(table, key); + + if (find_result.EntryIndex >= 0) { + remove_at(table.Entries, find_result.EntryIndex); + rehash_fast(table); + } +} + +template forceinline +void hashtable_remove_entry(HashTable table, ssize idx) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + remove_at(table.Entries, idx); +} + +template inline +void hashtable_set(HashTable* table, u64 key, Type value) +{ + GEN_ASSERT_NOT_NULL(table); + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); + ssize idx; + HashTableFindResult find_result; + + if (hashtable_full(* table)) + hashtable_grow(table); + + find_result = hashtable__find(* table, key); + if (find_result.EntryIndex >= 0) { + idx = find_result.EntryIndex; + } + else + { + idx = hashtable__add_entry(table, key); + + if (find_result.PrevIndex >= 0) { + table->Entries[find_result.PrevIndex].Next = idx; + } + else { + table->Hashes[find_result.HashIndex] = idx; + } + } + + table->Entries[idx].Value = value; + + if (hashtable_full(* table)) + hashtable_grow(table); +} + +template forceinline +ssize hashtable_slot(HashTable table, u64 key) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + for (ssize idx = 0; idx < ssize(num(table.Hashes)); ++idx) + if (table.Hashes[idx] == key) + return idx; + + return -1; +} + +template forceinline +ssize hashtable__add_entry(HashTable* table, u64 key) { + GEN_ASSERT_NOT_NULL(table); + GEN_ASSERT_NOT_NULL(table->Hashes); + GEN_ASSERT_NOT_NULL(table->Entries); + ssize idx; + HashTableEntry entry = { key, -1 }; + + idx = array_num(table->Entries); + array_append( table->Entries, entry); + return idx; +} + +template inline +HashTableFindResult hashtable__find(HashTable table, u64 key) +{ + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + HashTableFindResult result = { -1, -1, -1 }; + + if (array_num(table.Hashes) > 0) + { + result.HashIndex = key % array_num(table.Hashes); + result.EntryIndex = table.Hashes[result.HashIndex]; + + while (result.EntryIndex >= 0) + { + if (table.Entries[result.EntryIndex].Key == key) + break; + + result.PrevIndex = result.EntryIndex; + result.EntryIndex = table.Entries[result.EntryIndex].Next; + } + } + + return result; +} + +template forceinline +bool hashtable_full(HashTable table) { + GEN_ASSERT_NOT_NULL(table.Hashes); + GEN_ASSERT_NOT_NULL(table.Entries); + usize critical_load = usize(HashTable_CriticalLoadScale * f32(array_num(table.Hashes))); + b32 result = array_num(table.Entries) > critical_load; + return result; +} + +#define hashtable_init(type, allocator) hashtable_init (allocator) +#define hashtable_init_reserve(type, allocator, num) hashtable_init_reserve(allocator, num) +#define hashtable_clear(table) hashtable_clear < get_hashtable_underlying_type(table) >(table) +#define hashtable_destroy(table) hashtable_destroy < get_hashtable_underlying_type(table) >(& table) +#define hashtable_get(table, key) hashtable_get < get_hashtable_underlying_type(table) >(table, key) +#define hashtable_grow(table) hashtable_grow < get_hashtable_underlying_type(table) >(& table) +#define hashtable_rehash(table, new_num) hashtable_rehash < get_hashtable_underlying_type(table) >(& table, new_num) +#define hashtable_rehash_fast(table) hashtable_rehash_fast < get_hashtable_underlying_type(table) >(table) +#define hashtable_remove(table, key) hashtable_remove < get_hashtable_underlying_type(table) >(table, key) +#define hashtable_remove_entry(table, idx) hashtable_remove_entry< get_hashtable_underlying_type(table) >(table, idx) +#define hashtable_set(table, key, value) hashtable_set < get_hashtable_underlying_type(table) >(& table, key, value) +#define hashtable_slot(table, key) hashtable_slot < get_hashtable_underlying_type(table) >(table, key) +#define hashtable_map(table, map_proc) hashtable_map < get_hashtable_underlying_type(table) >(table, map_proc) +#define hashtable_map_mut(table, map_proc) hashtable_map_mut < get_hashtable_underlying_type(table) >(table, map_proc) + +//#define hashtable_add_entry(table, key) hashtable_add_entry < get_hashtable_underlying_type(table) >(& table, key) +//#define hashtable_find(table, key) hashtable_find < get_hashtable_underlying_type(table) >(table, key) +//#define hashtable_full(table) hashtable_full < get_hashtable_underlying_type(table) >(table) + +#pragma endregion HashTable + #pragma endregion Containers #pragma region Hashing -u32 crc32( void const* data, sw len ); -u64 crc64( void const* data, sw len ); +u32 crc32( void const* data, ssize len ); +u64 crc64( void const* data, ssize len ); #pragma endregion Hashing #pragma region Strings -// Constant string with length. -struct StrC -{ - sw Len; - char const* Ptr; +struct Str; - operator char const*() const - { - return Ptr; - } +Str to_str_from_c_str (char const* bad_string); +bool str_are_equal (Str lhs, Str rhs); +char const* str_back (Str str); +bool str_contains (Str str, Str substring); +Str str_duplicate (Str str, AllocatorInfo allocator); +b32 str_starts_with (Str str, Str substring); +Str str_visualize_whitespace(Str str, AllocatorInfo allocator); + +// Constant string with length. +struct Str +{ + char const* Ptr; + ssize Len; + +#if GEN_COMPILER_CPP + forceinline operator char const* () const { return Ptr; } + forceinline char const& operator[]( ssize index ) const { return Ptr[index]; } + +#if ! GEN_C_LIKE_CPP + forceinline bool is_equal (Str rhs) const { return str_are_equal(* this, rhs); } + forceinline char const* back () const { return str_back(* this); } + forceinline bool contains (Str substring) const { return str_contains(* this, substring); } + forceinline Str duplicate (AllocatorInfo allocator) const { return str_duplicate(* this, allocator); } + forceinline b32 starts_with (Str substring) const { return str_starts_with(* this, substring); } + forceinline Str visualize_whitespace(AllocatorInfo allocator) const { return str_visualize_whitespace(* this, allocator); } +#endif +#endif }; -#define cast_to_strc( str ) *rcast( StrC*, str - sizeof( sw ) ) -#define txt( text ) \ - StrC \ - { \ - sizeof( text ) - 1, text \ - } +#define cast_to_str( str ) * rcast( Str*, (str) - sizeof(ssize) ) -StrC to_str( char const* str ) +#ifndef txt +# if GEN_COMPILER_CPP +# define txt( text ) GEN_NS Str { ( text ), sizeof( text ) - 1 } +# else +# define txt( text ) (GEN_NS Str){ ( text ), sizeof( text ) - 1 } +# endif +#endif + +GEN_API_C_BEGIN +forceinline char const* str_begin(Str str) { return str.Ptr; } +forceinline char const* str_end (Str str) { return str.Ptr + str.Len; } +forceinline char const* str_next (Str str, char const* iter) { return iter + 1; } +GEN_API_C_END + +#if GEN_COMPILER_CPP +forceinline char const* begin(Str str) { return str.Ptr; } +forceinline char const* end (Str str) { return str.Ptr + str.Len; } +forceinline char const* next (Str str, char const* iter) { return iter + 1; } +#endif + +inline +bool str_are_equal(Str lhs, Str rhs) { - return { str_len( str ), str }; + if (lhs.Len != rhs.Len) + return false; + + for (ssize idx = 0; idx < lhs.Len; ++idx) + if (lhs.Ptr[idx] != rhs.Ptr[idx]) + return false; + + return true; } -// Dynamic String +inline +char const* str_back(Str str) { + return & str.Ptr[str.Len - 1]; +} + +inline +bool str_contains(Str str, Str substring) +{ + if (substring.Len > str.Len) + return false; + + ssize main_len = str.Len; + ssize sub_len = substring.Len; + for (ssize idx = 0; idx <= main_len - sub_len; ++idx) + { + if (c_str_compare_len(str.Ptr + idx, substring.Ptr, sub_len) == 0) + return true; + } + return false; +} + +inline +b32 str_starts_with(Str str, Str substring) { + if (substring.Len > str.Len) + return false; + + b32 result = c_str_compare_len(str.Ptr, substring.Ptr, substring.Len) == 0; + return result; +} + +inline +Str to_str_from_c_str( char const* bad_str ) { + Str result = { bad_str, c_str_len( bad_str ) }; + return result; +} + +// Dynamic StrBuilder // 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. -struct String +#pragma region StrBuilder +struct StrBuilderHeader; + +#if GEN_COMPILER_C +typedef char* StrBuilder; +#else +struct StrBuilder; +#endif + +forceinline usize strbuilder_grow_formula(usize value); + +StrBuilder strbuilder_make_c_str (AllocatorInfo allocator, char const* str); +StrBuilder strbuilder_make_str (AllocatorInfo allocator, Str str); +StrBuilder strbuilder_make_reserve (AllocatorInfo allocator, ssize capacity); +StrBuilder strbuilder_make_length (AllocatorInfo allocator, char const* str, ssize length); +StrBuilder strbuilder_fmt (AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...); +StrBuilder strbuilder_fmt_buf (AllocatorInfo allocator, char const* fmt, ...); +StrBuilder strbuilder_join (AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue); +bool strbuilder_are_equal (StrBuilder const lhs, StrBuilder const rhs); +bool strbuilder_are_equal_str (StrBuilder const lhs, Str rhs); +bool strbuilder_make_space_for (StrBuilder* str, char const* to_append, ssize add_len); +bool strbuilder_append_char (StrBuilder* str, char c); +bool strbuilder_append_c_str (StrBuilder* str, char const* c_str_to_append); +bool strbuilder_append_c_str_len (StrBuilder* str, char const* c_str_to_append, ssize length); +bool strbuilder_append_str (StrBuilder* str, Str c_str_to_append); +bool strbuilder_append_string (StrBuilder* str, StrBuilder const other); +bool strbuilder_append_fmt (StrBuilder* str, char const* fmt, ...); +ssize strbuilder_avail_space (StrBuilder const str); +char* strbuilder_back (StrBuilder str); +bool strbuilder_contains_str (StrBuilder const str, Str substring); +bool strbuilder_contains_string (StrBuilder const str, StrBuilder const substring); +ssize strbuilder_capacity (StrBuilder const str); +void strbuilder_clear (StrBuilder str); +StrBuilder strbuilder_duplicate (StrBuilder const str, AllocatorInfo allocator); +void strbuilder_free (StrBuilder* str); +StrBuilderHeader* strbuilder_get_header (StrBuilder str); +ssize strbuilder_length (StrBuilder const str); +b32 strbuilder_starts_with_str (StrBuilder const str, Str substring); +b32 strbuilder_starts_with_string (StrBuilder const str, StrBuilder substring); +void strbuilder_skip_line (StrBuilder str); +void strbuilder_strip_space (StrBuilder str); +Str strbuilder_to_str (StrBuilder str); +void strbuilder_trim (StrBuilder str, char const* cut_set); +void strbuilder_trim_space (StrBuilder str); +StrBuilder strbuilder_visualize_whitespace(StrBuilder const str); + +struct StrBuilderHeader { + AllocatorInfo Allocator; + ssize Capacity; + ssize Length; +}; + +#if GEN_COMPILER_CPP +struct StrBuilder { - struct Header - { - AllocatorInfo Allocator; - sw Capacity; - sw Length; - }; + char* Data; - static uw grow_formula( uw 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 char*() { return Data; } + forceinline operator char const*() const { return Data; } + forceinline operator Str() const { return { Data, strbuilder_length(* this) }; } + + StrBuilder const& operator=(StrBuilder const& other) const { + if (this == &other) + return *this; + + StrBuilder* this_ = ccast(StrBuilder*, this); + this_->Data = other.Data; + + return *this; } - static String make( AllocatorInfo allocator, char const* str ) - { - sw length = str ? str_len( str ) : 0; - return make_length( allocator, str, length ); + forceinline char& operator[](ssize index) { return Data[index]; } + forceinline char const& operator[](ssize index) const { return Data[index]; } + + forceinline bool operator==(std::nullptr_t) const { return Data == nullptr; } + forceinline bool operator!=(std::nullptr_t) const { return Data != nullptr; } + friend forceinline bool operator==(std::nullptr_t, const StrBuilder str) { return str.Data == nullptr; } + friend forceinline bool operator!=(std::nullptr_t, const StrBuilder str) { return str.Data != nullptr; } + +#if ! GEN_C_LIKE_CPP + forceinline char* begin() const { return Data; } + forceinline char* end() const { return Data + strbuilder_length(* this); } + +#pragma region Member Mapping + forceinline static StrBuilder make(AllocatorInfo allocator, char const* str) { return strbuilder_make_c_str(allocator, str); } + forceinline static StrBuilder make(AllocatorInfo allocator, Str str) { return strbuilder_make_str(allocator, str); } + forceinline static StrBuilder make_reserve(AllocatorInfo allocator, ssize cap) { return strbuilder_make_reserve(allocator, cap); } + forceinline static StrBuilder make_length(AllocatorInfo a, char const* s, ssize l) { return strbuilder_make_length(a, s, l); } + forceinline static StrBuilder join(AllocatorInfo a, char const** p, ssize n, char const* g) { return strbuilder_join(a, p, n, g); } + forceinline static usize grow_formula(usize value) { return strbuilder_grow_formula(value); } + + static + StrBuilder fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) { + va_list va; + va_start(va, fmt); + ssize res = c_str_fmt_va(buf, buf_size, fmt, va) - 1; + va_end(va); + return strbuilder_make_length(allocator, buf, res); } - static String make( AllocatorInfo allocator, StrC str ) - { - return make_length( allocator, str.Ptr, str.Len ); + static + StrBuilder fmt_buf(AllocatorInfo allocator, char const* fmt, ...) { + local_persist thread_local + char buf[GEN_PRINTF_MAXLEN] = { 0 }; + va_list va; + va_start(va, fmt); + ssize res = c_str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va) - 1; + va_end(va); + return strbuilder_make_length(allocator, buf, res); } - static String make_reserve( AllocatorInfo allocator, sw capacity ); + forceinline bool make_space_for(char const* str, ssize add_len) { return strbuilder_make_space_for(this, str, add_len); } + forceinline bool append(char c) { return strbuilder_append_char(this, c); } + forceinline bool append(char const* str) { return strbuilder_append_c_str(this, str); } + forceinline bool append(char const* str, ssize length) { return strbuilder_append_c_str_len(this, str, length); } + forceinline bool append(Str str) { return strbuilder_append_str(this, str); } + forceinline bool append(const StrBuilder other) { return strbuilder_append_string(this, other); } + forceinline ssize avail_space() const { return strbuilder_avail_space(* this); } + forceinline char* back() { return strbuilder_back(* this); } + forceinline bool contains(Str substring) const { return strbuilder_contains_str(* this, substring); } + forceinline bool contains(StrBuilder const& substring) const { return strbuilder_contains_string(* this, substring); } + forceinline ssize capacity() const { return strbuilder_capacity(* this); } + forceinline void clear() { strbuilder_clear(* this); } + forceinline StrBuilder duplicate(AllocatorInfo allocator) const { return strbuilder_duplicate(* this, allocator); } + forceinline void free() { strbuilder_free(this); } + forceinline bool is_equal(StrBuilder const& other) const { return strbuilder_are_equal(* this, other); } + forceinline bool is_equal(Str other) const { return strbuilder_are_equal_str(* this, other); } + forceinline ssize length() const { return strbuilder_length(* this); } + forceinline b32 starts_with(Str substring) const { return strbuilder_starts_with_str(* this, substring); } + forceinline b32 starts_with(StrBuilder substring) const { return strbuilder_starts_with_string(* this, substring); } + forceinline void skip_line() { strbuilder_skip_line(* this); } + forceinline void strip_space() { strbuilder_strip_space(* this); } + forceinline Str to_str() { return { Data, strbuilder_length(*this) }; } + forceinline void trim(char const* cut_set) { strbuilder_trim(* this, cut_set); } + forceinline void trim_space() { strbuilder_trim_space(* this); } + forceinline StrBuilder visualize_whitespace() const { return strbuilder_visualize_whitespace(* this); } + forceinline StrBuilderHeader& get_header() { return * strbuilder_get_header(* this); } - static String make_length( AllocatorInfo allocator, char const* str, sw length ); + bool append_fmt(char const* fmt, ...) { + ssize res; + char buf[GEN_PRINTF_MAXLEN] = { 0 }; - static String fmt( AllocatorInfo allocator, char* buf, sw buf_size, char const* fmt, ... ); + va_list va; + va_start(va, fmt); + res = c_str_fmt_va(buf, count_of(buf) - 1, fmt, va) - 1; + va_end(va); - static String fmt_buf( AllocatorInfo allocator, char const* fmt, ... ); + return strbuilder_append_c_str_len(this, buf, res); + } +#pragma endregion Member Mapping +#endif +}; +#endif - static String join( AllocatorInfo allocator, char const** parts, sw num_parts, char const* glue ) +forceinline char* strbuilder_begin(StrBuilder str) { return ((char*) str); } +forceinline char* strbuilder_end (StrBuilder str) { return ((char*) str + strbuilder_length(str)); } +forceinline char* strbuilder_next (StrBuilder str, char const* iter) { return ((char*) iter + 1); } + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +forceinline char* begin(StrBuilder str) { return ((char*) str); } +forceinline char* end (StrBuilder str) { return ((char*) str + strbuilder_length(str)); } +forceinline char* next (StrBuilder str, char* iter) { return ((char*) iter + 1); } +#endif + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +forceinline bool make_space_for(StrBuilder& str, char const* to_append, ssize add_len); +forceinline bool append(StrBuilder& str, char c); +forceinline bool append(StrBuilder& str, char const* c_str_to_append); +forceinline bool append(StrBuilder& str, char const* c_str_to_append, ssize length); +forceinline bool append(StrBuilder& str, Str c_str_to_append); +forceinline bool append(StrBuilder& str, const StrBuilder other); +forceinline bool append_fmt(StrBuilder& str, char const* fmt, ...); +forceinline char& back(StrBuilder& str); +forceinline void clear(StrBuilder& str); +forceinline void free(StrBuilder& str); +#endif + +forceinline +usize strbuilder_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 +StrBuilder strbuilder_make_c_str(AllocatorInfo allocator, char const* str) { + ssize length = str ? c_str_len(str) : 0; + return strbuilder_make_length(allocator, str, length); +} + +forceinline +StrBuilder strbuilder_make_str(AllocatorInfo allocator, Str str) { + return strbuilder_make_length(allocator, str.Ptr, str.Len); +} + +inline +StrBuilder strbuilder_fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) { + va_list va; + va_start(va, fmt); + ssize res = c_str_fmt_va(buf, buf_size, fmt, va) - 1; + va_end(va); + + return strbuilder_make_length(allocator, buf, res); +} + +inline +StrBuilder strbuilder_fmt_buf(AllocatorInfo allocator, char const* fmt, ...) +{ + local_persist thread_local + PrintF_Buffer buf = struct_init(PrintF_Buffer, {0}); + + va_list va; + va_start(va, fmt); + ssize res = c_str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va) -1; + va_end(va); + + return strbuilder_make_length(allocator, buf, res); +} + +inline +StrBuilder strbuilder_join(AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue) +{ + StrBuilder result = strbuilder_make_c_str(allocator, ""); + + for (ssize idx = 0; idx < num_parts; ++idx) { - String result = make( allocator, "" ); + strbuilder_append_c_str(& result, parts[idx]); - for ( sw idx = 0; idx < num_parts; ++idx ) - { - result.append( parts[ idx ] ); - - if ( idx < num_parts - 1 ) - result.append( glue ); - } - - return result; + if (idx < num_parts - 1) + strbuilder_append_c_str(& result, glue); } - static bool are_equal( String lhs, String rhs ) + return result; +} + +forceinline +bool strbuilder_append_char(StrBuilder* str, char c) { + GEN_ASSERT(str != nullptr); + return strbuilder_append_c_str_len( str, (char const*)& c, (ssize)1); +} + +forceinline +bool strbuilder_append_c_str(StrBuilder* str, char const* c_str_to_append) { + GEN_ASSERT(str != nullptr); + return strbuilder_append_c_str_len(str, c_str_to_append, c_str_len(c_str_to_append)); +} + +inline +bool strbuilder_append_c_str_len(StrBuilder* str, char const* c_str_to_append, ssize append_length) +{ + GEN_ASSERT(str != nullptr); + if ( rcast(sptr, c_str_to_append) > 0) { - if ( lhs.length() != rhs.length() ) + ssize curr_len = strbuilder_length(* str); + + if ( ! strbuilder_make_space_for(str, c_str_to_append, append_length)) return false; - for ( sw idx = 0; idx < lhs.length(); ++idx ) - if ( lhs[ idx ] != rhs[ idx ] ) - return false; + StrBuilderHeader* header = strbuilder_get_header(* str); + + char* Data = * str; + mem_copy( Data + curr_len, c_str_to_append, append_length); + + Data[curr_len + append_length] = '\0'; + + header->Length = curr_len + append_length; + } + return c_str_to_append != nullptr; +} + +forceinline +bool strbuilder_append_str(StrBuilder* str, Str c_str_to_append) { + GEN_ASSERT(str != nullptr); + return strbuilder_append_c_str_len(str, c_str_to_append.Ptr, c_str_to_append.Len); +} + +forceinline +bool strbuilder_append_string(StrBuilder* str, StrBuilder const other) { + GEN_ASSERT(str != nullptr); + return strbuilder_append_c_str_len(str, (char const*)other, strbuilder_length(other)); +} + +bool strbuilder_append_fmt(StrBuilder* str, char const* fmt, ...) { + GEN_ASSERT(str != nullptr); + ssize res; + char buf[GEN_PRINTF_MAXLEN] = { 0 }; + + va_list va; + va_start(va, fmt); + res = c_str_fmt_va(buf, count_of(buf) - 1, fmt, va) - 1; + va_end(va); + + return strbuilder_append_c_str_len(str, (char const*)buf, res); +} + +inline +bool strbuilder_are_equal_string(StrBuilder const lhs, StrBuilder const rhs) +{ + if (strbuilder_length(lhs) != strbuilder_length(rhs)) + return false; + + for (ssize idx = 0; idx < strbuilder_length(lhs); ++idx) + if (lhs[idx] != rhs[idx]) + return false; + + return true; +} + +inline +bool strbuilder_are_equal_str(StrBuilder const lhs, Str rhs) +{ + if (strbuilder_length(lhs) != (rhs.Len)) + return false; + + for (ssize idx = 0; idx < strbuilder_length(lhs); ++idx) + if (lhs[idx] != rhs.Ptr[idx]) + return false; + + return true; +} + +forceinline +ssize strbuilder_avail_space(StrBuilder const str) { + StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader)); + return header->Capacity - header->Length; +} + +forceinline +char* strbuilder_back(StrBuilder str) { + return & (str)[strbuilder_length(str) - 1]; +} + +inline +bool strbuilder_contains_StrC(StrBuilder const str, Str substring) +{ + StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader)); + + 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 (c_str_compare_len(str + idx, substring.Ptr, sub_len) == 0) + return true; + } + + return false; +} + +inline +bool strbuilder_contains_string(StrBuilder const str, StrBuilder const substring) +{ + StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader)); + + if (strbuilder_length(substring) > header->Length) + return false; + + ssize main_len = header->Length; + ssize sub_len = strbuilder_length(substring); + + for (ssize idx = 0; idx <= main_len - sub_len; ++idx) + { + if (c_str_compare_len(str + idx, substring, sub_len) == 0) + return true; + } + + return false; +} + +forceinline +ssize strbuilder_capacity(StrBuilder const str) { + StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader)); + return header->Capacity; +} + +forceinline +void strbuilder_clear(StrBuilder str) { + strbuilder_get_header(str)->Length = 0; +} + +forceinline +StrBuilder strbuilder_duplicate(StrBuilder const str, AllocatorInfo allocator) { + return strbuilder_make_length(allocator, str, strbuilder_length(str)); +} + +forceinline +void strbuilder_free(StrBuilder* str) { + GEN_ASSERT(str != nullptr); + if (! (* str)) + return; + + StrBuilderHeader* header = strbuilder_get_header(* str); + allocator_free(header->Allocator, header); +} + +forceinline +StrBuilderHeader* strbuilder_get_header(StrBuilder str) { + return (StrBuilderHeader*)(scast(char*, str) - sizeof(StrBuilderHeader)); +} + +forceinline +ssize strbuilder_length(StrBuilder const str) +{ + StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader)); + return header->Length; +} + +inline +bool strbuilder_make_space_for(StrBuilder* str, char const* to_append, ssize add_len) +{ + ssize available = strbuilder_avail_space(* str); + + if (available >= add_len) { + return true; + } + else + { + ssize new_len, old_size, new_size; + void* ptr; + void* new_ptr; + + AllocatorInfo allocator = strbuilder_get_header(* str)->Allocator; + StrBuilderHeader* header = nullptr; + + new_len = strbuilder_grow_formula(strbuilder_length(* str) + add_len); + ptr = strbuilder_get_header(* str); + old_size = size_of(StrBuilderHeader) + strbuilder_length(* str) + 1; + new_size = size_of(StrBuilderHeader) + new_len + 1; + + new_ptr = resize(allocator, ptr, old_size, new_size); + + if (new_ptr == nullptr) + return false; + + header = rcast(StrBuilderHeader*, new_ptr); + header->Allocator = allocator; + header->Capacity = new_len; + + char** Data = rcast(char**, str); + * Data = rcast(char*, header + 1); return true; } +} - bool make_space_for( char const* str, sw add_len ); +forceinline +b32 strbuilder_starts_with_str(StrBuilder const str, Str substring) { + if (substring.Len > strbuilder_length(str)) + return false; - bool append( char c ) - { - return append( &c, 1 ); - } + b32 result = c_str_compare_len(str, substring.Ptr, substring.Len) == 0; + return result; +} - bool append( char const* str ) - { - return append( str, str_len( str ) ); - } +forceinline +b32 strbuilder_starts_with_string(StrBuilder const str, StrBuilder substring) { + if (strbuilder_length(substring) > strbuilder_length(str)) + return false; - bool append( char const* str, sw length ) - { - if ( sptr( str ) > 0 ) - { - sw curr_len = this->length(); + b32 result = c_str_compare_len(str, substring, strbuilder_length(substring) - 1) == 0; + return result; +} - 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; - } - - 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, ... ); - - sw avail_space() const - { - Header const& header = *rcast( Header const*, Data - sizeof( Header ) ); - - return header.Capacity - header.Length; - } - - char& back() - { - return Data[ length() - 1 ]; - } - - sw capacity() const - { - Header const& header = *rcast( Header const*, Data - sizeof( Header ) ); - - return header.Capacity; - } - - void clear() - { - get_header().Length = 0; - } - - String duplicate( AllocatorInfo allocator ) - { - 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 ) ); - } - - sw length() const - { - Header const& header = *rcast( Header const*, Data - sizeof( Header ) ); - - return header.Length; - } - - 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 ) - { - sw 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( sw, ( 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; - } - - 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 ) - return *this; - - String& this_ = ccast( String, *this ); - - this_.Data = other.Data; - - return this_; - } - - char& operator[]( sw index ) - { - return Data[ index ]; - } - - char const& operator[]( sw index ) const - { - return Data[ index ]; - } - - char* Data; -}; - -struct String_POD +inline +void strbuilder_skip_line(StrBuilder str) { +#define current (*scanner) + char* scanner = str; + while (current != '\r' && current != '\n') { + ++scanner; + } + + s32 new_length = scanner - str; + + if (current == '\r') { + new_length += 1; + } + + mem_move((char*)str, scanner, new_length); + + StrBuilderHeader* header = strbuilder_get_header(str); + header->Length = new_length; +#undef current +} + +inline +void strbuilder_strip_space(StrBuilder 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 + strbuilder_get_header(str)->Length = write_pos - str; +} + +forceinline +Str strbuilder_to_str(StrBuilder str) { + Str result = { (char const*)str, strbuilder_length(str) }; + return result; +} + +inline +void strbuilder_trim(StrBuilder str, char const* cut_set) +{ + ssize len = 0; + + char* start_pos = str; + char* end_pos = scast(char*, str) + strbuilder_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 != start_pos) + mem_move(str, start_pos, len); + + str[len] = '\0'; + + strbuilder_get_header(str)->Length = len; +} + +forceinline +void strbuilder_trim_space(StrBuilder str) { + strbuilder_trim(str, " \t\r\n\v\f"); +} + +inline +StrBuilder strbuilder_visualize_whitespace(StrBuilder const str) +{ + StrBuilderHeader* header = (StrBuilderHeader*)(scast(char const*, str) - sizeof(StrBuilderHeader)); + StrBuilder result = strbuilder_make_reserve(header->Allocator, strbuilder_length(str) * 2); // Assume worst case for space requirements. + + for (char const* c = strbuilder_begin(str); c != strbuilder_end(str); c = strbuilder_next(str, c)) + switch ( * c ) + { + case ' ': + strbuilder_append_str(& result, txt("·")); + break; + case '\t': + strbuilder_append_str(& result, txt("→")); + break; + case '\n': + strbuilder_append_str(& result, txt("↵")); + break; + case '\r': + strbuilder_append_str(& result, txt("⏎")); + break; + case '\v': + strbuilder_append_str(& result, txt("⇕")); + break; + case '\f': + strbuilder_append_str(& result, txt("⌂")); + break; + default: + strbuilder_append_char(& result, * c); + break; + } + + return result; +} +#pragma endregion StrBuilder + +#if GEN_COMPILER_CPP +struct StrBuilder_POD { char* Data; }; +static_assert( sizeof( StrBuilder_POD ) == sizeof( StrBuilder ), "StrBuilder is not a POD" ); +#endif -static_assert( sizeof( String_POD ) == sizeof( String ), "String is not a POD" ); +forceinline +Str str_duplicate(Str str, AllocatorInfo allocator) { + Str result = strbuilder_to_str( strbuilder_make_length(allocator, str.Ptr, str.Len)); + return result; +} -// Implements basic string interning. Data structure is based off the ZPL Hashtable. -using StringTable = HashTable< String const >; +inline +Str str_visualize_whitespace(Str str, AllocatorInfo allocator) +{ + StrBuilder result = strbuilder_make_reserve(allocator, str.Len * 2); // Assume worst case for space requirements. + for (char const* c = str_begin(str); c != str_end(str); c = str_next(str, c)) + switch ( * c ) + { + case ' ': + strbuilder_append_str(& result, txt("·")); + break; + case '\t': + strbuilder_append_str(& result, txt("→")); + break; + case '\n': + strbuilder_append_str(& result, txt("↵")); + break; + case '\r': + strbuilder_append_str(& result, txt("⏎")); + break; + case '\v': + strbuilder_append_str(& result, txt("⇕")); + break; + case '\f': + strbuilder_append_str(& result, txt("⌂")); + break; + default: + strbuilder_append_char(& result, * c); + break; +} + return strbuilder_to_str(result); +} // 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 Str StrCached; +// Implements basic string interning. Data structure is based off the ZPL Hashtable. +typedef HashTable(StrCached) StringTable; #pragma endregion Strings #pragma region File Handling -typedef u32 FileMode; - enum FileModeFlag { EFileMode_READ = bit( 0 ), @@ -2501,11 +3291,12 @@ union FileDescriptor uptr u; }; +typedef u32 FileMode; typedef struct FileOperations FileOperations; #define GEN_FILE_OPEN_PROC( name ) FileError name( FileDescriptor* fd, FileOperations* ops, FileMode mode, char const* filename ) -#define GEN_FILE_READ_AT_PROC( name ) b32 name( FileDescriptor fd, void* buffer, sw size, s64 offset, sw* bytes_read, b32 stop_at_newline ) -#define GEN_FILE_WRITE_AT_PROC( name ) b32 name( FileDescriptor fd, void const* buffer, sw size, s64 offset, sw* bytes_written ) +#define GEN_FILE_READ_AT_PROC( name ) b32 name( FileDescriptor fd, void* buffer, ssize size, s64 offset, ssize* bytes_read, b32 stop_at_newline ) +#define GEN_FILE_WRITE_AT_PROC( name ) b32 name( FileDescriptor fd, mem_ptr_const buffer, ssize size, s64 offset, ssize* bytes_written ) #define GEN_FILE_SEEK_PROC( name ) b32 name( FileDescriptor fd, s64 offset, SeekWhenceType whence, s64* new_offset ) #define GEN_FILE_CLOSE_PROC( name ) void name( FileDescriptor fd ) @@ -2538,9 +3329,9 @@ struct DirInfo; struct DirEntry { - char const* filename; - struct DirInfo* dir_info; - u8 type; + char const* filename; + DirInfo* dir_info; + u8 type; }; struct DirInfo @@ -2550,7 +3341,7 @@ struct DirInfo // Internals char** filenames; // zpl_array - String buf; + StrBuilder buf; }; struct FileInfo @@ -2574,145 +3365,186 @@ enum FileStandardType }; /** - * Get standard file I/O. - * @param std Check zpl_file_standard_type - * @return File handle to standard I/O - */ + * Get standard file I/O. + * @param std Check zpl_file_standard_type + * @return File handle to standard I/O + */ FileInfo* file_get_standard( FileStandardType std ); /** - * Closes the file - * @param file - */ + * Closes the file + * @param file + */ FileError file_close( FileInfo* file ); /** - * Returns the currently opened file's name - * @param file - */ -inline char const* file_name( FileInfo* file ) + * Returns the currently opened file's name + * @param file + */ +inline + char const* file_name( FileInfo* file ) { return file->filename ? file->filename : ""; } /** - * Opens a file - * @param file - * @param filename - */ + * Opens a file + * @param file + * @param filename + */ FileError file_open( FileInfo* file, char const* filename ); /** - * Opens a file using a specified mode - * @param file - * @param mode Access mode to use - * @param filename - */ + * Opens a file using a specified mode + * @param file + * @param mode Access mode to use + * @param filename + */ FileError file_open_mode( FileInfo* file, FileMode mode, char const* filename ); /** - * Reads from a file - * @param file - * @param buffer Buffer to read to - * @param size Size to read - */ -GEN_DEF_INLINE b32 file_read( FileInfo* file, void* buffer, sw size ); + * Reads from a file + * @param file + * @param buffer Buffer to read to + * @param size Size to read + */ +b32 file_read( FileInfo* file, void* buffer, ssize size ); /** - * Reads file at a specific offset - * @param file - * @param buffer Buffer to read to - * @param size Size to read - * @param offset Offset to read from - * @param bytes_read How much data we've actually read - */ -GEN_DEF_INLINE b32 file_read_at( FileInfo* file, void* buffer, sw size, s64 offset ); + * Reads file at a specific offset + * @param file + * @param buffer Buffer to read to + * @param size Size to read + * @param offset Offset to read from + * @param bytes_read How much data we've actually read + */ +b32 file_read_at( FileInfo* file, void* buffer, ssize size, s64 offset ); /** - * Reads file safely - * @param file - * @param buffer Buffer to read to - * @param size Size to read - * @param offset Offset to read from - * @param bytes_read How much data we've actually read - */ -GEN_DEF_INLINE b32 file_read_at_check( FileInfo* file, void* buffer, sw size, s64 offset, sw* bytes_read ); + * Reads file safely + * @param file + * @param buffer Buffer to read to + * @param size Size to read + * @param offset Offset to read from + * @param bytes_read How much data we've actually read + */ +b32 file_read_at_check( FileInfo* file, void* buffer, ssize size, s64 offset, ssize* bytes_read ); +typedef struct FileContents FileContents; struct FileContents { AllocatorInfo allocator; void* data; - sw size; + ssize size; }; -constexpr b32 zero_terminate = true; -constexpr b32 no_zero_terminate = false; +constexpr b32 file_zero_terminate = true; +constexpr b32 file_no_zero_terminate = false; /** - * Reads the whole file contents - * @param a Allocator to use - * @param zero_terminate End the read data with null terminator - * @param filepath Path to the file - * @return File contents data - */ + * Reads the whole file contents + * @param a Allocator to use + * @param zero_terminate End the read data with null terminator + * @param filepath Path to the file + * @return File contents data + */ FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const* filepath ); /** - * Returns a size of the file - * @param file - * @return File size - */ + * Returns a size of the file + * @param file + * @return File size + */ s64 file_size( FileInfo* file ); /** - * Seeks the file cursor from the beginning of file to a specific position - * @param file - * @param offset Offset to seek to - */ -GEN_DEF_INLINE s64 file_seek( FileInfo* file, s64 offset ); + * Seeks the file cursor from the beginning of file to a specific position + * @param file + * @param offset Offset to seek to + */ +s64 file_seek( FileInfo* file, s64 offset ); /** - * Seeks the file cursor to the end of the file - * @param file - */ -GEN_DEF_INLINE s64 file_seek_to_end( FileInfo* file ); + * Seeks the file cursor to the end of the file + * @param file + */ +s64 file_seek_to_end( FileInfo* file ); /** - * Returns the length from the beginning of the file we've read so far - * @param file - * @return Our current position in file - */ -GEN_DEF_INLINE s64 file_tell( FileInfo* file ); + * Returns the length from the beginning of the file we've read so far + * @param file + * @return Our current position in file + */ +s64 file_tell( FileInfo* file ); /** - * Writes to a file - * @param file - * @param buffer Buffer to read from - * @param size Size to read - */ -GEN_DEF_INLINE b32 file_write( FileInfo* file, void const* buffer, sw size ); + * Writes to a file + * @param file + * @param buffer Buffer to read from + * @param size Size to read + */ +b32 file_write( FileInfo* file, void const* buffer, ssize size ); /** - * Writes to file at a specific offset - * @param file - * @param buffer Buffer to read from - * @param size Size to write - * @param offset Offset to write to - * @param bytes_written How much data we've actually written - */ -GEN_DEF_INLINE b32 file_write_at( FileInfo* file, void const* buffer, sw size, s64 offset ); + * Writes to file at a specific offset + * @param file + * @param buffer Buffer to read from + * @param size Size to write + * @param offset Offset to write to + * @param bytes_written How much data we've actually written + */ +b32 file_write_at( FileInfo* file, void const* buffer, ssize size, s64 offset ); /** - * Writes to file safely - * @param file - * @param buffer Buffer to read from - * @param size Size to write - * @param offset Offset to write to - * @param bytes_written How much data we've actually written - */ -GEN_DEF_INLINE b32 file_write_at_check( FileInfo* file, void const* buffer, sw size, s64 offset, sw* bytes_written ); + * Writes to file safely + * @param file + * @param buffer Buffer to read from + * @param size Size to write + * @param offset Offset to write to + * @param bytes_written How much data we've actually written + */ +b32 file_write_at_check( FileInfo* file, void const* buffer, ssize size, s64 offset, ssize* bytes_written ); -GEN_IMPL_INLINE s64 file_seek( FileInfo* f, s64 offset ) +enum FileStreamFlags : u32 +{ + /* Allows us to write to the buffer directly. Beware: you can not append a new data! */ + EFileStream_WRITABLE = bit( 0 ), + + /* Clones the input buffer so you can write (zpl_file_write*) data into it. */ + /* Since we work with a clone, the buffer size can dynamically grow as well. */ + EFileStream_CLONE_WRITABLE = bit( 1 ), + + EFileStream_UNDERLYING = GEN_U32_MAX, +}; + +/** + * Opens a new memory stream + * @param file + * @param allocator + */ +b8 file_stream_new( FileInfo* file, AllocatorInfo allocator ); + +/** + * Opens a memory stream over an existing buffer + * @param file + * @param allocator + * @param buffer Memory to create stream from + * @param size Buffer's size + * @param flags + */ +b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize size, FileStreamFlags flags ); + +/** + * Retrieves the stream's underlying buffer and buffer size. + * @param file memory stream + * @param size (Optional) buffer size + */ +u8* file_stream_buf( FileInfo* file, ssize* size ); + +extern FileOperations const memory_file_operations; + +inline +s64 file_seek( FileInfo* f, s64 offset ) { s64 new_offset = 0; @@ -2724,7 +3556,8 @@ GEN_IMPL_INLINE s64 file_seek( FileInfo* f, s64 offset ) return new_offset; } -GEN_IMPL_INLINE s64 file_seek_to_end( FileInfo* f ) +inline +s64 file_seek_to_end( FileInfo* f ) { s64 new_offset = 0; @@ -2736,7 +3569,8 @@ GEN_IMPL_INLINE s64 file_seek_to_end( FileInfo* f ) return new_offset; } -GEN_IMPL_INLINE s64 file_tell( FileInfo* f ) +inline +s64 file_tell( FileInfo* f ) { s64 new_offset = 0; @@ -2748,7 +3582,8 @@ GEN_IMPL_INLINE s64 file_tell( FileInfo* f ) return new_offset; } -GEN_IMPL_INLINE b32 file_read( FileInfo* f, void* buffer, sw size ) +inline +b32 file_read( FileInfo* f, void* buffer, ssize size ) { s64 cur_offset = file_tell( f ); b32 result = file_read_at( f, buffer, size, file_tell( f ) ); @@ -2756,19 +3591,22 @@ GEN_IMPL_INLINE b32 file_read( FileInfo* f, void* buffer, sw size ) return result; } -GEN_IMPL_INLINE b32 file_read_at( FileInfo* f, void* buffer, sw size, s64 offset ) +inline +b32 file_read_at( FileInfo* f, void* buffer, ssize size, s64 offset ) { return file_read_at_check( f, buffer, size, offset, NULL ); } -GEN_IMPL_INLINE b32 file_read_at_check( FileInfo* f, void* buffer, sw size, s64 offset, sw* bytes_read ) +inline +b32 file_read_at_check( FileInfo* f, void* buffer, ssize size, s64 offset, ssize* bytes_read ) { if ( ! f->ops.read_at ) f->ops = default_file_operations; return f->ops.read_at( f->fd, buffer, size, offset, bytes_read, false ); } -GEN_IMPL_INLINE b32 file_write( FileInfo* f, void const* buffer, sw size ) +inline +b32 file_write( FileInfo* f, void const* buffer, ssize size ) { s64 cur_offset = file_tell( f ); b32 result = file_write_at( f, buffer, size, file_tell( f ) ); @@ -2778,12 +3616,14 @@ GEN_IMPL_INLINE b32 file_write( FileInfo* f, void const* buffer, sw size ) return result; } -GEN_IMPL_INLINE b32 file_write_at( FileInfo* f, void const* buffer, sw size, s64 offset ) +inline +b32 file_write_at( FileInfo* f, void const* buffer, ssize size, s64 offset ) { return file_write_at_check( f, buffer, size, offset, NULL ); } -GEN_IMPL_INLINE b32 file_write_at_check( FileInfo* f, void const* buffer, sw size, s64 offset, sw* bytes_written ) +inline +b32 file_write_at_check( FileInfo* f, void const* buffer, ssize size, s64 offset, ssize* bytes_written ) { if ( ! f->ops.read_at ) f->ops = default_file_operations; @@ -2791,42 +3631,6 @@ GEN_IMPL_INLINE b32 file_write_at_check( FileInfo* f, void const* buffer, sw siz return f->ops.write_at( f->fd, buffer, size, offset, bytes_written ); } -enum FileStreamFlags : u32 -{ - /* Allows us to write to the buffer directly. Beware: you can not append a new data! */ - EFileStream_WRITABLE = bit( 0 ), - - /* Clones the input buffer so you can write (zpl_file_write*) data into it. */ - /* Since we work with a clone, the buffer size can dynamically grow as well. */ - EFileStream_CLONE_WRITABLE = bit( 1 ), -}; - -/** - * Opens a new memory stream - * @param file - * @param allocator - */ -b8 file_stream_new( FileInfo* file, AllocatorInfo allocator ); - -/** - * Opens a memory stream over an existing buffer - * @param file - * @param allocator - * @param buffer Memory to create stream from - * @param size Buffer's size - * @param flags - */ -b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, sw size, FileStreamFlags flags ); - -/** - * Retrieves the stream's underlying buffer and buffer size. - * @param file memory stream - * @param size (Optional) buffer size - */ -u8* file_stream_buf( FileInfo* file, sw* size ); - -extern FileOperations const memory_file_operations; - #pragma endregion File Handling #pragma region Timing @@ -2844,8 +3648,6 @@ u64 time_rel_ms( void ); #pragma endregion Timing -#pragma region Parsing - #pragma region ADT enum ADT_Type : u32 @@ -2913,7 +3715,7 @@ struct ADT_Node /* properties */ ADT_Type type : 4; - u8 props : 4; + u8 props : 4; #ifndef GEN_PARSER_DISABLE_ANALYSIS u8 cfg_mode : 1; u8 name_style : 2; @@ -2926,8 +3728,8 @@ struct ADT_Node /* adt data */ union { - char const* string; - Array< ADT_Node > nodes; ///< zpl_array + char const* string; + Array(ADT_Node) nodes; ///< zpl_array struct { @@ -2951,283 +3753,283 @@ struct ADT_Node }; /* ADT NODE LIMITS - * delimiter and assignment segment width is limited to 128 whitespace symbols each. - * real number limits decimal position to 128 places. - * real number exponent is limited to 64 digits. - */ + * delimiter and assignment segment width is limited to 128 whitespace symbols each. + * real number limits decimal position to 128 places. + * real number exponent is limited to 64 digits. + */ /** - * @brief Initialise an ADT object or array - * - * @param node - * @param backing Memory allocator used for descendants - * @param name Node's name - * @param is_array - * @return error code - */ + * @brief Initialise an ADT object or array + * + * @param node + * @param backing Memory allocator used for descendants + * @param name Node's name + * @param is_array + * @return error code + */ u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32 is_array ); /** - * @brief Destroy an ADT branch and its descendants - * - * @param node - * @return error code - */ + * @brief Destroy an ADT branch and its descendants + * + * @param node + * @return error code + */ u8 adt_destroy_branch( ADT_Node* node ); /** - * @brief Initialise an ADT leaf - * - * @param node - * @param name Node's name - * @param type Node's type (use zpl_adt_make_branch for container nodes) - * @return error code - */ + * @brief Initialise an ADT leaf + * + * @param node + * @param name Node's name + * @param type Node's type (use zpl_adt_make_branch for container nodes) + * @return error code + */ u8 adt_make_leaf( ADT_Node* node, char const* name, ADT_Type type ); /** - * @brief Fetch a node using provided URI string. - * - * This method uses a basic syntax to fetch a node from the ADT. The following features are available - * to retrieve the data: - * - * - "a/b/c" navigates through objects "a" and "b" to get to "c" - * - "arr/[foo=123]/bar" iterates over "arr" to find any object with param "foo" that matches the value "123", then gets its field called "bar" - * - "arr/3" retrieves the 4th element in "arr" - * - "arr/[apple]" retrieves the first element of value "apple" in "arr" - * - * @param node ADT node - * @param uri Locator string as described above - * @return zpl_adt_node* - * - * @see code/apps/examples/json_get.c - */ + * @brief Fetch a node using provided URI string. + * + * This method uses a basic syntax to fetch a node from the ADT. The following features are available + * to retrieve the data: + * + * - "a/b/c" navigates through objects "a" and "b" to get to "c" + * - "arr/[foo=123]/bar" iterates over "arr" to find any object with param "foo" that matches the value "123", then gets its field called "bar" + * - "arr/3" retrieves the 4th element in "arr" + * - "arr/[apple]" retrieves the first element of value "apple" in "arr" + * + * @param node ADT node + * @param uri Locator string as described above + * @return zpl_adt_node* + * + * @see code/apps/examples/json_get.c + */ ADT_Node* adt_query( ADT_Node* node, char const* uri ); /** - * @brief Find a field node within an object by the given name. - * - * @param node - * @param name - * @param deep_search Perform search recursively - * @return zpl_adt_node * node - */ + * @brief Find a field node within an object by the given name. + * + * @param node + * @param name + * @param deep_search Perform search recursively + * @return zpl_adt_node * node + */ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ); /** - * @brief Allocate an unitialised node within a container at a specified index. - * - * @param parent - * @param index - * @return zpl_adt_node * node - */ -ADT_Node* adt_alloc_at( ADT_Node* parent, sw index ); + * @brief Allocate an unitialised node within a container at a specified index. + * + * @param parent + * @param index + * @return zpl_adt_node * node + */ +ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index ); /** - * @brief Allocate an unitialised node within a container. - * - * @param parent - * @return zpl_adt_node * node - */ + * @brief Allocate an unitialised node within a container. + * + * @param parent + * @return zpl_adt_node * node + */ ADT_Node* adt_alloc( ADT_Node* parent ); /** - * @brief Move an existing node to a new container at a specified index. - * - * @param node - * @param new_parent - * @param index - * @return zpl_adt_node * node - */ -ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, sw index ); + * @brief Move an existing node to a new container at a specified index. + * + * @param node + * @param new_parent + * @param index + * @return zpl_adt_node * node + */ +ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, ssize index ); /** - * @brief Move an existing node to a new container. - * - * @param node - * @param new_parent - * @return zpl_adt_node * node - */ + * @brief Move an existing node to a new container. + * + * @param node + * @param new_parent + * @return zpl_adt_node * node + */ ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent ); /** - * @brief Swap two nodes. - * - * @param node - * @param other_node - * @return - */ + * @brief Swap two nodes. + * + * @param node + * @param other_node + * @return + */ void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ); /** - * @brief Remove node from container. - * - * @param node - * @return - */ + * @brief Remove node from container. + * + * @param node + * @return + */ void adt_remove_node( ADT_Node* node ); /** - * @brief Initialise a node as an object - * - * @param obj - * @param name - * @param backing - * @return - */ + * @brief Initialise a node as an object + * + * @param obj + * @param name + * @param backing + * @return + */ b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing ); /** - * @brief Initialise a node as an array - * - * @param obj - * @param name - * @param backing - * @return - */ + * @brief Initialise a node as an array + * + * @param obj + * @param name + * @param backing + * @return + */ b8 adt_set_arr( ADT_Node* obj, char const* name, AllocatorInfo backing ); /** - * @brief Initialise a node as a string - * - * @param obj - * @param name - * @param value - * @return - */ + * @brief Initialise a node as a string + * + * @param obj + * @param name + * @param value + * @return + */ b8 adt_set_str( ADT_Node* obj, char const* name, char const* value ); /** - * @brief Initialise a node as a float - * - * @param obj - * @param name - * @param value - * @return - */ + * @brief Initialise a node as a float + * + * @param obj + * @param name + * @param value + * @return + */ b8 adt_set_flt( ADT_Node* obj, char const* name, f64 value ); /** - * @brief Initialise a node as a signed integer - * - * @param obj - * @param name - * @param value - * @return - */ + * @brief Initialise a node as a signed integer + * + * @param obj + * @param name + * @param value + * @return + */ b8 adt_set_int( ADT_Node* obj, char const* name, s64 value ); /** - * @brief Append a new node to a container as an object - * - * @param parent - * @param name - * @return* - */ + * @brief Append a new node to a container as an object + * + * @param parent + * @param name + * @return* + */ ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ); /** - * @brief Append a new node to a container as an array - * - * @param parent - * @param name - * @return* - */ + * @brief Append a new node to a container as an array + * + * @param parent + * @param name + * @return* + */ ADT_Node* adt_append_arr( ADT_Node* parent, char const* name ); /** - * @brief Append a new node to a container as a string - * - * @param parent - * @param name - * @param value - * @return* - */ + * @brief Append a new node to a container as a string + * + * @param parent + * @param name + * @param value + * @return* + */ ADT_Node* adt_append_str( ADT_Node* parent, char const* name, char const* value ); /** - * @brief Append a new node to a container as a float - * - * @param parent - * @param name - * @param value - * @return* - */ + * @brief Append a new node to a container as a float + * + * @param parent + * @param name + * @param value + * @return* + */ ADT_Node* adt_append_flt( ADT_Node* parent, char const* name, f64 value ); /** - * @brief Append a new node to a container as a signed integer - * - * @param parent - * @param name - * @param value - * @return* - */ + * @brief Append a new node to a container as a signed integer + * + * @param parent + * @param name + * @param value + * @return* + */ ADT_Node* adt_append_int( ADT_Node* parent, char const* name, s64 value ); /* parser helpers */ /** - * @brief Parses a text and stores the result into an unitialised node. - * - * @param node - * @param base - * @return* - */ + * @brief Parses a text and stores the result into an unitialised node. + * + * @param node + * @param base + * @return* + */ char* adt_parse_number( ADT_Node* node, char* base ); /** - * @brief Parses a text and stores the result into an unitialised node. - * This function expects the entire input to be a number. - * - * @param node - * @param base - * @return* - */ + * @brief Parses a text and stores the result into an unitialised node. + * This function expects the entire input to be a number. + * + * @param node + * @param base + * @return* + */ char* adt_parse_number_strict( ADT_Node* node, char* base_str ); /** - * @brief Parses and converts an existing string node into a number. - * - * @param node - * @return - */ -ADT_Error adt_str_to_number( ADT_Node* node ); + * @brief Parses and converts an existing string node into a number. + * + * @param node + * @return + */ +ADT_Error adt_c_str_to_number( ADT_Node* node ); /** - * @brief Parses and converts an existing string node into a number. - * This function expects the entire input to be a number. - * - * @param node - * @return - */ -ADT_Error adt_str_to_number_strict( ADT_Node* node ); + * @brief Parses and converts an existing string node into a number. + * This function expects the entire input to be a number. + * + * @param node + * @return + */ +ADT_Error adt_c_str_to_number_strict( ADT_Node* node ); /** - * @brief Prints a number into a file stream. - * - * The provided file handle can also be a memory mapped stream. - * - * @see zpl_file_stream_new - * @param file - * @param node - * @return - */ + * @brief Prints a number into a file stream. + * + * The provided file handle can also be a memory mapped stream. + * + * @see zpl_file_stream_new + * @param file + * @param node + * @return + */ ADT_Error adt_print_number( FileInfo* file, ADT_Node* node ); /** - * @brief Prints a string into a file stream. - * - * The provided file handle can also be a memory mapped stream. - * - * @see zpl_file_stream_new - * @param file - * @param node - * @param escaped_chars - * @param escape_symbol - * @return - */ + * @brief Prints a string into a file stream. + * + * The provided file handle can also be a memory mapped stream. + * + * @see zpl_file_stream_new + * @param file + * @param node + * @param escaped_chars + * @param escape_symbol + * @return + */ ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_chars, char const* escape_symbol ); #pragma endregion ADT @@ -3244,36 +4046,37 @@ enum CSV_Error : u32 typedef ADT_Node CSV_Object; -GEN_DEF_INLINE u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ); -u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim ); -void csv_free( CSV_Object* obj ); +u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ); +u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim ); +void csv_free( CSV_Object* obj ); -GEN_DEF_INLINE void csv_write( FileInfo* file, CSV_Object* obj ); -GEN_DEF_INLINE String csv_write_string( AllocatorInfo a, CSV_Object* obj ); -void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delim ); -String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delim ); +void csv_write( FileInfo* file, CSV_Object* obj ); +StrBuilder csv_write_string( AllocatorInfo a, CSV_Object* obj ); +void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delim ); +StrBuilder csv_write_strbuilder_delimiter( AllocatorInfo a, CSV_Object* obj, char delim ); /* inline */ -GEN_IMPL_INLINE u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ) +inline +u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ) { return csv_parse_delimiter( root, text, allocator, has_header, ',' ); } -GEN_IMPL_INLINE void csv_write( FileInfo* file, CSV_Object* obj ) +inline +void csv_write( FileInfo* file, CSV_Object* obj ) { csv_write_delimiter( file, obj, ',' ); } -GEN_IMPL_INLINE String csv_write_string( AllocatorInfo a, CSV_Object* obj ) +inline +StrBuilder csv_write_string( AllocatorInfo a, CSV_Object* obj ) { - return csv_write_string_delimiter( a, obj, ',' ); + return csv_write_strbuilder_delimiter( a, obj, ',' ); } #pragma endregion CSV -#pragma endregion Parsing - GEN_NS_END // GEN_ROLL_OWN_DEPENDENCIES @@ -3283,445 +4086,930 @@ GEN_NS_BEGIN #pragma region Types -using LogFailType = sw ( * )( char const*, ... ); +/* + ________ __ __ ________ +| \ | \ | \ | \ +| ▓▓▓▓▓▓▓▓_______ __ __ ______ ____ _______ | ▓▓\ | ▓▓ \▓▓▓▓▓▓▓▓__ __ ______ ______ _______ +| ▓▓__ | \| \ | \ \ \ / \ | ▓▓▓\| ▓▓ | ▓▓ | \ | \/ \ / \ / \ +| ▓▓ \ | ▓▓▓▓▓▓▓\ ▓▓ | ▓▓ ▓▓▓▓▓▓\▓▓▓▓\ ▓▓▓▓▓▓▓ | ▓▓▓▓\ ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ +| ▓▓▓▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ | ▓▓ | ▓▓\▓▓ \ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓\▓▓ \ +| ▓▓_____| ▓▓ | ▓▓ ▓▓__/ ▓▓ ▓▓ | ▓▓ | ▓▓_\▓▓▓▓▓▓\ | ▓▓ \▓▓▓▓ | ▓▓ | ▓▓__/ ▓▓ ▓▓__/ ▓▓ ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ +| ▓▓ \ ▓▓ | ▓▓\▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ \▓▓▓ | ▓▓ \▓▓ ▓▓ ▓▓ ▓▓\▓▓ \ ▓▓ + \▓▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓\▓▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓ _\▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓▓▓▓▓▓ + | \__| ▓▓ ▓▓ + \▓▓ ▓▓ ▓▓ + \▓▓▓▓▓▓ \▓▓ + +*/ + +using LogFailType = ssize(*)(char const*, ...); // By default this library will either crash or exit if an error is detected while generating codes. // Even if set to not use GEN_FATAL, GEN_FATAL will still be used for memory failures as the library is unusable when they occur. #ifdef GEN_DONT_USE_FATAL -#define log_failure log_fmt + #define log_failure log_fmt #else -#define log_failure GEN_FATAL + #define log_failure GEN_FATAL #endif -enum class AccessSpec : u32 +enum AccessSpec : u32 { - Default, - Public, - Protected, - Private, + 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 ) +inline +Str access_spec_to_str( AccessSpec type ) { - local_persist char const* lookup[ ( u32 )AccessSpec::Num_AccessSpec ] = { - "", - "public", - "protected", - "private", + local_persist + Str lookup[ (u32)AccessSpec_Num_AccessSpec ] = { + { "", sizeof( "" ) - 1 }, + { "private", sizeof("prviate") - 1 }, + { "private", sizeof("protected") - 1 }, + { "public", sizeof("public") - 1 }, }; - if ( type > AccessSpec::Public ) - return "Invalid"; + Str invalid = { "Invalid", sizeof("Invalid") - 1 }; + if ( type > AccessSpec_Public ) + return invalid; - return lookup[ ( u32 )type ]; + return lookup[ (u32)type ]; } enum CodeFlag : u32 { - 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 : 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 : 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, -StrC to_str( ModuleFlag flag ) + ModuleFlag_SizeDef = GEN_U32_MAX, +}; +static_assert( size_of(ModuleFlag) == size_of(u32), "ModuleFlag not u32 size" ); + +inline +Str module_flag_to_str( ModuleFlag flag ) { - local_persist StrC lookup[ ( u32 )ModuleFlag::Num_ModuleFlags ] = { - {sizeof( "__none__" ), "__none__"}, - { sizeof( "export" ), "export" }, - { sizeof( "import" ), "import" }, + local_persist + Str lookup[ (u32)Num_ModuleFlags ] = { + { "__none__", sizeof("__none__") - 1 }, + { "export", sizeof("export") - 1 }, + { "import", sizeof("import") - 1 }, }; - if ( flag > ModuleFlag::Import ) - return { sizeof( "invalid" ), "invalid" }; + local_persist + Str invalid_flag = { "invalid", sizeof("invalid") }; + if ( flag > ModuleFlag_Import ) + return invalid_flag; - return lookup[ ( u32 )flag ]; + return lookup[ (u32)flag ]; } -ModuleFlag operator|( ModuleFlag A, ModuleFlag B ) +enum EPreprocessCond : u32 { - return ( ModuleFlag )( ( u32 )A | ( u32 )B ); -} + PreprocessCond_If, + PreprocessCond_IfDef, + PreprocessCond_IfNotDef, + PreprocessCond_ElIf, -enum class EPreprocessCond : u32 + EPreprocessCond_SizeDef = GEN_U32_MAX, +}; +static_assert( size_of(EPreprocessCond) == size_of(u32), "EPreprocessCond not u32 size" ); + +enum ETypenameTag : u16 { - If, - IfDef, - IfNotDef, - ElIf + Tag_None, + Tag_Class, + Tag_Enum, + Tag_Struct, + Tag_Union, + + Tag_UnderlyingType = GEN_U16_MAX, +}; +static_assert( size_of(ETypenameTag) == size_of(u16), "ETypenameTag is not u16 size"); + +enum CodeType : u32 +{ + CT_Invalid, + CT_Untyped, + CT_NewLine, + CT_Comment, + CT_Access_Private, + CT_Access_Protected, + CT_Access_Public, + CT_PlatformAttributes, + CT_Class, + CT_Class_Fwd, + CT_Class_Body, + CT_Constructor, + CT_Constructor_Fwd, + CT_Destructor, + CT_Destructor_Fwd, + CT_Enum, + CT_Enum_Fwd, + CT_Enum_Body, + CT_Enum_Class, + CT_Enum_Class_Fwd, + CT_Execution, + CT_Export_Body, + CT_Extern_Linkage, + CT_Extern_Linkage_Body, + CT_Friend, + CT_Function, + CT_Function_Fwd, + CT_Function_Body, + CT_Global_Body, + CT_Module, + CT_Namespace, + CT_Namespace_Body, + CT_Operator, + CT_Operator_Fwd, + CT_Operator_Member, + CT_Operator_Member_Fwd, + CT_Operator_Cast, + CT_Operator_Cast_Fwd, + CT_Parameters, + CT_Preprocess_Define, + CT_Preprocess_Include, + CT_Preprocess_If, + CT_Preprocess_IfDef, + CT_Preprocess_IfNotDef, + CT_Preprocess_ElIf, + CT_Preprocess_Else, + CT_Preprocess_EndIf, + CT_Preprocess_Pragma, + CT_Specifiers, + CT_Struct, + CT_Struct_Fwd, + CT_Struct_Body, + CT_Template, + CT_Typedef, + CT_Typename, + CT_Union, + CT_Union_Fwd, + CT_Union_Body, + CT_Using, + CT_Using_Namespace, + CT_Variable, + CT_NumTypes, + CT_UnderlyingType = GEN_U32_MAX }; -constexpr EPreprocessCond PreprocessCond_If = EPreprocessCond::If; -constexpr EPreprocessCond PreprocessCond_IfDef = EPreprocessCond::IfDef; -constexpr EPreprocessCond PreprocessCond_IfNotDef = EPreprocessCond::IfNotDef; -constexpr EPreprocessCond PreprocessCond_ElIf = EPreprocessCond::ElIf; - -namespace ECode +inline Str codetype_to_str( CodeType type ) { - enum Type : u32 - { - Invalid, - Untyped, - NewLine, - Comment, - Access_Private, - Access_Protected, - Access_Public, - PlatformAttributes, - Class, - Class_Fwd, - Class_Body, - Constructor, - Constructor_Fwd, - Destructor, - Destructor_Fwd, - Enum, - Enum_Fwd, - Enum_Body, - Enum_Class, - Enum_Class_Fwd, - Execution, - Export_Body, - Extern_Linkage, - Extern_Linkage_Body, - Friend, - Function, - Function_Fwd, - Function_Body, - Global_Body, - Module, - Namespace, - Namespace_Body, - Operator, - Operator_Fwd, - Operator_Member, - Operator_Member_Fwd, - Operator_Cast, - Operator_Cast_Fwd, - Parameters, - Preprocess_Define, - Preprocess_Include, - Preprocess_If, - Preprocess_IfDef, - Preprocess_IfNotDef, - Preprocess_ElIf, - Preprocess_Else, - Preprocess_EndIf, - Preprocess_Pragma, - Specifiers, - Struct, - Struct_Fwd, - Struct_Body, - Template, - Typedef, - Typename, - Union, - Union_Body, - Using, - Using_Namespace, - Variable, - NumTypes + local_persist Str lookup[61] = { + { "Invalid", sizeof( "Invalid" ) - 1 }, + { "Untyped", sizeof( "Untyped" ) - 1 }, + { "NewLine", sizeof( "NewLine" ) - 1 }, + { "Comment", sizeof( "Comment" ) - 1 }, + { "Access_Private", sizeof( "Access_Private" ) - 1 }, + { "Access_Protected", sizeof( "Access_Protected" ) - 1 }, + { "Access_Public", sizeof( "Access_Public" ) - 1 }, + { "PlatformAttributes", sizeof( "PlatformAttributes" ) - 1 }, + { "Class", sizeof( "Class" ) - 1 }, + { "Class_Fwd", sizeof( "Class_Fwd" ) - 1 }, + { "Class_Body", sizeof( "Class_Body" ) - 1 }, + { "Constructor", sizeof( "Constructor" ) - 1 }, + { "Constructor_Fwd", sizeof( "Constructor_Fwd" ) - 1 }, + { "Destructor", sizeof( "Destructor" ) - 1 }, + { "Destructor_Fwd", sizeof( "Destructor_Fwd" ) - 1 }, + { "Enum", sizeof( "Enum" ) - 1 }, + { "Enum_Fwd", sizeof( "Enum_Fwd" ) - 1 }, + { "Enum_Body", sizeof( "Enum_Body" ) - 1 }, + { "Enum_Class", sizeof( "Enum_Class" ) - 1 }, + { "Enum_Class_Fwd", sizeof( "Enum_Class_Fwd" ) - 1 }, + { "Execution", sizeof( "Execution" ) - 1 }, + { "Export_Body", sizeof( "Export_Body" ) - 1 }, + { "Extern_Linkage", sizeof( "Extern_Linkage" ) - 1 }, + { "Extern_Linkage_Body", sizeof( "Extern_Linkage_Body" ) - 1 }, + { "Friend", sizeof( "Friend" ) - 1 }, + { "Function", sizeof( "Function" ) - 1 }, + { "Function_Fwd", sizeof( "Function_Fwd" ) - 1 }, + { "Function_Body", sizeof( "Function_Body" ) - 1 }, + { "Global_Body", sizeof( "Global_Body" ) - 1 }, + { "Module", sizeof( "Module" ) - 1 }, + { "Namespace", sizeof( "Namespace" ) - 1 }, + { "Namespace_Body", sizeof( "Namespace_Body" ) - 1 }, + { "Operator", sizeof( "Operator" ) - 1 }, + { "Operator_Fwd", sizeof( "Operator_Fwd" ) - 1 }, + { "Operator_Member", sizeof( "Operator_Member" ) - 1 }, + { "Operator_Member_Fwd", sizeof( "Operator_Member_Fwd" ) - 1 }, + { "Operator_Cast", sizeof( "Operator_Cast" ) - 1 }, + { "Operator_Cast_Fwd", sizeof( "Operator_Cast_Fwd" ) - 1 }, + { "Parameters", sizeof( "Parameters" ) - 1 }, + { "Preprocess_Define", sizeof( "Preprocess_Define" ) - 1 }, + { "Preprocess_Include", sizeof( "Preprocess_Include" ) - 1 }, + { "Preprocess_If", sizeof( "Preprocess_If" ) - 1 }, + { "Preprocess_IfDef", sizeof( "Preprocess_IfDef" ) - 1 }, + { "Preprocess_IfNotDef", sizeof( "Preprocess_IfNotDef" ) - 1 }, + { "Preprocess_ElIf", sizeof( "Preprocess_ElIf" ) - 1 }, + { "Preprocess_Else", sizeof( "Preprocess_Else" ) - 1 }, + { "Preprocess_EndIf", sizeof( "Preprocess_EndIf" ) - 1 }, + { "Preprocess_Pragma", sizeof( "Preprocess_Pragma" ) - 1 }, + { "Specifiers", sizeof( "Specifiers" ) - 1 }, + { "Struct", sizeof( "Struct" ) - 1 }, + { "Struct_Fwd", sizeof( "Struct_Fwd" ) - 1 }, + { "Struct_Body", sizeof( "Struct_Body" ) - 1 }, + { "Template", sizeof( "Template" ) - 1 }, + { "Typedef", sizeof( "Typedef" ) - 1 }, + { "Typename", sizeof( "Typename" ) - 1 }, + { "Union", sizeof( "Union" ) - 1 }, + { "Union_Fwd", sizeof( "Union_Fwd" ) - 1 }, + { "Union_Body", sizeof( "Union_Body" ) - 1 }, + { "Using", sizeof( "Using" ) - 1 }, + { "Using_Namespace", sizeof( "Using_Namespace" ) - 1 }, + { "Variable", sizeof( "Variable" ) - 1 }, }; + return lookup[type]; +} - StrC to_str( Type type ) - { - local_persist StrC lookup[] { - {sizeof( "Invalid" ), "Invalid" }, - { sizeof( "Untyped" ), "Untyped" }, - { sizeof( "NewLine" ), "NewLine" }, - { sizeof( "Comment" ), "Comment" }, - { sizeof( "Access_Private" ), "Access_Private" }, - { sizeof( "Access_Protected" ), "Access_Protected" }, - { sizeof( "Access_Public" ), "Access_Public" }, - { sizeof( "PlatformAttributes" ), "PlatformAttributes" }, - { sizeof( "Class" ), "Class" }, - { sizeof( "Class_Fwd" ), "Class_Fwd" }, - { sizeof( "Class_Body" ), "Class_Body" }, - { sizeof( "Constructor" ), "Constructor" }, - { sizeof( "Constructor_Fwd" ), "Constructor_Fwd" }, - { sizeof( "Destructor" ), "Destructor" }, - { sizeof( "Destructor_Fwd" ), "Destructor_Fwd" }, - { sizeof( "Enum" ), "Enum" }, - { sizeof( "Enum_Fwd" ), "Enum_Fwd" }, - { sizeof( "Enum_Body" ), "Enum_Body" }, - { sizeof( "Enum_Class" ), "Enum_Class" }, - { sizeof( "Enum_Class_Fwd" ), "Enum_Class_Fwd" }, - { sizeof( "Execution" ), "Execution" }, - { sizeof( "Export_Body" ), "Export_Body" }, - { sizeof( "Extern_Linkage" ), "Extern_Linkage" }, - { sizeof( "Extern_Linkage_Body" ), "Extern_Linkage_Body"}, - { sizeof( "Friend" ), "Friend" }, - { sizeof( "Function" ), "Function" }, - { sizeof( "Function_Fwd" ), "Function_Fwd" }, - { sizeof( "Function_Body" ), "Function_Body" }, - { sizeof( "Global_Body" ), "Global_Body" }, - { sizeof( "Module" ), "Module" }, - { sizeof( "Namespace" ), "Namespace" }, - { sizeof( "Namespace_Body" ), "Namespace_Body" }, - { sizeof( "Operator" ), "Operator" }, - { sizeof( "Operator_Fwd" ), "Operator_Fwd" }, - { sizeof( "Operator_Member" ), "Operator_Member" }, - { sizeof( "Operator_Member_Fwd" ), "Operator_Member_Fwd"}, - { sizeof( "Operator_Cast" ), "Operator_Cast" }, - { sizeof( "Operator_Cast_Fwd" ), "Operator_Cast_Fwd" }, - { sizeof( "Parameters" ), "Parameters" }, - { sizeof( "Preprocess_Define" ), "Preprocess_Define" }, - { sizeof( "Preprocess_Include" ), "Preprocess_Include" }, - { sizeof( "Preprocess_If" ), "Preprocess_If" }, - { sizeof( "Preprocess_IfDef" ), "Preprocess_IfDef" }, - { sizeof( "Preprocess_IfNotDef" ), "Preprocess_IfNotDef"}, - { sizeof( "Preprocess_ElIf" ), "Preprocess_ElIf" }, - { sizeof( "Preprocess_Else" ), "Preprocess_Else" }, - { sizeof( "Preprocess_EndIf" ), "Preprocess_EndIf" }, - { sizeof( "Preprocess_Pragma" ), "Preprocess_Pragma" }, - { sizeof( "Specifiers" ), "Specifiers" }, - { sizeof( "Struct" ), "Struct" }, - { sizeof( "Struct_Fwd" ), "Struct_Fwd" }, - { sizeof( "Struct_Body" ), "Struct_Body" }, - { sizeof( "Template" ), "Template" }, - { sizeof( "Typedef" ), "Typedef" }, - { sizeof( "Typename" ), "Typename" }, - { sizeof( "Union" ), "Union" }, - { sizeof( "Union_Body" ), "Union_Body" }, - { sizeof( "Using" ), "Using" }, - { sizeof( "Using_Namespace" ), "Using_Namespace" }, - { sizeof( "Variable" ), "Variable" }, - }; - return lookup[ type ]; - } - -} // namespace ECode - -using CodeT = ECode::Type; - -namespace EOperator +inline Str codetype_to_keyword_str( CodeType type ) { - enum Type : u32 - { - Invalid, - Assign, - Assign_Add, - Assign_Subtract, - Assign_Multiply, - Assign_Divide, - Assign_Modulo, - Assign_BAnd, - Assign_BOr, - Assign_BXOr, - Assign_LShift, - Assign_RShift, - Increment, - Decrement, - Unary_Plus, - Unary_Minus, - UnaryNot, - Add, - Subtract, - Multiply, - Divide, - Modulo, - BNot, - BAnd, - BOr, - BXOr, - LShift, - RShift, - LAnd, - LOr, - LEqual, - LNot, - Lesser, - Greater, - LesserEqual, - GreaterEqual, - Subscript, - Indirection, - AddressOf, - MemberOfPointer, - PtrToMemOfPtr, - FunctionCall, - Comma, - NumOps + local_persist Str lookup[61] = { + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "//", sizeof( "//" ) - 1 }, + { "private", sizeof( "private" ) - 1 }, + { "protected", sizeof( "protected" ) - 1 }, + { "public", sizeof( "public" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "class", sizeof( "class" ) - 1 }, + { "clsss", sizeof( "clsss" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "enum", sizeof( "enum" ) - 1 }, + { "enum", sizeof( "enum" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "enum class", sizeof( "enum class" ) - 1 }, + { "enum class", sizeof( "enum class" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "extern", sizeof( "extern" ) - 1 }, + { "extern", sizeof( "extern" ) - 1 }, + { "friend", sizeof( "friend" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "module", sizeof( "module" ) - 1 }, + { "namespace", sizeof( "namespace" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "operator", sizeof( "operator" ) - 1 }, + { "operator", sizeof( "operator" ) - 1 }, + { "operator", sizeof( "operator" ) - 1 }, + { "operator", sizeof( "operator" ) - 1 }, + { "operator", sizeof( "operator" ) - 1 }, + { "operator", sizeof( "operator" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "define", sizeof( "define" ) - 1 }, + { "include", sizeof( "include" ) - 1 }, + { "if", sizeof( "if" ) - 1 }, + { "ifdef", sizeof( "ifdef" ) - 1 }, + { "ifndef", sizeof( "ifndef" ) - 1 }, + { "elif", sizeof( "elif" ) - 1 }, + { "else", sizeof( "else" ) - 1 }, + { "endif", sizeof( "endif" ) - 1 }, + { "pragma", sizeof( "pragma" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "struct", sizeof( "struct" ) - 1 }, + { "struct", sizeof( "struct" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "template", sizeof( "template" ) - 1 }, + { "typedef", sizeof( "typedef" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "union", sizeof( "union" ) - 1 }, + { "union", sizeof( "union" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, + { "using", sizeof( "using" ) - 1 }, + { "using namespace", sizeof( "using namespace" ) - 1 }, + { "__NA__", sizeof( "__NA__" ) - 1 }, }; + return lookup[type]; +} - StrC to_str( Type op ) - { - local_persist StrC lookup[] { - {sizeof( "INVALID" ), "INVALID"}, - { sizeof( "=" ), "=" }, - { sizeof( "+=" ), "+=" }, - { sizeof( "-=" ), "-=" }, - { sizeof( "*=" ), "*=" }, - { sizeof( "/=" ), "/=" }, - { sizeof( "%=" ), "%=" }, - { sizeof( "&=" ), "&=" }, - { sizeof( "|=" ), "|=" }, - { sizeof( "^=" ), "^=" }, - { sizeof( "<<=" ), "<<=" }, - { sizeof( ">>=" ), ">>=" }, - { sizeof( "++" ), "++" }, - { sizeof( "--" ), "--" }, - { sizeof( "+" ), "+" }, - { sizeof( "-" ), "-" }, - { sizeof( "!" ), "!" }, - { sizeof( "+" ), "+" }, - { sizeof( "-" ), "-" }, - { sizeof( "*" ), "*" }, - { sizeof( "/" ), "/" }, - { sizeof( "%" ), "%" }, - { sizeof( "~" ), "~" }, - { sizeof( "&" ), "&" }, - { sizeof( "|" ), "|" }, - { sizeof( "^" ), "^" }, - { sizeof( "<<" ), "<<" }, - { sizeof( ">>" ), ">>" }, - { sizeof( "&&" ), "&&" }, - { sizeof( "||" ), "||" }, - { sizeof( "==" ), "==" }, - { sizeof( "!=" ), "!=" }, - { sizeof( "<" ), "<" }, - { sizeof( ">" ), ">" }, - { sizeof( "<=" ), "<=" }, - { sizeof( ">=" ), ">=" }, - { sizeof( "[]" ), "[]" }, - { sizeof( "*" ), "*" }, - { sizeof( "&" ), "&" }, - { sizeof( "->" ), "->" }, - { sizeof( "->*" ), "->*" }, - { sizeof( "()" ), "()" }, - { sizeof( "," ), "," }, - }; - return lookup[ op ]; - } - -} // namespace EOperator - -using OperatorT = EOperator::Type; - -namespace ESpecifier +forceinline Str to_str( CodeType type ) { - enum Type : u32 - { - Invalid, - Consteval, - Constexpr, - Constinit, - Explicit, - External_Linkage, - ForceInline, - Global, - Inline, - Internal_Linkage, - Local_Persist, - Mutable, - NeverInline, - Ptr, - Ref, - Register, - RValue, - Static, - Thread_Local, - Volatile, - Virtual, - Const, - Final, - NoExceptions, - Override, - Pure, - NumSpecifiers + return codetype_to_str( type ); +} + +forceinline Str to_keyword_str( CodeType type ) +{ + return codetype_to_keyword_str( type ); +} + +enum Operator : u32 +{ + Op_Invalid, + Op_Assign, + Op_Assign_Add, + Op_Assign_Subtract, + Op_Assign_Multiply, + Op_Assign_Divide, + Op_Assign_Modulo, + Op_Assign_BAnd, + Op_Assign_BOr, + Op_Assign_BXOr, + Op_Assign_LShift, + Op_Assign_RShift, + Op_Increment, + Op_Decrement, + Op_Unary_Plus, + Op_Unary_Minus, + Op_UnaryNot, + Op_Add, + Op_Subtract, + Op_Multiply, + Op_Divide, + Op_Modulo, + Op_BNot, + Op_BAnd, + Op_BOr, + Op_BXOr, + Op_LShift, + Op_RShift, + Op_LAnd, + Op_LOr, + Op_LEqual, + Op_LNot, + Op_Lesser, + Op_Greater, + Op_LesserEqual, + Op_GreaterEqual, + Op_Subscript, + Op_Indirection, + Op_AddressOf, + Op_MemberOfPointer, + Op_PtrToMemOfPtr, + Op_FunctionCall, + Op_Comma, + Op_New, + Op_NewArray, + Op_Delete, + Op_DeleteArray, + Op_NumOps, + Op_UnderlyingType = 0xffffffffu +}; + +inline Str operator_to_str( Operator op ) +{ + local_persist Str lookup[47] = { + { "INVALID", sizeof( "INVALID" ) - 1 }, + { "=", sizeof( "=" ) - 1 }, + { "+=", sizeof( "+=" ) - 1 }, + { "-=", sizeof( "-=" ) - 1 }, + { "*=", sizeof( "*=" ) - 1 }, + { "/=", sizeof( "/=" ) - 1 }, + { "%=", sizeof( "%=" ) - 1 }, + { "&=", sizeof( "&=" ) - 1 }, + { "|=", sizeof( "|=" ) - 1 }, + { "^=", sizeof( "^=" ) - 1 }, + { "<<=", sizeof( "<<=" ) - 1 }, + { ">>=", sizeof( ">>=" ) - 1 }, + { "++", sizeof( "++" ) - 1 }, + { "--", sizeof( "--" ) - 1 }, + { "+", sizeof( "+" ) - 1 }, + { "-", sizeof( "-" ) - 1 }, + { "!", sizeof( "!" ) - 1 }, + { "+", sizeof( "+" ) - 1 }, + { "-", sizeof( "-" ) - 1 }, + { "*", sizeof( "*" ) - 1 }, + { "/", sizeof( "/" ) - 1 }, + { "%", sizeof( "%" ) - 1 }, + { "~", sizeof( "~" ) - 1 }, + { "&", sizeof( "&" ) - 1 }, + { "|", sizeof( "|" ) - 1 }, + { "^", sizeof( "^" ) - 1 }, + { "<<", sizeof( "<<" ) - 1 }, + { ">>", sizeof( ">>" ) - 1 }, + { "&&", sizeof( "&&" ) - 1 }, + { "||", sizeof( "||" ) - 1 }, + { "==", sizeof( "==" ) - 1 }, + { "!=", sizeof( "!=" ) - 1 }, + { "<", sizeof( "<" ) - 1 }, + { ">", sizeof( ">" ) - 1 }, + { "<=", sizeof( "<=" ) - 1 }, + { ">=", sizeof( ">=" ) - 1 }, + { "[]", sizeof( "[]" ) - 1 }, + { "*", sizeof( "*" ) - 1 }, + { "&", sizeof( "&" ) - 1 }, + { "->", sizeof( "->" ) - 1 }, + { "->*", sizeof( "->*" ) - 1 }, + { "()", sizeof( "()" ) - 1 }, + { ",", sizeof( "," ) - 1 }, + { "new", sizeof( "new" ) - 1 }, + { "new[]", sizeof( "new[]" ) - 1 }, + { "delete", sizeof( "delete" ) - 1 }, + { "delete[]", sizeof( "delete[]" ) - 1 }, }; + return lookup[op]; +} - bool is_trailing( Type specifier ) +forceinline Str to_str( Operator op ) +{ + return operator_to_str( op ); +} + +enum Specifier : u32 +{ + Spec_Invalid, + Spec_Consteval, + Spec_Constexpr, + Spec_Constinit, + Spec_Explicit, + Spec_External_Linkage, + Spec_ForceInline, + Spec_Global, + Spec_Inline, + Spec_Internal_Linkage, + Spec_Local_Persist, + Spec_Mutable, + Spec_NeverInline, + Spec_Ptr, + Spec_Ref, + Spec_Register, + Spec_RValue, + Spec_Static, + Spec_Thread_Local, + Spec_Virtual, + Spec_Const, + Spec_Final, + Spec_NoExceptions, + Spec_Override, + Spec_Pure, + Spec_Volatile, + Spec_NumSpecifiers, + Spec_UnderlyingType = 0xffffffffu +}; + +inline Str spec_to_str( Specifier type ) +{ + local_persist Str lookup[26] = { + { "INVALID", sizeof( "INVALID" ) - 1 }, + { "consteval", sizeof( "consteval" ) - 1 }, + { "constexpr", sizeof( "constexpr" ) - 1 }, + { "constinit", sizeof( "constinit" ) - 1 }, + { "explicit", sizeof( "explicit" ) - 1 }, + { "extern", sizeof( "extern" ) - 1 }, + { "forceinline", sizeof( "forceinline" ) - 1 }, + { "global", sizeof( "global" ) - 1 }, + { "inline", sizeof( "inline" ) - 1 }, + { "internal", sizeof( "internal" ) - 1 }, + { "local_persist", sizeof( "local_persist" ) - 1 }, + { "mutable", sizeof( "mutable" ) - 1 }, + { "neverinline", sizeof( "neverinline" ) - 1 }, + { "*", sizeof( "*" ) - 1 }, + { "&", sizeof( "&" ) - 1 }, + { "register", sizeof( "register" ) - 1 }, + { "&&", sizeof( "&&" ) - 1 }, + { "static", sizeof( "static" ) - 1 }, + { "thread_local", sizeof( "thread_local" ) - 1 }, + { "virtual", sizeof( "virtual" ) - 1 }, + { "const", sizeof( "const" ) - 1 }, + { "final", sizeof( "final" ) - 1 }, + { "noexcept", sizeof( "noexcept" ) - 1 }, + { "override", sizeof( "override" ) - 1 }, + { "= 0", sizeof( "= 0" ) - 1 }, + { "volatile", sizeof( "volatile" ) - 1 }, + }; + return lookup[type]; +} + +inline bool spec_is_trailing( Specifier specifier ) +{ + return specifier > Spec_Virtual; +} + +inline Specifier str_to_specifier( Str str ) +{ + local_persist u32 keymap[Spec_NumSpecifiers]; + do_once_start for ( u32 index = 0; index < Spec_NumSpecifiers; index++ ) { - return specifier > Virtual; + Str enum_str = spec_to_str( (Specifier)index ); + keymap[index] = crc32( enum_str.Ptr, enum_str.Len ); } - - StrC to_str( Type type ) + do_once_end u32 hash = crc32( str.Ptr, str.Len ); + for ( u32 index = 0; index < Spec_NumSpecifiers; index++ ) { - local_persist StrC lookup[] { - {sizeof( "INVALID" ), "INVALID" }, - { sizeof( "consteval" ), "consteval" }, - { sizeof( "constexpr" ), "constexpr" }, - { sizeof( "constinit" ), "constinit" }, - { sizeof( "explicit" ), "explicit" }, - { sizeof( "extern" ), "extern" }, - { sizeof( "forceinline" ), "forceinline" }, - { sizeof( "global" ), "global" }, - { sizeof( "inline" ), "inline" }, - { sizeof( "internal" ), "internal" }, - { sizeof( "local_persist" ), "local_persist"}, - { sizeof( "mutable" ), "mutable" }, - { sizeof( "neverinline" ), "neverinline" }, - { sizeof( "*" ), "*" }, - { sizeof( "&" ), "&" }, - { sizeof( "register" ), "register" }, - { sizeof( "&&" ), "&&" }, - { sizeof( "static" ), "static" }, - { sizeof( "thread_local" ), "thread_local" }, - { sizeof( "volatile" ), "volatile" }, - { sizeof( "virtual" ), "virtual" }, - { sizeof( "const" ), "const" }, - { sizeof( "final" ), "final" }, - { sizeof( "noexcept" ), "noexcept" }, - { sizeof( "override" ), "override" }, - { sizeof( "= 0" ), "= 0" }, - }; - return lookup[ type ]; + if ( keymap[index] == hash ) + return (Specifier)index; } + return Spec_Invalid; +} - Type to_type( StrC str ) +forceinline Str to_str( Specifier spec ) +{ + return spec_to_str( spec ); +} + +forceinline Specifier to_type( Str str ) +{ + return str_to_specifier( str ); +} + +forceinline bool is_trailing( Specifier specifier ) +{ + return spec_is_trailing( specifier ); +} + +#define GEN_DEFINE_ATTRIBUTE_TOKENS Entry( Tok_Attribute_GEN_API, "GEN_API" ) + +enum TokType : u32 +{ + Tok_Invalid, + Tok_Access_Private, + Tok_Access_Protected, + Tok_Access_Public, + Tok_Access_MemberSymbol, + Tok_Access_StaticSymbol, + Tok_Ampersand, + Tok_Ampersand_DBL, + Tok_Assign_Classifer, + Tok_Attribute_Open, + Tok_Attribute_Close, + Tok_BraceCurly_Open, + Tok_BraceCurly_Close, + Tok_BraceSquare_Open, + Tok_BraceSquare_Close, + Tok_Capture_Start, + Tok_Capture_End, + Tok_Comment, + Tok_Comment_End, + Tok_Comment_Start, + Tok_Char, + Tok_Comma, + Tok_Decl_Class, + Tok_Decl_GNU_Attribute, + Tok_Decl_MSVC_Attribute, + Tok_Decl_Enum, + Tok_Decl_Extern_Linkage, + Tok_Decl_Friend, + Tok_Decl_Module, + Tok_Decl_Namespace, + Tok_Decl_Operator, + Tok_Decl_Struct, + Tok_Decl_Template, + Tok_Decl_Typedef, + Tok_Decl_Using, + Tok_Decl_Union, + Tok_Identifier, + Tok_Module_Import, + Tok_Module_Export, + Tok_NewLine, + Tok_Number, + Tok_Operator, + Tok_Preprocess_Hash, + Tok_Preprocess_Define, + Tok_Preprocess_If, + Tok_Preprocess_IfDef, + Tok_Preprocess_IfNotDef, + Tok_Preprocess_ElIf, + Tok_Preprocess_Else, + Tok_Preprocess_EndIf, + Tok_Preprocess_Include, + Tok_Preprocess_Pragma, + Tok_Preprocess_Content, + Tok_Preprocess_Macro, + Tok_Preprocess_Unsupported, + Tok_Spec_Alignas, + Tok_Spec_Const, + Tok_Spec_Consteval, + Tok_Spec_Constexpr, + Tok_Spec_Constinit, + Tok_Spec_Explicit, + Tok_Spec_Extern, + Tok_Spec_Final, + Tok_Spec_ForceInline, + Tok_Spec_Global, + Tok_Spec_Inline, + Tok_Spec_Internal_Linkage, + Tok_Spec_LocalPersist, + Tok_Spec_Mutable, + Tok_Spec_NeverInline, + Tok_Spec_Override, + Tok_Spec_Static, + Tok_Spec_ThreadLocal, + Tok_Spec_Volatile, + Tok_Spec_Virtual, + Tok_Star, + Tok_Statement_End, + Tok_StaticAssert, + Tok_String, + Tok_Type_Typename, + Tok_Type_Unsigned, + Tok_Type_Signed, + Tok_Type_Short, + Tok_Type_Long, + Tok_Type_bool, + Tok_Type_char, + Tok_Type_int, + Tok_Type_double, + Tok_Type_MS_int8, + Tok_Type_MS_int16, + Tok_Type_MS_int32, + Tok_Type_MS_int64, + Tok_Type_MS_W64, + Tok_Varadic_Argument, + Tok___Attributes_Start, + Tok_Attribute_GEN_API, + Tok_NumTokens +}; + +inline Str toktype_to_str( TokType type ) +{ + local_persist Str lookup[] = { + { "__invalid__", sizeof( "__invalid__" ) - 1 }, + { "private", sizeof( "private" ) - 1 }, + { "protected", sizeof( "protected" ) - 1 }, + { "public", sizeof( "public" ) - 1 }, + { ".", sizeof( "." ) - 1 }, + { "::", sizeof( "::" ) - 1 }, + { "&", sizeof( "&" ) - 1 }, + { "&&", sizeof( "&&" ) - 1 }, + { ":", sizeof( ":" ) - 1 }, + { "[[", sizeof( "[[" ) - 1 }, + { "]]", sizeof( "]]" ) - 1 }, + { "{", sizeof( "{" ) - 1 }, + { "}", sizeof( "}" ) - 1 }, + { "[", sizeof( "[" ) - 1 }, + { "]", sizeof( "]" ) - 1 }, + { "(", sizeof( "(" ) - 1 }, + { ")", sizeof( ")" ) - 1 }, + { "__comment__", sizeof( "__comment__" ) - 1 }, + { "__comment_end__", sizeof( "__comment_end__" ) - 1 }, + { "__comment_start__", sizeof( "__comment_start__" ) - 1 }, + { "__character__", sizeof( "__character__" ) - 1 }, + { ",", sizeof( "," ) - 1 }, + { "class", sizeof( "class" ) - 1 }, + { "__attribute__", sizeof( "__attribute__" ) - 1 }, + { "__declspec", sizeof( "__declspec" ) - 1 }, + { "enum", sizeof( "enum" ) - 1 }, + { "extern", sizeof( "extern" ) - 1 }, + { "friend", sizeof( "friend" ) - 1 }, + { "module", sizeof( "module" ) - 1 }, + { "namespace", sizeof( "namespace" ) - 1 }, + { "operator", sizeof( "operator" ) - 1 }, + { "struct", sizeof( "struct" ) - 1 }, + { "template", sizeof( "template" ) - 1 }, + { "typedef", sizeof( "typedef" ) - 1 }, + { "using", sizeof( "using" ) - 1 }, + { "union", sizeof( "union" ) - 1 }, + { "__identifier__", sizeof( "__identifier__" ) - 1 }, + { "import", sizeof( "import" ) - 1 }, + { "export", sizeof( "export" ) - 1 }, + { "__new_line__", sizeof( "__new_line__" ) - 1 }, + { "__number__", sizeof( "__number__" ) - 1 }, + { "__operator__", sizeof( "__operator__" ) - 1 }, + { "#", sizeof( "#" ) - 1 }, + { "define", sizeof( "define" ) - 1 }, + { "if", sizeof( "if" ) - 1 }, + { "ifdef", sizeof( "ifdef" ) - 1 }, + { "ifndef", sizeof( "ifndef" ) - 1 }, + { "elif", sizeof( "elif" ) - 1 }, + { "else", sizeof( "else" ) - 1 }, + { "endif", sizeof( "endif" ) - 1 }, + { "include", sizeof( "include" ) - 1 }, + { "pragma", sizeof( "pragma" ) - 1 }, + { "__macro_content__", sizeof( "__macro_content__" ) - 1 }, + { "__macro__", sizeof( "__macro__" ) - 1 }, + { "__unsupported__", sizeof( "__unsupported__" ) - 1 }, + { "alignas", sizeof( "alignas" ) - 1 }, + { "const", sizeof( "const" ) - 1 }, + { "consteval", sizeof( "consteval" ) - 1 }, + { "constexpr", sizeof( "constexpr" ) - 1 }, + { "constinit", sizeof( "constinit" ) - 1 }, + { "explicit", sizeof( "explicit" ) - 1 }, + { "extern", sizeof( "extern" ) - 1 }, + { "final", sizeof( "final" ) - 1 }, + { "forceinline", sizeof( "forceinline" ) - 1 }, + { "global", sizeof( "global" ) - 1 }, + { "inline", sizeof( "inline" ) - 1 }, + { "internal", sizeof( "internal" ) - 1 }, + { "local_persist", sizeof( "local_persist" ) - 1 }, + { "mutable", sizeof( "mutable" ) - 1 }, + { "neverinline", sizeof( "neverinline" ) - 1 }, + { "override", sizeof( "override" ) - 1 }, + { "static", sizeof( "static" ) - 1 }, + { "thread_local", sizeof( "thread_local" ) - 1 }, + { "volatile", sizeof( "volatile" ) - 1 }, + { "virtual", sizeof( "virtual" ) - 1 }, + { "*", sizeof( "*" ) - 1 }, + { ";", sizeof( ";" ) - 1 }, + { "static_assert", sizeof( "static_assert" ) - 1 }, + { "__string__", sizeof( "__string__" ) - 1 }, + { "typename", sizeof( "typename" ) - 1 }, + { "unsigned", sizeof( "unsigned" ) - 1 }, + { "signed", sizeof( "signed" ) - 1 }, + { "short", sizeof( "short" ) - 1 }, + { "long", sizeof( "long" ) - 1 }, + { "bool", sizeof( "bool" ) - 1 }, + { "char", sizeof( "char" ) - 1 }, + { "int", sizeof( "int" ) - 1 }, + { "double", sizeof( "double" ) - 1 }, + { "__int8", sizeof( "__int8" ) - 1 }, + { "__int16", sizeof( "__int16" ) - 1 }, + { "__int32", sizeof( "__int32" ) - 1 }, + { "__int64", sizeof( "__int64" ) - 1 }, + { "_W64", sizeof( "_W64" ) - 1 }, + { "...", sizeof( "..." ) - 1 }, + { "__attrib_start__", sizeof( "__attrib_start__" ) - 1 }, + { "GEN_API", sizeof( "GEN_API" ) - 1 }, + }; + return lookup[type]; +} + +inline TokType str_to_toktype( Str str ) +{ + local_persist u32 keymap[Tok_NumTokens]; + do_once_start for ( u32 index = 0; index < Tok_NumTokens; index++ ) { - local_persist u32 keymap[ NumSpecifiers ]; - do_once_start for ( u32 index = 0; index < NumSpecifiers; index++ ) - { - StrC enum_str = to_str( ( Type )index ); - keymap[ index ] = crc32( enum_str.Ptr, enum_str.Len - 1 ); - } - do_once_end u32 hash = crc32( str.Ptr, str.Len ); - for ( u32 index = 0; index < NumSpecifiers; index++ ) - { - if ( keymap[ index ] == hash ) - return ( Type )index; - } - return Invalid; + Str enum_str = toktype_to_str( (TokType)index ); + keymap[index] = crc32( enum_str.Ptr, enum_str.Len ); } + do_once_end u32 hash = crc32( str.Ptr, str.Len ); + for ( u32 index = 0; index < Tok_NumTokens; index++ ) + { + if ( keymap[index] == hash ) + return (TokType)index; + } + return Tok_Invalid; +} -} // namespace ESpecifier +enum TokFlags : u32 +{ + TF_Operator = bit(0), + TF_Assign = bit(1), + TF_Preprocess = bit(2), + TF_Preprocess_Cond = bit(3), + TF_Attribute = bit(6), + TF_AccessOperator = bit( 7 ), + TF_AccessSpecifier = bit( 8 ), + TF_Specifier = bit( 9 ), + TF_EndDefinition = bit( 10 ), // Either ; or } + TF_Formatting = bit( 11 ), + TF_Literal = bit( 12 ), -using SpecifierT = ESpecifier::Type; + TF_Null = 0, + TF_UnderlyingType = GEN_U32_MAX, +}; + +struct Token +{ + Str Text; + TokType Type; + s32 Line; + s32 Column; + u32 Flags; +}; + +constexpr Token NullToken { {}, Tok_Invalid, 0, 0, TF_Null }; + +forceinline +AccessSpec tok_to_access_specifier(Token tok) { + return scast(AccessSpec, tok.Type); +} + +forceinline +Str tok_to_str(Token tok) { + return tok.Text; +} + +forceinline +bool tok_is_valid( Token tok ) { + return tok.Text.Ptr && tok.Text.Len && tok.Type != Tok_Invalid; +} + +forceinline +bool tok_is_access_operator(Token tok) { + return bitfield_is_equal( u32, tok.Flags, TF_AccessOperator ); +} + +forceinline +bool tok_is_access_specifier(Token tok) { + return bitfield_is_equal( u32, tok.Flags, TF_AccessSpecifier ); +} + +forceinline +bool tok_is_attribute(Token tok) { + return bitfield_is_equal( u32, tok.Flags, TF_Attribute ); +} + +forceinline +bool tok_is_operator(Token tok) { + return bitfield_is_equal( u32, tok.Flags, TF_Operator ); +} + +forceinline +bool tok_is_preprocessor(Token tok) { + return bitfield_is_equal( u32, tok.Flags, TF_Preprocess ); +} + +forceinline +bool tok_is_preprocess_cond(Token tok) { + return bitfield_is_equal( u32, tok.Flags, TF_Preprocess_Cond ); +} + +forceinline +bool tok_is_specifier(Token tok) { + return bitfield_is_equal( u32, tok.Flags, TF_Specifier ); +} + +forceinline +bool tok_is_end_definition(Token tok) { + return bitfield_is_equal( u32, tok.Flags, TF_EndDefinition ); +} + +StrBuilder tok_to_strbuilder(Token tok); + +struct TokArray +{ + Array(Token) Arr; + s32 Idx; +}; + +struct LexContext +{ + Str content; + s32 left; + char const* scanner; + s32 line; + s32 column; + StringTable defines; + Token token; +}; + +struct StackNode +{ + StackNode* Prev; + + Token* Start; + Str Name; // The name of the AST node (if parsed) + Str ProcName; // The name of the procedure +}; + +struct ParseContext +{ + TokArray Tokens; + StackNode* Scope; +}; #pragma endregion Types #pragma region AST +/* + ______ ______ ________ __ __ ______ __ + / \ / \| \ | \ | \ / \ | \ +| ▓▓▓▓▓▓\ ▓▓▓▓▓▓\\▓▓▓▓▓▓▓▓ | ▓▓\ | ▓▓ | ▓▓▓▓▓▓\ ______ ____| ▓▓ ______ +| ▓▓__| ▓▓ ▓▓___\▓▓ | ▓▓ | ▓▓▓\| ▓▓ | ▓▓ \▓▓/ \ / ▓▓/ \ +| ▓▓ ▓▓\▓▓ \ | ▓▓ | ▓▓▓▓\ ▓▓ | ▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\ +| ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ | ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ __| ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓ +| ▓▓ | ▓▓ \__| ▓▓ | ▓▓ | ▓▓ \▓▓▓▓ | ▓▓__/ \ ▓▓__/ ▓▓ ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ +| ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ \▓▓▓ \▓▓ ▓▓\▓▓ ▓▓\▓▓ ▓▓\▓▓ \ + \▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ +*/ + struct AST; struct AST_Body; struct AST_Attributes; struct AST_Comment; struct AST_Constructor; +// struct AST_BaseClass; struct AST_Class; struct AST_Define; struct AST_Destructor; @@ -3735,21 +5023,84 @@ struct AST_Module; struct AST_NS; struct AST_Operator; struct AST_OpCast; -struct AST_Param; +struct AST_Params; struct AST_Pragma; struct AST_PreprocessCond; struct AST_Specifiers; + +#if GEN_EXECUTION_EXPRESSION_SUPPORT +struct AST_Expr; +struct AST_Expr_Assign; +struct AST_Expr_Alignof; +struct AST_Expr_Binary; +struct AST_Expr_CStyleCast; +struct AST_Expr_FunctionalCast; +struct AST_Expr_CppCast; +struct AST_Expr_ProcCall; +struct AST_Expr_Decltype; +struct AST_Expr_Comma; // TODO(Ed) : This is a binary op not sure if it needs its own AST... +struct AST_Expr_AMS; // Access Member Symbol +struct AST_Expr_Sizeof; +struct AST_Expr_Subscript; +struct AST_Expr_Ternary; +struct AST_Expr_UnaryPrefix; +struct AST_Expr_UnaryPostfix; +struct AST_Expr_Element; + +struct AST_Stmt; +struct AST_Stmt_Break; +struct AST_Stmt_Case; +struct AST_Stmt_Continue; +struct AST_Stmt_Decl; +struct AST_Stmt_Do; +struct AST_Stmt_Expr; // TODO(Ed) : Is this distinction needed? (Should it be a flag instead?) +struct AST_Stmt_Else; +struct AST_Stmt_If; +struct AST_Stmt_For; +struct AST_Stmt_Goto; +struct AST_Stmt_Label; +struct AST_Stmt_Switch; +struct AST_Stmt_While; +#endif + struct AST_Struct; struct AST_Template; -struct AST_Type; +struct AST_Typename; struct AST_Typedef; struct AST_Union; struct AST_Using; struct AST_Var; +#if GEN_COMPILER_C +typedef AST* Code; +#else struct Code; +#endif + +#if GEN_COMPILER_C +typedef AST_Body* CodeBody; +typedef AST_Attributes* CodeAttributes; +typedef AST_Comment* CodeComment; +typedef AST_Class* CodeClass; +typedef AST_Constructor* CodeConstructor; +typedef AST_Define* CodeDefine; +typedef AST_Destructor* CodeDestructor; +typedef AST_Enum* CodeEnum; +typedef AST_Exec* CodeExec; +typedef AST_Extern* CodeExtern; +typedef AST_Include* CodeInclude; +typedef AST_Friend* CodeFriend; +typedef AST_Fn* CodeFn; +typedef AST_Module* CodeModule; +typedef AST_NS* CodeNS; +typedef AST_Operator* CodeOperator; +typedef AST_OpCast* CodeOpCast; +typedef AST_Params* CodeParams; +typedef AST_PreprocessCond* CodePreprocessCond; +typedef AST_Pragma* CodePragma; +typedef AST_Specifiers* CodeSpecifiers; +#else struct CodeBody; -// These are to offer ease of use and optionally strong type safety for the AST. struct CodeAttributes; struct CodeComment; struct CodeClass; @@ -3766,82 +5117,181 @@ struct CodeModule; struct CodeNS; struct CodeOperator; struct CodeOpCast; -struct CodeParam; +struct CodeParams; struct CodePreprocessCond; struct CodePragma; struct CodeSpecifiers; +#endif + +#if GEN_EXECUTION_EXPRESSION_SUPPORT + +#if GEN_COMPILER_C +typedef AST_Expr* CodeExpr; +typedef AST_Expr_Assign* CodeExpr_Assign; +typedef AST_Expr_Alignof* CodeExpr_Alignof; +typedef AST_Expr_Binary* CodeExpr_Binary; +typedef AST_Expr_CStyleCast* CodeExpr_CStyleCast; +typedef AST_Expr_FunctionalCast* CodeExpr_FunctionalCast; +typedef AST_Expr_CppCast* CodeExpr_CppCast; +typedef AST_Expr_Element* CodeExpr_Element; +typedef AST_Expr_ProcCall* CodeExpr_ProcCall; +typedef AST_Expr_Decltype* CodeExpr_Decltype; +typedef AST_Expr_Comma* CodeExpr_Comma; +typedef AST_Expr_AMS* CodeExpr_AMS; // Access Member Symbol +typedef AST_Expr_Sizeof* CodeExpr_Sizeof; +typedef AST_Expr_Subscript* CodeExpr_Subscript; +typedef AST_Expr_Ternary* CodeExpr_Ternary; +typedef AST_Expr_UnaryPrefix* CodeExpr_UnaryPrefix; +typedef AST_Expr_UnaryPostfix* CodeExpr_UnaryPostfix; +#else +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; +#endif + +#if GEN_COMPILER_C +typedef AST_Stmt* CodeStmt; +typedef AST_Stmt_Break* CodeStmt_Break; +typedef AST_Stmt_Case* CodeStmt_Case; +typedef AST_Stmt_Continue* CodeStmt_Continue; +typedef AST_Stmt_Decl* CodeStmt_Decl; +typedef AST_Stmt_Do* CodeStmt_Do; +typedef AST_Stmt_Expr* CodeStmt_Expr; +typedef AST_Stmt_Else* CodeStmt_Else; +typedef AST_Stmt_If* CodeStmt_If; +typedef AST_Stmt_For* CodeStmt_For; +typedef AST_Stmt_Goto* CodeStmt_Goto; +typedef AST_Stmt_Label* CodeStmt_Label; +typedef AST_Stmt_Switch* CodeStmt_Switch; +typedef AST_Stmt_While* CodeStmt_While; +#else +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; +#endif + +// GEN_EXECUTION_EXPRESSION_SUPPORT +#endif + +#if GEN_COMPILER_C +typedef AST_Struct* CodeStruct; +typedef AST_Template* CodeTemplate; +typedef AST_Typename* CodeTypename; +typedef AST_Typedef* CodeTypedef; +typedef AST_Union* CodeUnion; +typedef AST_Using* CodeUsing; +typedef AST_Var* CodeVar; +#else struct CodeStruct; struct CodeTemplate; -struct CodeType; +struct CodeTypename; struct CodeTypedef; struct CodeUnion; struct CodeUsing; struct CodeVar; +#endif -namespace Parser -{ - struct Token; -} +#if GEN_COMPILER_CPP +template< class Type> forceinline Type tmpl_cast( Code self ) { return * rcast( Type*, & self ); } +#endif +#pragma region Code C-Interface + +GEN_API void code_append (Code code, Code other ); +GEN_API Str code_debug_str (Code code); +GEN_API Code code_duplicate (Code code); +GEN_API Code* code_entry (Code code, u32 idx ); +GEN_API bool code_has_entries (Code code); +GEN_API bool code_is_body (Code code); +GEN_API bool code_is_equal (Code code, Code other); +GEN_API bool code_is_valid (Code code); +GEN_API void code_set_global (Code code); +GEN_API StrBuilder code_to_strbuilder (Code self ); +GEN_API void code_to_strbuilder_ptr(Code self, StrBuilder* result ); +GEN_API Str code_type_str (Code self ); +GEN_API bool code_validate_body (Code self ); + +#pragma endregion Code C-Interface + +#if GEN_COMPILER_CPP /* - AST* wrapper - - Not constantly have to append the '*' as this is written often.. - - Allows for implicit conversion to any of the ASTs (raw or filtered). + AST* wrapper + - Not constantly have to append the '*' as this is written often.. + - Allows for implicit conversion to any of the ASTs (raw or filtered). */ struct Code { -#pragma region Statics - // Used to identify ASTs that should always be duplicated. (Global constant ASTs) - static Code Global; - - // Used to identify invalid generated code. - static Code Invalid; -#pragma endregion Statics - -#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 ); \ - operator bool(); - - Using_Code( Code ); - - template< class Type > - Type cast() - { - return *rcast( Type*, this ); - } - - AST* operator->() - { - return ast; - } - - Code& operator++(); - - auto& operator*() - { - return *this; - } - AST* ast; -#ifdef GEN_ENFORCE_STRONG_CODE_TYPES -#define operator explicit operator +# define Using_Code( Typename ) \ + forceinline Str debug_str() { return code_debug_str(* this); } \ + forceinline Code duplicate() { return code_duplicate(* this); } \ + forceinline bool is_equal( Code other ) { return code_is_equal(* this, other); } \ + forceinline bool is_body() { return code_is_body(* this); } \ + forceinline bool is_valid() { return code_is_valid(* this); } \ + forceinline void set_global() { return code_set_global(* this); } + +# define Using_CodeOps( Typename ) \ + forceinline Typename& operator = ( Code other ); \ + forceinline bool operator ==( Code other ) { return (AST*)ast == other.ast; } \ + forceinline bool operator !=( Code other ) { return (AST*)ast != other.ast; } \ + forceinline bool operator ==(std::nullptr_t) const { return ast == nullptr; } \ + forceinline bool operator !=(std::nullptr_t) const { return ast != nullptr; } \ + operator bool(); + +#if ! GEN_C_LIKE_CPP + Using_Code( Code ); + forceinline void append(Code other) { return code_append(* this, other); } + forceinline Code* entry(u32 idx) { return code_entry(* this, idx); } + forceinline bool has_entries() { return code_has_entries(* this); } + forceinline StrBuilder to_strbuilder() { return code_to_strbuilder(* this); } + forceinline void to_strbuilder(StrBuilder& result) { return code_to_strbuilder_ptr(* this, & result); } + forceinline Str type_str() { return code_type_str(* this); } + forceinline bool validate_body() { return code_validate_body(*this); } #endif + + Using_CodeOps( Code ); + forceinline Code operator *() { return * this; } // Required to support for-range iteration. + forceinline AST* operator ->() { return ast; } + + Code& operator ++(); + +#ifdef GEN_ENFORCE_STRONG_CODE_TYPES +# define operator explicit operator +#endif + operator CodeBody() const; operator CodeAttributes() const; + // operator CodeBaseClass() const; operator CodeComment() const; - operator CodeConstructor() const; - operator CodeDestructor() const; operator CodeClass() const; + operator CodeConstructor() const; operator CodeDefine() const; + operator CodeDestructor() const; operator CodeExec() const; operator CodeEnum() const; operator CodeExtern() const; @@ -3852,1547 +5302,3022 @@ struct Code operator CodeNS() const; operator CodeOperator() const; operator CodeOpCast() const; - operator CodeParam() const; + operator CodeParams() const; operator CodePragma() const; operator CodePreprocessCond() const; operator CodeSpecifiers() const; operator CodeStruct() const; operator CodeTemplate() const; - operator CodeType() const; + operator CodeTypename() const; operator CodeTypedef() const; operator CodeUnion() const; operator CodeUsing() const; operator CodeVar() const; - operator CodeBody() const; -#undef operator + #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 { AST* ast; }; - -static_assert( sizeof( Code ) == sizeof( Code_POD ), "ERROR: Code is not POD" ); +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; +constexpr static +int AST_ArrSpecs_Cap = +( + AST_POD_Size + - sizeof(Code) + - sizeof(StrCached) + - sizeof(Code) * 2 + - sizeof(Token*) + - sizeof(Code) + - sizeof(CodeType) + - sizeof(ModuleFlag) + - sizeof(u32) +) +/ sizeof(Specifier) - 1; + /* - Simple AST POD with functionality to seralize into C++ syntax. + Simple AST POD with functionality to seralize into C++ syntax. */ struct AST { -#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(); - - neverinline String to_string(); - - template< class Type > - Type cast() - { - return *this; - } - - operator Code(); - operator CodeBody(); - operator CodeAttributes(); - operator CodeComment(); - operator CodeConstructor(); - operator CodeDestructor(); - operator CodeClass(); - operator CodeDefine(); - operator CodeEnum(); - operator CodeExec(); - operator CodeExtern(); - operator CodeInclude(); - operator CodeFriend(); - operator CodeFn(); - operator CodeModule(); - operator CodeNS(); - operator CodeOperator(); - operator CodeOpCast(); - operator CodeParam(); - operator CodePragma(); - operator CodePreprocessCond(); - operator CodeSpecifiers(); - operator CodeStruct(); - operator CodeTemplate(); - operator CodeType(); - operator CodeTypedef(); - 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 - { + union { struct { - AST* InlineCmt; // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable - AST* Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable - AST* Specs; // Destructor, Function, Operator, Typename, Variable - - union - { - AST* InitializerList; // Constructor - AST* ParentType; // Class, Struct, ParentType->Next has a possible list of interfaces. - AST* ReturnType; // Function, Operator, Typename - AST* UnderlyingType; // Enum, Typedef - AST* ValueType; // Parameter, Variable + Code InlineCmt; // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable + Code Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable + Code Specs; // Destructor, Function, Operator, Typename, Variable + union { + Code InitializerList; // Constructor + Code ParentType; // Class, Struct, ParentType->Next has a possible list of interfaces. + Code ReturnType; // Function, Operator, Typename + Code UnderlyingType; // Enum, Typedef + Code ValueType; // Parameter, Variable }; - - union - { - AST* BitfieldSize; // Variable (Class/Struct Data Member) - AST* Params; // Constructor, Function, Operator, Template, Typename + union { + Code Macro; // Parameter + Code BitfieldSize; // Variable (Class/Struct Data Member) + Code Params; // Constructor, Function, Operator, Template, Typename + Code UnderlyingTypeMacro; // Enum }; - - union - { - AST* ArrExpr; // Typename - AST* Body; // Class, Constructr, Destructor, Enum, Function, Namespace, Struct, Union - AST* Declaration; // Friend, Template - AST* Value; // Parameter, Variable + union { + Code ArrExpr; // Typename + Code Body; // Class, Constructor, Destructor, Enum, Friend, Function, Namespace, Struct, Union + Code Declaration; // Friend, Template + Code Value; // Parameter, Variable }; - - union - { - AST* NextVar; // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = - // NextVar->Value ) - AST* SuffixSpecs; // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed ) + union { + Code NextVar; // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = NextVar->Value ) + Code SuffixSpecs; // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed ) + Code PostNameMacro; // Only used with parameters for specifically UE_REQUIRES (Thanks Unreal) }; }; - - StringCached Content; // Attributes, Comment, Execution, Include - - struct - { - SpecifierT ArrSpecs[ ArrSpecs_Cap ]; // Specifiers - AST* NextSpecs; // Specifiers; If ArrSpecs is full, then NextSpecs is used. + StrCached Content; // Attributes, Comment, Execution, Include + struct { + Specifier ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers + Code NextSpecs; // Specifiers; If ArrSpecs is full, then NextSpecs is used. }; }; - - union - { - AST* Prev; - AST* Front; - AST* Last; + StrCached Name; + union { + Code Prev; + Code Front; + Code Last; }; - - union - { - AST* Next; - AST* Back; + union { + Code Next; + Code Back; }; - - Parser::Token* Token; // Reference to starting token, only avaialble if it was derived from parsing. - AST* Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - - union - { - b32 IsFunction; // Used by typedef to not serialize the name field. - b32 IsParamPack; // Used by typename to know if type should be considered a parameter pack. - OperatorT Op; - AccessSpec ParentAccess; - s32 NumEntries; + Token* Token; // Reference to starting token, only avaialble if it was derived from parsing. + Code Parent; + CodeType Type; +// CodeFlag CodeFlags; + ModuleFlag ModuleFlags; + union { + b32 IsFunction; // Used by typedef to not serialize the name field. + struct { + b16 IsParamPack; // Used by typename to know if type should be considered a parameter pack. + ETypenameTag TypeTag; // Used by typename to keep track of explicitly declared tags for the identifier (enum, struct, union) + }; + Operator Op; + AccessSpec ParentAccess; + s32 NumEntries; + s32 VarParenthesizedInit; // Used by variables to know that initialization is using a constructor expression instead of an assignment expression. }; }; +static_assert( sizeof(AST) == AST_POD_Size, "ERROR: AST is not size of AST_POD_Size" ); -struct AST_POD -{ - union - { - struct - { - AST* InlineCmt; // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable - AST* Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable - AST* Specs; // Destructor, Function, Operator, Typename, Variable - - union - { - AST* InitializerList; // Constructor - AST* ParentType; // Class, Struct, ParentType->Next has a possible list of interfaces. - AST* ReturnType; // Function, Operator, Typename - AST* UnderlyingType; // Enum, Typedef - AST* ValueType; // Parameter, Variable - }; - - union - { - AST* BitfieldSize; // Variable (Class/Struct Data Member) - AST* Params; // Constructor, Function, Operator, Template, Typename - }; - - union - { - AST* ArrExpr; // Typename - AST* Body; // Class, Constructr, Destructor, Enum, Function, Namespace, Struct, Union - AST* Declaration; // Friend, Template - AST* Value; // Parameter, Variable - }; - - union - { - AST* NextVar; // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = - // NextVar->Value ) - AST* SuffixSpecs; // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed ) - }; - }; - - StringCached Content; // Attributes, Comment, Execution, Include - - struct - { - SpecifierT ArrSpecs[ AST::ArrSpecs_Cap ]; // Specifiers - AST* NextSpecs; // Specifiers; If ArrSpecs is full, then NextSpecs is used. - }; - }; - - union - { - AST* Prev; - AST* Front; - AST* Last; - }; - - union - { - AST* Next; - AST* Back; - }; - - Parser::Token* Token; // Reference to starting token, only avaialble if it was derived from parsing. - AST* Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - - union - { - b32 IsFunction; // Used by typedef to not serialize the name field. - b32 IsParamPack; // Used by typename to know if type should be considered a parameter pack. - OperatorT Op; - AccessSpec ParentAccess; - s32 NumEntries; - }; -}; - -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" ); -static_assert( sizeof( AST_POD ) == AST_POD_Size, "ERROR: AST POD is not size of AST_POD_Size" ); +#if GEN_COMPILER_CPP +// Uses an implicitly overloaded cast from the AST to the desired code type. +// Necessary if the user wants GEN_ENFORCE_STRONG_CODE_TYPES +struct InvalidCode_ImplictCaster; +#define InvalidCode (InvalidCode_ImplictCaster{}) +#else +#define InvalidCode (void*){ (void*)Code_Invalid } +#endif +#if GEN_COMPILER_CPP +struct NullCode_ImplicitCaster; // 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 NullCode (NullCode_ImplicitCaster{}) +#else +#define NullCode nullptr +#endif -#pragma region Code Types +/* + ______ __ ______ __ ______ + / \ | \ | \ | \ / \ +| ▓▓▓▓▓▓\ ______ ____| ▓▓ ______ \▓▓▓▓▓▓_______ _| ▓▓_ ______ ______ | ▓▓▓▓▓▓\ ______ _______ ______ +| ▓▓ \▓▓/ \ / ▓▓/ \ | ▓▓ | \| ▓▓ \ / \ / \| ▓▓_ \▓▓| \ / \/ \ +| ▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\ | ▓▓ | ▓▓▓▓▓▓▓\\▓▓▓▓▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓ \ \▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\ +| ▓▓ __| ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ __| ▓▓ ▓▓ ▓▓ \▓▓ ▓▓▓▓ / ▓▓ ▓▓ | ▓▓ ▓▓ +| ▓▓__/ \ ▓▓__/ ▓▓ ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ _| ▓▓_| ▓▓ | ▓▓ | ▓▓| \ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ | ▓▓▓▓▓▓▓ ▓▓_____| ▓▓▓▓▓▓▓▓ + \▓▓ ▓▓\▓▓ ▓▓\▓▓ ▓▓\▓▓ \ | ▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \\▓▓ \ + \▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ +*/ + +#pragma region Code Type C-Interface + +GEN_API void body_append ( CodeBody body, Code other ); +GEN_API void body_append_body ( CodeBody body, CodeBody other ); +GEN_API StrBuilder body_to_strbuilder ( CodeBody body ); +GEN_API void body_to_strbuilder_ref ( CodeBody body, StrBuilder* result ); +GEN_API void body_to_strbuilder_export( CodeBody body, StrBuilder* result ); + +GEN_API Code begin_CodeBody( CodeBody body); +GEN_API Code end_CodeBody ( CodeBody body ); +GEN_API Code next_CodeBody ( CodeBody body, Code entry_iter ); + +GEN_API void class_add_interface ( CodeClass self, CodeTypename interface ); +GEN_API StrBuilder class_to_strbuilder ( CodeClass self ); +GEN_API void class_to_strbuilder_def( CodeClass self, StrBuilder* result ); +GEN_API void class_to_strbuilder_fwd( CodeClass self, StrBuilder* result ); + +GEN_API void params_append (CodeParams params, CodeParams param ); +GEN_API CodeParams params_get (CodeParams params, s32 idx); +GEN_API bool params_has_entries (CodeParams params ); +GEN_API StrBuilder params_to_strbuilder (CodeParams params ); +GEN_API void params_to_strbuilder_ref(CodeParams params, StrBuilder* result ); + +GEN_API CodeParams begin_CodeParams(CodeParams params); +GEN_API CodeParams end_CodeParams (CodeParams params); +GEN_API CodeParams next_CodeParams (CodeParams params, CodeParams entry_iter); + +GEN_API bool specifiers_append (CodeSpecifiers specifiers, Specifier spec); +GEN_API s32 specifiers_has (CodeSpecifiers specifiers, Specifier spec); +GEN_API s32 specifiers_remove (CodeSpecifiers specifiers, Specifier to_remove ); +GEN_API StrBuilder specifiers_to_strbuilder (CodeSpecifiers specifiers); +GEN_API void specifiers_to_strbuilder_ref(CodeSpecifiers specifiers, StrBuilder* result); + +GEN_API Specifier* begin_CodeSpecifiers(CodeSpecifiers specifiers); +GEN_API Specifier* end_CodeSpecifiers (CodeSpecifiers specifiers); +GEN_API Specifier* next_CodeSpecifiers (CodeSpecifiers specifiers, Specifier* spec_iter); + +GEN_API void struct_add_interface (CodeStruct self, CodeTypename interface); +GEN_API StrBuilder struct_to_strbuilder (CodeStruct self); +GEN_API void struct_to_strbuilder_fwd(CodeStruct self, StrBuilder* result); +GEN_API void struct_to_strbuilder_def(CodeStruct self, StrBuilder* result); + +GEN_API StrBuilder attributes_to_strbuilder (CodeAttributes attributes); +GEN_API void attributes_to_strbuilder_ref(CodeAttributes attributes, StrBuilder* result); + +GEN_API StrBuilder comment_to_strbuilder (CodeComment comment ); +GEN_API void comment_to_strbuilder_ref(CodeComment comment, StrBuilder* result ); + +GEN_API StrBuilder constructor_to_strbuilder (CodeConstructor constructor); +GEN_API void constructor_to_strbuilder_def(CodeConstructor constructor, StrBuilder* result ); +GEN_API void constructor_to_strbuilder_fwd(CodeConstructor constructor, StrBuilder* result ); + +GEN_API StrBuilder define_to_strbuilder (CodeDefine self); +GEN_API void define_to_strbuilder_ref(CodeDefine self, StrBuilder* result); + +GEN_API StrBuilder destructor_to_strbuilder (CodeDestructor destructor); +GEN_API void destructor_to_strbuilder_fwd(CodeDestructor destructor, StrBuilder* result ); +GEN_API void destructor_to_strbuilder_def(CodeDestructor destructor, StrBuilder* result ); + +GEN_API StrBuilder enum_to_strbuilder (CodeEnum self); +GEN_API void enum_to_strbuilder_def (CodeEnum self, StrBuilder* result ); +GEN_API void enum_to_strbuilder_fwd (CodeEnum self, StrBuilder* result ); +GEN_API void enum_to_strbuilder_class_def(CodeEnum self, StrBuilder* result ); +GEN_API void enum_to_strbuilder_class_fwd(CodeEnum self, StrBuilder* result ); + +GEN_API StrBuilder exec_to_strbuilder (CodeExec exec); +GEN_API void exec_to_strbuilder_ref(CodeExec exec, StrBuilder* result); + +GEN_API void extern_to_strbuilder(CodeExtern self, StrBuilder* result); + +GEN_API StrBuilder include_to_strbuilder (CodeInclude self); +GEN_API void include_to_strbuilder_ref(CodeInclude self, StrBuilder* result); + +GEN_API StrBuilder friend_to_strbuilder (CodeFriend self); +GEN_API void friend_to_strbuilder_ref(CodeFriend self, StrBuilder* result); + +GEN_API StrBuilder fn_to_strbuilder (CodeFn self); +GEN_API void fn_to_strbuilder_def(CodeFn self, StrBuilder* result); +GEN_API void fn_to_strbuilder_fwd(CodeFn self, StrBuilder* result); + +GEN_API StrBuilder module_to_strbuilder (CodeModule self); +GEN_API void module_to_strbuilder_ref(CodeModule self, StrBuilder* result); + +GEN_API StrBuilder namespace_to_strbuilder (CodeNS self); +GEN_API void namespace_to_strbuilder_ref(CodeNS self, StrBuilder* result); + +GEN_API StrBuilder code_op_to_strbuilder (CodeOperator self); +GEN_API void code_op_to_strbuilder_fwd(CodeOperator self, StrBuilder* result ); +GEN_API void code_op_to_strbuilder_def(CodeOperator self, StrBuilder* result ); + +GEN_API StrBuilder opcast_to_strbuilder (CodeOpCast op_cast ); +GEN_API void opcast_to_strbuilder_def(CodeOpCast op_cast, StrBuilder* result ); +GEN_API void opcast_to_strbuilder_fwd(CodeOpCast op_cast, StrBuilder* result ); + +GEN_API StrBuilder pragma_to_strbuilder (CodePragma self); +GEN_API void pragma_to_strbuilder_ref(CodePragma self, StrBuilder* result); + +GEN_API StrBuilder preprocess_to_strbuilder (CodePreprocessCond cond); +GEN_API void preprocess_to_strbuilder_if (CodePreprocessCond cond, StrBuilder* result ); +GEN_API void preprocess_to_strbuilder_ifdef (CodePreprocessCond cond, StrBuilder* result ); +GEN_API void preprocess_to_strbuilder_ifndef(CodePreprocessCond cond, StrBuilder* result ); +GEN_API void preprocess_to_strbuilder_elif (CodePreprocessCond cond, StrBuilder* result ); +GEN_API void preprocess_to_strbuilder_else (CodePreprocessCond cond, StrBuilder* result ); +GEN_API void preprocess_to_strbuilder_endif (CodePreprocessCond cond, StrBuilder* result ); + +GEN_API StrBuilder template_to_strbuilder (CodeTemplate self); +GEN_API void template_to_strbuilder_ref(CodeTemplate self, StrBuilder* result); + +GEN_API StrBuilder typename_to_strbuilder (CodeTypename self); +GEN_API void typename_to_strbuilder_ref(CodeTypename self, StrBuilder* result); + +GEN_API StrBuilder typedef_to_strbuilder (CodeTypedef self); +GEN_API void typedef_to_strbuilder_ref(CodeTypedef self, StrBuilder* result ); + +GEN_API StrBuilder union_to_strbuilder (CodeUnion self); +GEN_API void union_to_strbuilder_def(CodeUnion self, StrBuilder* result); +GEN_API void union_to_strbuilder_fwd(CodeUnion self, StrBuilder* result); + +GEN_API StrBuilder using_to_strbuilder (CodeUsing op_cast ); +GEN_API void using_to_strbuilder_ref(CodeUsing op_cast, StrBuilder* result ); +GEN_API void using_to_strbuilder_ns (CodeUsing op_cast, StrBuilder* result ); + +GEN_API StrBuilder var_to_strbuilder (CodeVar self); +GEN_API void var_to_strbuilder_ref(CodeVar self, StrBuilder* result); + +#pragma endregion Code Type C-Interface + +#if GEN_COMPILER_CPP +#pragma region Code Types C++ + +// These structs are not used at all by the C vairant. +static_assert( GEN_COMPILER_CPP, "This should not be compiled with the C-library" ); + +#define Verify_POD(Type) static_assert(size_of(Code##Type) == size_of(AST_##Type), "ERROR: Code##Type is not a POD") struct CodeBody { +#if ! GEN_C_LIKE_CPP Using_Code( CodeBody ); + forceinline void append( Code other ) { return body_append( *this, other ); } + forceinline void append( CodeBody body ) { return body_append(*this, body); } + forceinline bool has_entries() { return code_has_entries(* this); } + forceinline StrBuilder to_strbuilder() { return body_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return body_to_strbuilder_ref(* this, & result ); } + forceinline void to_strbuilder_export( StrBuilder& result ) { return body_to_strbuilder_export(* this, & result); } - 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(); - } - - AST* raw() - { - return rcast( AST*, ast ); - } - - AST_Body* operator->() - { - return ast; - } - - operator Code() - { - return *rcast( Code*, this ); - } - -#pragma region Iterator - - Code begin() - { - if ( ast ) - return { rcast( AST*, ast )->Front }; - - return { nullptr }; - } - - Code end() - { - return { rcast( AST*, ast )->Back->Next }; - } - -#pragma endregion Iterator - +#endif + forceinline Code begin() { return begin_CodeBody(* this); } + forceinline Code end() { return end_CodeBody(* this); } + Using_CodeOps( CodeBody ); + forceinline operator Code() { return * rcast( Code*, this ); } + forceinline AST_Body* operator->() { return ast; } AST_Body* ast; }; struct CodeClass { +#if ! GEN_C_LIKE_CPP Using_Code( CodeClass ); - - void add_interface( CodeType interface ); - - AST* raw() - { - return rcast( AST*, ast ); - } - - operator Code() - { - return *rcast( Code*, this ); - } - - AST_Class* operator->() - { - if ( ast == nullptr ) - { - log_failure( "Attempt to dereference a nullptr" ); - return nullptr; - } + forceinline void add_interface( CodeType interface ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder_def( StrBuilder& result ); + forceinline void to_strbuilder_fwd( StrBuilder& result ); +#endif + Using_CodeOps( CodeClass ); + forceinline operator Code() { return * rcast( Code*, this ); } + forceinline AST_Class* operator->() { + GEN_ASSERT(ast); return ast; } - AST_Class* ast; }; -struct CodeParam +struct CodeParams { - Using_Code( CodeParam ); +#if ! GEN_C_LIKE_CPP + Using_Code( CodeParams ); + forceinline void append( CodeParams other ); + forceinline CodeParams get( s32 idx ); + forceinline bool has_entries(); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); - void append( CodeParam other ); - - CodeParam get( s32 idx ); - bool has_entries(); - - AST* raw() - { - return rcast( AST*, ast ); - } - - AST_Param* operator->() - { - if ( ast == nullptr ) - { - log_failure( "Attempt to dereference a nullptr!" ); - return nullptr; - } +#endif + Using_CodeOps( CodeParams ); + forceinline CodeParams begin() { return begin_CodeParams(* this); } + forceinline CodeParams end() { return end_CodeParams(* this); } + forceinline operator Code() { return { (AST*)ast }; } + forceinline CodeParams operator *() { return * this; } // Required to support for-range iteration. + forceinline AST_Params* operator->() { + GEN_ASSERT(ast); return ast; } - - operator Code() - { - return { ( AST* )ast }; - } - -#pragma region Iterator - - CodeParam begin() - { - if ( ast ) - return { ast }; - - return { nullptr }; - } - - CodeParam end() - { - return { ( AST_Param* )rcast( AST*, ast )->Last }; - } - - CodeParam& operator++(); - - CodeParam operator*() - { - return *this; - } - -#pragma endregion Iterator - - AST_Param* ast; + CodeParams& operator++(); + AST_Params* ast; }; struct CodeSpecifiers { +#if ! GEN_C_LIKE_CPP Using_Code( CodeSpecifiers ); - - bool append( SpecifierT spec ) - { - if ( ast == nullptr ) - { - log_failure( "CodeSpecifiers: Attempted to append to a null specifiers AST!" ); - return false; - } - - if ( raw()->NumEntries == AST::ArrSpecs_Cap ) - { - log_failure( "CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST::ArrSpecs_Cap ); - return false; - } - - raw()->ArrSpecs[ raw()->NumEntries ] = spec; - raw()->NumEntries++; - return true; - } - - s32 has( SpecifierT spec ) - { - for ( s32 idx = 0; idx < raw()->NumEntries; idx++ ) - { - if ( raw()->ArrSpecs[ raw()->NumEntries ] == spec ) - return idx; - } - - return -1; - } - - AST* raw() - { - return rcast( AST*, ast ); - } - - AST_Specifiers* operator->() - { - if ( ast == nullptr ) - { - log_failure( "Attempt to dereference a nullptr!" ); - return nullptr; - } + bool append( Specifier spec ) { return specifiers_append(* this, spec); } + s32 has( Specifier spec ) { return specifiers_has(* this, spec); } + s32 remove( Specifier to_remove ) { return specifiers_remove(* this, to_remove); } + StrBuilder to_strbuilder() { return specifiers_to_strbuilder(* this ); } + void to_strbuilder( StrBuilder& result ) { return specifiers_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeSpecifiers); + forceinline operator Code() { return { (AST*) ast }; } + forceinline Code operator *() { return * this; } // Required to support for-range iteration. + forceinline AST_Specifiers* operator->() { + GEN_ASSERT(ast); return ast; } - - operator Code() - { - return { ( AST* )ast }; - } - -#pragma region Iterator - - SpecifierT* begin() - { - if ( ast ) - return &raw()->ArrSpecs[ 0 ]; - - return nullptr; - } - - SpecifierT* end() - { - return raw()->ArrSpecs + raw()->NumEntries; - } - -#pragma endregion Iterator - AST_Specifiers* ast; }; +struct CodeAttributes +{ +#if ! GEN_C_LIKE_CPP + Using_Code(CodeAttributes); + forceinline StrBuilder to_strbuilder() { return attributes_to_strbuilder(* this); } + forceinline void to_strbuilder(StrBuilder& result) { return attributes_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeAttributes); + operator Code(); + AST_Attributes *operator->(); + AST_Attributes *ast; +}; + +// Define_CodeType( BaseClass ); + +struct CodeComment +{ +#if ! GEN_C_LIKE_CPP + Using_Code(CodeComment); + forceinline StrBuilder to_strbuilder() { return comment_to_strbuilder (* this); } + forceinline void to_strbuilder(StrBuilder& result) { return comment_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeComment); + operator Code(); + AST_Comment *operator->(); + AST_Comment *ast; +}; + +struct CodeConstructor +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeConstructor ); + forceinline StrBuilder to_strbuilder() { return constructor_to_strbuilder(* this); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return constructor_to_strbuilder_def(* this, & result); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return constructor_to_strbuilder_fwd(* this, & result); } +#endif + Using_CodeOps(CodeConstructor); + operator Code(); + AST_Constructor* operator->(); + AST_Constructor* ast; +}; + +struct CodeDefine +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeDefine ); + forceinline StrBuilder to_strbuilder() { return define_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return define_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeDefine); + operator Code(); + AST_Define* operator->(); + AST_Define* ast; +}; + +struct CodeDestructor +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeDestructor ); + forceinline StrBuilder to_strbuilder() { return destructor_to_strbuilder(* this); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return destructor_to_strbuilder_def(* this, & result); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return destructor_to_strbuilder_fwd(* this, & result); } +#endif + Using_CodeOps(CodeDestructor); + operator Code(); + AST_Destructor* operator->(); + AST_Destructor* ast; +}; + +struct CodeEnum +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeEnum ); + forceinline StrBuilder to_strbuilder() { return enum_to_strbuilder(* this); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return enum_to_strbuilder_def(* this, & result); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return enum_to_strbuilder_fwd(* this, & result); } + forceinline void to_strbuilder_class_def( StrBuilder& result ) { return enum_to_strbuilder_class_def(* this, & result); } + forceinline void to_strbuilder_class_fwd( StrBuilder& result ) { return enum_to_strbuilder_class_fwd(* this, & result); } +#endif + Using_CodeOps(CodeEnum); + operator Code(); + AST_Enum* operator->(); + AST_Enum* ast; +}; + +struct CodeExec +{ +#if ! GEN_C_LIKE_CPP + Using_Code(CodeExec); + forceinline StrBuilder to_strbuilder() { return exec_to_strbuilder(* this); } + forceinline void to_strbuilder(StrBuilder& result) { return exec_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeExec); + operator Code(); + AST_Exec *operator->(); + AST_Exec *ast; +}; + +#if GEN_EXECUTION_EXPRESSION_SUPPORT +struct CodeExpr +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr* operator->(); + AST_Expr* ast; +}; + +struct CodeExpr_Assign +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Assign ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Assign* operator->(); + AST_Expr_Assign* ast; +}; + +struct CodeExpr_Alignof +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Alignof ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Alignof* operator->(); + AST_Expr_Alignof* ast; +}; + +struct CodeExpr_Binary +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Binary ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Binary* operator->(); + AST_Expr_Binary* ast; +}; + +struct CodeExpr_CStyleCast +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_CStyleCast ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_CStyleCast* operator->(); + AST_Expr_CStyleCast* ast; +}; + +struct CodeExpr_FunctionalCast +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_FunctionalCast ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_FunctionalCast* operator->(); + AST_Expr_FunctionalCast* ast; +}; + +struct CodeExpr_CppCast +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_CppCast ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_CppCast* operator->(); + AST_Expr_CppCast* ast; +}; + +struct CodeExpr_Element +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Element ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Element* operator->(); + AST_Expr_Element* ast; +}; + +struct CodeExpr_ProcCall +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_ProcCall ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_ProcCall* operator->(); + AST_Expr_ProcCall* ast; +}; + +struct CodeExpr_Decltype +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Decltype ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Decltype* operator->(); + AST_Expr_Decltype* ast; +}; + +struct CodeExpr_Comma +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Comma ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Comma* operator->(); + AST_Expr_Comma* ast; +}; + +struct CodeExpr_AMS +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_AMS ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_AMS* operator->(); + AST_Expr_AMS* ast; +}; + +struct CodeExpr_Sizeof +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Sizeof ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Sizeof* operator->(); + AST_Expr_Sizeof* ast; +}; + +struct CodeExpr_Subscript +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Subscript ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Subscript* operator->(); + AST_Expr_Subscript* ast; +}; + +struct CodeExpr_Ternary +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Ternary ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_Ternary* operator->(); + AST_Expr_Ternary* ast; +}; + +struct CodeExpr_UnaryPrefix +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_UnaryPrefix ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Expr_UnaryPrefix* operator->(); + AST_Expr_UnaryPrefix* ast; +}; + +struct CodeExpr_UnaryPostfix +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_UnaryPostfix ); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + AST* raw(); + operator Code(); + AST_Expr_UnaryPostfix* operator->(); + AST_Expr_UnaryPostfix* ast; +}; +#endif + +struct CodeExtern +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExtern ); + forceinline void to_strbuilder( StrBuilder& result ) { return extern_to_strbuilder(* this, & result); } +#endif + Using_CodeOps(CodeExtern); + operator Code(); + AST_Extern* operator->(); + AST_Extern* ast; +}; + +struct CodeInclude +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeInclude ); + forceinline StrBuilder to_strbuilder() { return include_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return include_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeInclude); + operator Code(); + AST_Include* operator->(); + AST_Include* ast; +}; + +struct CodeFriend +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeFriend ); + forceinline StrBuilder to_strbuilder() { return friend_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return friend_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeFriend); + operator Code(); + AST_Friend* operator->(); + AST_Friend* ast; +}; + +struct CodeFn +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeFn ); + forceinline StrBuilder to_strbuilder() { return fn_to_strbuilder(* this); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return fn_to_strbuilder_def(* this, & result); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return fn_to_strbuilder_fwd(* this, & result); } +#endif + Using_CodeOps(CodeFn); + operator Code(); + AST_Fn* operator->(); + AST_Fn* ast; +}; + +struct CodeModule +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeModule ); + forceinline StrBuilder to_strbuilder() { return module_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return module_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeModule); + operator Code(); + AST_Module* operator->(); + AST_Module* ast; +}; + +struct CodeNS +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeNS ); + forceinline StrBuilder to_strbuilder() { return namespace_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return namespace_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeNS); + operator Code(); + AST_NS* operator->(); + AST_NS* ast; +}; + +struct CodeOperator +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeOperator ); + forceinline StrBuilder to_strbuilder() { return code_op_to_strbuilder(* this); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return code_op_to_strbuilder_def(* this, & result); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return code_op_to_strbuilder_fwd(* this, & result); } +#endif + Using_CodeOps(CodeOperator); + operator Code(); + AST_Operator* operator->(); + AST_Operator* ast; +}; + +struct CodeOpCast +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeOpCast ); + forceinline StrBuilder to_strbuilder() { return opcast_to_strbuilder(* this); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return opcast_to_strbuilder_def(* this, & result); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return opcast_to_strbuilder_fwd(* this, & result); } +#endif + Using_CodeOps(CodeOpCast); + operator Code(); + AST_OpCast* operator->(); + AST_OpCast* ast; +}; + +struct CodePragma +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodePragma ); + forceinline StrBuilder to_strbuilder() { return pragma_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return pragma_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps( CodePragma ); + operator Code(); + AST_Pragma* operator->(); + AST_Pragma* ast; +}; + +struct CodePreprocessCond +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodePreprocessCond ); + forceinline StrBuilder to_strbuilder() { return preprocess_to_strbuilder(* this); } + forceinline void to_strbuilder_if( StrBuilder& result ) { return preprocess_to_strbuilder_if(* this, & result); } + forceinline void to_strbuilder_ifdef( StrBuilder& result ) { return preprocess_to_strbuilder_ifdef(* this, & result); } + forceinline void to_strbuilder_ifndef( StrBuilder& result ) { return preprocess_to_strbuilder_ifndef(* this, & result); } + forceinline void to_strbuilder_elif( StrBuilder& result ) { return preprocess_to_strbuilder_elif(* this, & result); } + forceinline void to_strbuilder_else( StrBuilder& result ) { return preprocess_to_strbuilder_else(* this, & result); } + forceinline void to_strbuilder_endif( StrBuilder& result ) { return preprocess_to_strbuilder_endif(* this, & result); } +#endif + Using_CodeOps( CodePreprocessCond ); + operator Code(); + AST_PreprocessCond* operator->(); + AST_PreprocessCond* ast; +}; + +#if GEN_EXECUTION_EXPRESSION_SUPPORT +struct CodeStmt +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt* operator->(); + AST_Stmt* ast; +}; + +struct CodeStmt_Break +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Break ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Break* operator->(); + AST_Stmt_Break* ast; +}; + +struct CodeStmt_Case +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Case ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Case* operator->(); + AST_Stmt_Case* ast; +}; + +struct CodeStmt_Continue +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Continue ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Continue* operator->(); + AST_Stmt_Continue* ast; +}; + +struct CodeStmt_Decl +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Decl ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Decl* operator->(); + AST_Stmt_Decl* ast; +}; + +struct CodeStmt_Do +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Do ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Do* operator->(); + AST_Stmt_Do* ast; +}; + +struct CodeStmt_Expr +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Expr ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Expr* operator->(); + AST_Stmt_Expr* ast; +}; + +struct CodeStmt_Else +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Else ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Else* operator->(); + AST_Stmt_Else* ast; +}; + +struct CodeStmt_If +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_If ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_If* operator->(); + AST_Stmt_If* ast; +}; + +struct CodeStmt_For +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_For ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_For* operator->(); + AST_Stmt_For* ast; +}; + +struct CodeStmt_Goto +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Goto ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Goto* operator->(); + AST_Stmt_Goto* ast; +}; + +struct CodeStmt_Label +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Label ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Label* operator->(); + AST_Stmt_Label* ast; +}; + +struct CodeStmt_Switch +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Switch ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_Switch* operator->(); + AST_Stmt_Switch* ast; +}; + +struct CodeStmt_While +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_While ); + forceinline StrBuilder to_strbuilder(); + forceinline void to_strbuilder( StrBuilder& result ); +#endif + operator Code(); + AST_Stmt_While* operator->(); + AST_Stmt_While* ast; +}; +#endif + +struct CodeTemplate +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeTemplate ); + forceinline StrBuilder to_strbuilder() { return template_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return template_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps( CodeTemplate ); + operator Code(); + AST_Template* operator->(); + AST_Template* ast; +}; + +struct CodeTypename +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeTypename ); + forceinline StrBuilder to_strbuilder() { return typename_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return typename_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps( CodeTypename ); + operator Code(); + AST_Typename* operator->(); + AST_Typename* ast; +}; + +struct CodeTypedef +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeTypedef ); + forceinline StrBuilder to_strbuilder() { return typedef_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return typedef_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps( CodeTypedef ); + operator Code(); + AST_Typedef* operator->(); + AST_Typedef* ast; +}; + +struct CodeUnion +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeUnion ); + forceinline StrBuilder to_strbuilder() { return union_to_strbuilder(* this); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return union_to_strbuilder_def(* this, & result); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return union_to_strbuilder_fwd(* this, & result); } +#endif + Using_CodeOps(CodeUnion); + operator Code(); + AST_Union* operator->(); + AST_Union* ast; +}; + +struct CodeUsing +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeUsing ); + forceinline StrBuilder to_strbuilder() { return using_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return using_to_strbuilder_ref(* this, & result); } + forceinline void to_strbuilder_ns( StrBuilder& result ) { return using_to_strbuilder_ns(* this, & result); } +#endif + Using_CodeOps(CodeUsing); + operator Code(); + AST_Using* operator->(); + AST_Using* ast; +}; + +struct CodeVar +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeVar ); + forceinline StrBuilder to_strbuilder() { return var_to_strbuilder(* this); } + forceinline void to_strbuilder( StrBuilder& result ) { return var_to_strbuilder_ref(* this, & result); } +#endif + Using_CodeOps(CodeVar); + operator Code(); + AST_Var* operator->(); + AST_Var* ast; +}; + struct CodeStruct { +#if ! GEN_C_LIKE_CPP Using_Code( CodeStruct ); - - void add_interface( CodeType interface ); - - AST* raw() - { - return rcast( AST*, ast ); - } - - operator Code() - { - return *rcast( Code*, this ); - } - - AST_Struct* operator->() - { - if ( ast == nullptr ) - { - log_failure( "Attempt to dereference a nullptr" ); - return nullptr; - } + forceinline void add_interface( CodeTypename interface ) { return struct_add_interface(* this, interface); } + forceinline StrBuilder to_strbuilder() { return struct_to_strbuilder(* this); } + forceinline void to_strbuilder_fwd( StrBuilder& result ) { return struct_to_strbuilder_fwd(* this, & result); } + forceinline void to_strbuilder_def( StrBuilder& result ) { return struct_to_strbuilder_def(* this, & result); } +#endif + Using_CodeOps( CodeStruct ); + forceinline operator Code() { return * rcast( Code*, this ); } + forceinline AST_Struct* operator->() { + GEN_ASSERT(ast); return ast; } - AST_Struct* ast; }; -#define Define_CodeType( Typename ) \ - struct Code##Typename \ - { \ - Using_Code( Code##Typename ); \ - AST* raw(); \ - operator Code(); \ - AST_##Typename* operator->(); \ - AST_##Typename* ast; \ - } - -Define_CodeType( Attributes ); -Define_CodeType( Comment ); -Define_CodeType( Constructor ); -Define_CodeType( Define ); -Define_CodeType( Destructor ); -Define_CodeType( Enum ); -Define_CodeType( Exec ); -Define_CodeType( Extern ); -Define_CodeType( Include ); -Define_CodeType( Friend ); -Define_CodeType( Fn ); -Define_CodeType( Module ); -Define_CodeType( NS ); -Define_CodeType( Operator ); -Define_CodeType( OpCast ); -Define_CodeType( Pragma ); -Define_CodeType( PreprocessCond ); -Define_CodeType( Template ); -Define_CodeType( Type ); -Define_CodeType( Typedef ); -Define_CodeType( Union ); -Define_CodeType( Using ); -Define_CodeType( Var ); - #undef Define_CodeType #undef Using_Code +#undef Using_CodeOps -#pragma endregion Code Types +#undef Verify_POD + +struct InvalidCode_ImplictCaster +{ + // operator CodeBaseClass() const; + operator Code () const { return Code_Invalid; } + operator CodeBody () const { return cast(CodeBody, Code_Invalid); } + operator CodeAttributes () const { return cast(CodeAttributes, Code_Invalid); } + operator CodeComment () const { return cast(CodeComment, Code_Invalid); } + operator CodeClass () const { return cast(CodeClass, Code_Invalid); } + operator CodeConstructor () const { return cast(CodeConstructor, Code_Invalid); } + operator CodeDefine () const { return cast(CodeDefine, Code_Invalid); } + operator CodeDestructor () const { return cast(CodeDestructor, Code_Invalid); } + operator CodeExec () const { return cast(CodeExec, Code_Invalid); } + operator CodeEnum () const { return cast(CodeEnum, Code_Invalid); } + operator CodeExtern () const { return cast(CodeExtern, Code_Invalid); } + operator CodeInclude () const { return cast(CodeInclude, Code_Invalid); } + operator CodeFriend () const { return cast(CodeFriend, Code_Invalid); } + operator CodeFn () const { return cast(CodeFn, Code_Invalid); } + operator CodeModule () const { return cast(CodeModule, Code_Invalid); } + operator CodeNS () const { return cast(CodeNS, Code_Invalid); } + operator CodeOperator () const { return cast(CodeOperator, Code_Invalid); } + operator CodeOpCast () const { return cast(CodeOpCast, Code_Invalid); } + operator CodeParams () const { return cast(CodeParams, Code_Invalid); } + operator CodePragma () const { return cast(CodePragma, Code_Invalid); } + operator CodePreprocessCond() const { return cast(CodePreprocessCond, Code_Invalid); } + operator CodeSpecifiers () const { return cast(CodeSpecifiers, Code_Invalid); } + operator CodeStruct () const { return cast(CodeStruct, Code_Invalid); } + operator CodeTemplate () const { return cast(CodeTemplate, Code_Invalid); } + operator CodeTypename () const { return cast(CodeTypename, Code_Invalid); } + operator CodeTypedef () const { return cast(CodeTypedef, Code_Invalid); } + operator CodeUnion () const { return cast(CodeUnion, Code_Invalid); } + operator CodeUsing () const { return cast(CodeUsing, Code_Invalid); } + operator CodeVar () const { return cast(CodeVar, Code_Invalid); } +}; + +struct NullCode_ImplicitCaster +{ + operator Code () const { return {nullptr}; } + operator CodeBody () const { return {(AST_Body*) nullptr}; } + operator CodeAttributes () const { return {(AST_Attributes*)nullptr}; } + operator CodeComment () const { return {nullptr}; } + operator CodeClass () const { return {nullptr}; } + operator CodeConstructor () const { return {nullptr}; } + operator CodeDefine () const { return {nullptr}; } + operator CodeDestructor () const { return {nullptr}; } + operator CodeExec () const { return {nullptr}; } + operator CodeEnum () const { return {nullptr}; } + operator CodeExtern () const { return {nullptr}; } + operator CodeInclude () const { return {nullptr}; } + operator CodeFriend () const { return {nullptr}; } + operator CodeFn () const { return {nullptr}; } + operator CodeModule () const { return {nullptr}; } + operator CodeNS () const { return {nullptr}; } + operator CodeOperator () const { return {nullptr}; } + operator CodeOpCast () const { return {nullptr}; } + operator CodeParams () const { return {nullptr}; } + operator CodePragma () const { return {nullptr}; } + operator CodePreprocessCond() const { return {nullptr}; } + operator CodeSpecifiers () const { return {nullptr}; } + operator CodeStruct () const { return {nullptr}; } + operator CodeTemplate () const { return {nullptr}; } + operator CodeTypename () const { return CodeTypename{(AST_Typename*)nullptr}; } + operator CodeTypedef () const { return {nullptr}; } + operator CodeUnion () const { return {nullptr}; } + operator CodeUsing () const { return {nullptr}; } + operator CodeVar () const { return {nullptr}; } +}; + +forceinline Code begin( CodeBody body) { return begin_CodeBody(body); } +forceinline Code end ( CodeBody body ) { return end_CodeBody(body); } +forceinline Code next ( CodeBody body, Code entry_iter ) { return next_CodeBody(body, entry_iter); } + +forceinline CodeParams begin(CodeParams params) { return begin_CodeParams(params); } +forceinline CodeParams end (CodeParams params) { return end_CodeParams(params); } +forceinline CodeParams next (CodeParams params, CodeParams entry_iter) { return next_CodeParams(params, entry_iter); } + +forceinline Specifier* begin(CodeSpecifiers specifiers) { return begin_CodeSpecifiers(specifiers); } +forceinline Specifier* end (CodeSpecifiers specifiers) { return end_CodeSpecifiers(specifiers); } +forceinline Specifier* next (CodeSpecifiers specifiers, Specifier& spec_iter) { return next_CodeSpecifiers(specifiers, & spec_iter); } + +#if ! GEN_C_LIKE_CPP +GEN_OPTIMIZE_MAPPINGS_BEGIN + +forceinline void append ( CodeBody body, Code other ) { return body_append(body, other); } +forceinline void append ( CodeBody body, CodeBody other ) { return body_append_body(body, other); } +forceinline StrBuilder to_strbuilder ( CodeBody body ) { return body_to_strbuilder(body); } +forceinline void to_strbuilder ( CodeBody body, StrBuilder& result ) { return body_to_strbuilder_ref(body, & result); } +forceinline void to_strbuilder_export( CodeBody body, StrBuilder& result ) { return body_to_strbuilder_export(body, & result); } + +forceinline void add_interface ( CodeClass self, CodeTypename interface ) { return class_add_interface(self, interface); } +forceinline StrBuilder to_strbuilder ( CodeClass self ) { return class_to_strbuilder(self); } +forceinline void to_strbuilder_def( CodeClass self, StrBuilder& result ) { return class_to_strbuilder_def(self, & result); } +forceinline void to_strbuilder_fwd( CodeClass self, StrBuilder& result ) { return class_to_strbuilder_fwd(self, & result); } + +forceinline void append (CodeParams params, CodeParams param ) { return params_append(params, param); } +forceinline CodeParams get (CodeParams params, s32 idx) { return params_get(params, idx); } +forceinline bool has_entries (CodeParams params ) { return params_has_entries(params); } +forceinline StrBuilder to_strbuilder(CodeParams params ) { return params_to_strbuilder(params); } +forceinline void to_strbuilder(CodeParams params, StrBuilder& result ) { return params_to_strbuilder_ref(params, & result); } + +forceinline bool append (CodeSpecifiers specifiers, Specifier spec) { return specifiers_append(specifiers, spec); } +forceinline s32 has (CodeSpecifiers specifiers, Specifier spec) { return specifiers_has(specifiers, spec); } +forceinline s32 remove (CodeSpecifiers specifiers, Specifier to_remove ) { return specifiers_remove(specifiers, to_remove); } +forceinline StrBuilder to_strbuilder(CodeSpecifiers specifiers) { return specifiers_to_strbuilder(specifiers); } +forceinline void to_strbuilder(CodeSpecifiers specifiers, StrBuilder& result) { return specifiers_to_strbuilder_ref(specifiers, & result); } + +forceinline void add_interface (CodeStruct self, CodeTypename interface) { return struct_add_interface(self, interface); } +forceinline StrBuilder to_strbuilder (CodeStruct self) { return struct_to_strbuilder(self); } +forceinline void to_strbuilder_fwd(CodeStruct self, StrBuilder& result) { return struct_to_strbuilder_fwd(self, & result); } +forceinline void to_strbuilder_def(CodeStruct self, StrBuilder& result) { return struct_to_strbuilder_def(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeAttributes attributes) { return attributes_to_strbuilder(attributes); } +forceinline void to_strbuilder(CodeAttributes attributes, StrBuilder& result) { return attributes_to_strbuilder_ref(attributes, & result); } + +forceinline StrBuilder to_strbuilder(CodeComment comment ) { return comment_to_strbuilder(comment); } +forceinline void to_strbuilder(CodeComment comment, StrBuilder& result ) { return comment_to_strbuilder_ref(comment, & result); } + +forceinline StrBuilder to_strbuilder (CodeConstructor constructor) { return constructor_to_strbuilder(constructor); } +forceinline void to_strbuilder_def(CodeConstructor constructor, StrBuilder& result ) { return constructor_to_strbuilder_def(constructor, & result); } +forceinline void to_strbuilder_fwd(CodeConstructor constructor, StrBuilder& result ) { return constructor_to_strbuilder_fwd(constructor, & result); } + +forceinline StrBuilder to_strbuilder(CodeDefine self) { return define_to_strbuilder(self); } +forceinline void to_strbuilder(CodeDefine self, StrBuilder& result) { return define_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder (CodeDestructor destructor) { return destructor_to_strbuilder(destructor); } +forceinline void to_strbuilder_def(CodeDestructor destructor, StrBuilder& result ) { return destructor_to_strbuilder_def(destructor, & result); } +forceinline void to_strbuilder_fwd(CodeDestructor destructor, StrBuilder& result ) { return destructor_to_strbuilder_fwd(destructor, & result); } + +forceinline StrBuilder to_strbuilder (CodeEnum self) { return enum_to_strbuilder(self); } +forceinline void to_strbuilder_def (CodeEnum self, StrBuilder& result ) { return enum_to_strbuilder_def(self, & result); } +forceinline void to_strbuilder_fwd (CodeEnum self, StrBuilder& result ) { return enum_to_strbuilder_fwd(self, & result); } +forceinline void to_strbuilder_class_def(CodeEnum self, StrBuilder& result ) { return enum_to_strbuilder_class_def(self, & result); } +forceinline void to_strbuilder_class_fwd(CodeEnum self, StrBuilder& result ) { return enum_to_strbuilder_class_fwd(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeExec exec) { return exec_to_strbuilder(exec); } +forceinline void to_strbuilder(CodeExec exec, StrBuilder& result) { return exec_to_strbuilder_ref(exec, & result); } + +forceinline void to_strbuilder(CodeExtern self, StrBuilder& result) { return extern_to_strbuilder(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeInclude self) { return include_to_strbuilder(self); } +forceinline void to_strbuilder(CodeInclude self, StrBuilder& result) { return include_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeFriend self) { return friend_to_strbuilder(self); } +forceinline void to_strbuilder(CodeFriend self, StrBuilder& result) { return friend_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder (CodeFn self) { return fn_to_strbuilder(self); } +forceinline void to_strbuilder_def(CodeFn self, StrBuilder& result) { return fn_to_strbuilder_def(self, & result); } +forceinline void to_strbuilder_fwd(CodeFn self, StrBuilder& result) { return fn_to_strbuilder_fwd(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeModule self) { return module_to_strbuilder(self); } +forceinline void to_strbuilder(CodeModule self, StrBuilder& result) { return module_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeNS self) { return namespace_to_strbuilder(self); } +forceinline void to_strbuilder(CodeNS self, StrBuilder& result) { return namespace_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder (CodeOperator self) { return code_op_to_strbuilder(self); } +forceinline void to_strbuilder_fwd(CodeOperator self, StrBuilder& result ) { return code_op_to_strbuilder_fwd(self, & result); } +forceinline void to_strbuilder_def(CodeOperator self, StrBuilder& result ) { return code_op_to_strbuilder_def(self, & result); } + +forceinline StrBuilder to_strbuilder (CodeOpCast op_cast ) { return opcast_to_strbuilder(op_cast); } +forceinline void to_strbuilder_def(CodeOpCast op_cast, StrBuilder& result ) { return opcast_to_strbuilder_def(op_cast, & result); } +forceinline void to_strbuilder_fwd(CodeOpCast op_cast, StrBuilder& result ) { return opcast_to_strbuilder_fwd(op_cast, & result); } + +forceinline StrBuilder to_strbuilder(CodePragma self) { return pragma_to_strbuilder(self); } +forceinline void to_strbuilder(CodePragma self, StrBuilder& result) { return pragma_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder (CodePreprocessCond cond) { return preprocess_to_strbuilder(cond); } +forceinline void to_strbuilder_if (CodePreprocessCond cond, StrBuilder& result ) { return preprocess_to_strbuilder_if(cond, & result); } +forceinline void to_strbuilder_ifdef (CodePreprocessCond cond, StrBuilder& result ) { return preprocess_to_strbuilder_ifdef(cond, & result); } +forceinline void to_strbuilder_ifndef(CodePreprocessCond cond, StrBuilder& result ) { return preprocess_to_strbuilder_ifndef(cond, & result); } +forceinline void to_strbuilder_elif (CodePreprocessCond cond, StrBuilder& result ) { return preprocess_to_strbuilder_elif(cond, & result); } +forceinline void to_strbuilder_else (CodePreprocessCond cond, StrBuilder& result ) { return preprocess_to_strbuilder_else(cond, & result); } +forceinline void to_strbuilder_endif (CodePreprocessCond cond, StrBuilder& result ) { return preprocess_to_strbuilder_endif(cond, & result); } + +forceinline StrBuilder to_strbuilder(CodeTemplate self) { return template_to_strbuilder(self); } +forceinline void to_strbuilder(CodeTemplate self, StrBuilder& result) { return template_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeTypename self) { return typename_to_strbuilder(self); } +forceinline void to_strbuilder(CodeTypename self, StrBuilder& result) { return typename_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder(CodeTypedef self) { return typedef_to_strbuilder(self); } +forceinline void to_strbuilder(CodeTypedef self, StrBuilder& result ) { return typedef_to_strbuilder_ref(self, & result); } + +forceinline StrBuilder to_strbuilder (CodeUnion self) { return union_to_strbuilder(self); } +forceinline void to_strbuilder_def(CodeUnion self, StrBuilder& result) { return union_to_strbuilder_def(self, & result); } +forceinline void to_strbuilder_fwd(CodeUnion self, StrBuilder& result) { return union_to_strbuilder_fwd(self, & result); } + +forceinline StrBuilder to_strbuilder (CodeUsing op_cast ) { return using_to_strbuilder(op_cast); } +forceinline void to_strbuilder (CodeUsing op_cast, StrBuilder& result ) { return using_to_strbuilder_ref(op_cast, & result); } +forceinline void to_strbuilder_ns(CodeUsing op_cast, StrBuilder& result ) { return using_to_strbuilder_ns(op_cast, & result); } + +forceinline StrBuilder to_strbuilder(CodeVar self) { return var_to_strbuilder(self); } +forceinline void to_strbuilder(CodeVar self, StrBuilder& result) { return var_to_strbuilder_ref(self, & result); } + +GEN_OPITMIZE_MAPPINGS_END +#endif //if GEN_C_LIKE_CPP + +#pragma endregion Code Types C++ +#endif //if GEN_COMPILER_CPP #pragma region AST Types /* - Show only relevant members of the AST for its type. - AST* fields are replaced with Code types. - - Guards assignemnts to AST* fields to ensure the AST is duplicated if assigned to another parent. + ______ ______ ________ ________ + / \ / \| \ | \ +| ▓▓▓▓▓▓\ ▓▓▓▓▓▓\\▓▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓▓__ __ ______ ______ _______ +| ▓▓__| ▓▓ ▓▓___\▓▓ | ▓▓ | ▓▓ | \ | \/ \ / \ / \ +| ▓▓ ▓▓\▓▓ \ | ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ +| ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ | ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓\▓▓ \ +| ▓▓ | ▓▓ \__| ▓▓ | ▓▓ | ▓▓ | ▓▓__/ ▓▓ ▓▓__/ ▓▓ ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ +| ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ \▓▓ ▓▓ ▓▓ ▓▓\▓▓ \ ▓▓ + \▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ _\▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓▓▓▓▓▓ + | \__| ▓▓ ▓▓ + \▓▓ ▓▓ ▓▓ + \▓▓▓▓▓▓ \▓▓ +*/ + +/* + Show only relevant members of the AST for its type. + AST* fields are replaced with Code types. + - Guards assignemnts to AST* fields to ensure the AST is duplicated if assigned to another parent. */ struct AST_Body { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - Code Front; - Code Back; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) ]; - s32 NumEntries; + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + Code Front; + Code Back; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; + s32 NumEntries; }; - -static_assert( sizeof( AST_Body ) == sizeof( AST ), "ERROR: AST_Body is not the same size as AST" ); +static_assert( sizeof(AST_Body) == sizeof(AST), "ERROR: AST_Body is not the same size as AST"); struct AST_Attributes { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - StringCached Content; + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + StrCached Content; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; +static_assert( sizeof(AST_Attributes) == sizeof(AST), "ERROR: AST_Attributes is not the same size as AST"); -static_assert( sizeof( AST_Attributes ) == sizeof( AST ), "ERROR: AST_Attributes is not the same size as AST" ); +#if 0 +struct AST_BaseClass +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_BaseClass) == sizeof(AST), "ERROR: AST_BaseClass is not the same size as AST"); +#endif struct AST_Comment { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - StringCached Content; + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + StrCached Content; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; - -static_assert( sizeof( AST_Comment ) == sizeof( AST ), "ERROR: AST_Comment is not the same size as AST" ); +static_assert( sizeof(AST_Comment) == sizeof(AST), "ERROR: AST_Comment is not the same size as AST"); struct AST_Class { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { - CodeComment InlineCmt; // Only supported by forward declarations - CodeAttributes Attributes; - char _PAD_SPECS_[ sizeof( AST* ) ]; - CodeType ParentType; - char _PAD_PARAMS_[ sizeof( AST* ) ]; - CodeBody Body; - char _PAD_PROPERTIES_2_[ sizeof( AST* ) ]; + CodeComment InlineCmt; // Only supported by forward declarations + CodeAttributes Attributes; + char _PAD_SPECS_ [ sizeof(AST*) ]; + CodeTypename ParentType; + char _PAD_PARAMS_[ sizeof(AST*) ]; + CodeBody Body; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; - - CodeType Prev; - CodeType Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - AccessSpec ParentAccess; + StrCached Name; + CodeTypename Prev; + CodeTypename Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + AccessSpec ParentAccess; }; - -static_assert( sizeof( AST_Class ) == sizeof( AST ), "ERROR: AST_Class is not the same size as AST" ); +static_assert( sizeof(AST_Class) == sizeof(AST), "ERROR: AST_Class is not the same size as AST"); struct AST_Constructor { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { - CodeComment InlineCmt; // Only supported by forward declarations - char _PAD_PROPERTIES_[ sizeof( AST* ) * 1 ]; + CodeComment InlineCmt; // Only supported by forward declarations + char _PAD_PROPERTIES_ [ sizeof(AST*) * 1 ]; CodeSpecifiers Specs; Code InitializerList; - CodeParam Params; + CodeParams Params; Code Body; - char _PAD_PROPERTIES_2_[ sizeof( AST* ) * 2 ]; + char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 2 ]; }; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - char _PAD_NAME_[ sizeof( StringCached ) ]; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; - -static_assert( sizeof( AST_Constructor ) == sizeof( AST ), "ERROR: AST_Constructor is not the same size as AST" ); +static_assert( sizeof(AST_Constructor) == sizeof(AST), "ERROR: AST_Constructor is not the same size as AST"); struct AST_Define { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - StringCached Content; + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + StrCached Content; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; - -static_assert( sizeof( AST_Define ) == sizeof( AST ), "ERROR: AST_Define is not the same size as AST" ); +static_assert( sizeof(AST_Define) == sizeof(AST), "ERROR: AST_Define is not the same size as AST"); struct AST_Destructor { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; - char _PAD_PROPERTIES_[ sizeof( AST* ) * 1 ]; + char _PAD_PROPERTIES_ [ sizeof(AST*) * 1 ]; CodeSpecifiers Specs; - char _PAD_PROPERTIES_2_[ sizeof( AST* ) * 2 ]; + char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 2 ]; Code Body; - char _PAD_PROPERTIES_3_[ sizeof( AST* ) ]; + char _PAD_PROPERTIES_3_ [ sizeof(AST*) ]; }; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - char _PAD_NAME_[ sizeof( StringCached ) ]; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; - -static_assert( sizeof( AST_Destructor ) == sizeof( AST ), "ERROR: AST_Destructor is not the same size as AST" ); +static_assert( sizeof(AST_Destructor) == sizeof(AST), "ERROR: AST_Destructor is not the same size as AST"); struct AST_Enum { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; CodeAttributes Attributes; - char _PAD_SPEC_[ sizeof( AST* ) ]; - CodeType UnderlyingType; - char _PAD_PARAMS_[ sizeof( AST* ) ]; + char _PAD_SPEC_ [ sizeof(AST*) ]; + CodeTypename UnderlyingType; + Code UnderlyingTypeMacro; CodeBody Body; - char _PAD_PROPERTIES_2_[ sizeof( AST* ) ]; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - char _PAD_UNUSED_[ sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; - -static_assert( sizeof( AST_Enum ) == sizeof( AST ), "ERROR: AST_Enum is not the same size as AST" ); +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* ) ]; - StringCached Content; + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + StrCached Content; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; +static_assert( sizeof(AST_Exec) == sizeof(AST), "ERROR: AST_Exec is not the same size as AST"); -static_assert( sizeof( AST_Exec ) == sizeof( AST ), "ERROR: AST_Exec is not the same size as AST" ); +#if GEN_EXECUTION_EXPRESSION_SUPPORT +struct AST_Expr +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr) == sizeof(AST), "ERROR: AST_Expr is not the same size as AST"); + +struct AST_Expr_Assign +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Assign) == sizeof(AST), "ERROR: AST_Expr_Assign is not the same size as AST"); + +struct AST_Expr_Alignof +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Alignof) == sizeof(AST), "ERROR: AST_Expr_Alignof is not the same size as AST"); + +struct AST_Expr_Binary +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Binary) == sizeof(AST), "ERROR: AST_Expr_Binary is not the same size as AST"); + +struct AST_Expr_CStyleCast +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_CStyleCast) == sizeof(AST), "ERROR: AST_Expr_CStyleCast is not the same size as AST"); + +struct AST_Expr_FunctionalCast +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_FunctionalCast) == sizeof(AST), "ERROR: AST_Expr_FunctionalCast is not the same size as AST"); + +struct AST_Expr_CppCast +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_CppCast) == sizeof(AST), "ERROR: AST_Expr_CppCast is not the same size as AST"); + +struct AST_Expr_ProcCall +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_ProcCall) == sizeof(AST), "ERROR: AST_Expr_Identifier is not the same size as AST"); + +struct AST_Expr_Decltype +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Decltype) == sizeof(AST), "ERROR: AST_Expr_Decltype is not the same size as AST"); + +struct AST_Expr_Comma +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Comma) == sizeof(AST), "ERROR: AST_Expr_Comma is not the same size as AST"); + +struct AST_Expr_AMS +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_AMS) == sizeof(AST), "ERROR: AST_Expr_AMS is not the same size as AST"); + +struct AST_Expr_Sizeof +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Sizeof) == sizeof(AST), "ERROR: AST_Expr_Sizeof is not the same size as AST"); + +struct AST_Expr_Subscript +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Subscript) == sizeof(AST), "ERROR: AST_Expr_Subscript is not the same size as AST"); + +struct AST_Expr_Ternary +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Ternary) == sizeof(AST), "ERROR: AST_Expr_Ternary is not the same size as AST"); + +struct AST_Expr_UnaryPrefix +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_UnaryPrefix) == sizeof(AST), "ERROR: AST_Expr_UnaryPrefix is not the same size as AST"); + +struct AST_Expr_UnaryPostfix +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_UnaryPostfix) == sizeof(AST), "ERROR: AST_Expr_UnaryPostfix is not the same size as AST"); + +struct AST_Expr_Element +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Expr_Element) == sizeof(AST), "ERROR: AST_Expr_Element is not the same size as AST"); +#endif struct AST_Extern { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { - char _PAD_PROPERTIES_[ sizeof( AST* ) * 5 ]; - CodeBody Body; - char _PAD_PROPERTIES_2_[ sizeof( AST* ) ]; + char _PAD_PROPERTIES_[ sizeof(AST*) * 5 ]; + CodeBody Body; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; - -static_assert( sizeof( AST_Extern ) == sizeof( AST ), "ERROR: AST_Extern is not the same size as AST" ); +static_assert( sizeof(AST_Extern) == sizeof(AST), "ERROR: AST_Extern is not the same size as AST"); struct AST_Include { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - StringCached Content; + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + StrCached Content; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; - -static_assert( sizeof( AST_Include ) == sizeof( AST ), "ERROR: AST_Include is not the same size as AST" ); +static_assert( sizeof(AST_Include) == sizeof(AST), "ERROR: AST_Include is not the same size as AST"); struct AST_Friend { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; - char _PAD_PROPERTIES_[ sizeof( AST* ) * 4 ]; + char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ]; Code Declaration; - char _PAD_PROPERTIES_2_[ sizeof( AST* ) ]; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; - -static_assert( sizeof( AST_Friend ) == sizeof( AST ), "ERROR: AST_Friend is not the same size as AST" ); +static_assert( sizeof(AST_Friend) == sizeof(AST), "ERROR: AST_Friend is not the same size as AST"); struct AST_Fn { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { - CodeComment InlineCmt; - CodeAttributes Attributes; - CodeSpecifiers Specs; - CodeType ReturnType; - CodeParam Params; - CodeBody Body; - char _PAD_PROPERTIES_[ sizeof( AST* ) ]; + CodeComment InlineCmt; + CodeAttributes Attributes; + CodeSpecifiers Specs; + CodeTypename ReturnType; + CodeParams Params; + CodeBody Body; + char _PAD_PROPERTIES_ [ sizeof(AST*) ]; }; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - char _PAD_UNUSED_[ sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(u32) ]; }; - -static_assert( sizeof( AST_Fn ) == sizeof( AST ), "ERROR: AST_Fn is not the same size as AST" ); +static_assert( sizeof(AST_Fn) == sizeof(AST), "ERROR: AST_Fn is not the same size as AST"); struct AST_Module { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - char _PAD_UNUSED_[ sizeof( u32 ) ]; + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(u32) ]; }; - -static_assert( sizeof( AST_Module ) == sizeof( AST ), "ERROR: AST_Module is not the same size as AST" ); +static_assert( sizeof(AST_Module) == sizeof(AST), "ERROR: AST_Module is not the same size as AST"); struct AST_NS { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - - struct - { - char _PAD_PROPERTIES_[ sizeof( AST* ) * 5 ]; - CodeBody Body; - char _PAD_PROPERTIES_2_[ sizeof( AST* ) ]; + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct { + char _PAD_PROPERTIES_[ sizeof(AST*) * 5 ]; + CodeBody Body; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - char _PAD_UNUSED_[ sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(u32) ]; }; - -static_assert( sizeof( AST_NS ) == sizeof( AST ), "ERROR: AST_NS is not the same size as AST" ); +static_assert( sizeof(AST_NS) == sizeof(AST), "ERROR: AST_NS is not the same size as AST"); struct AST_Operator { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { - CodeComment InlineCmt; - CodeAttributes Attributes; - CodeSpecifiers Specs; - CodeType ReturnType; - CodeParam Params; - CodeBody Body; - char _PAD_PROPERTIES_[ sizeof( AST* ) ]; + CodeComment InlineCmt; + CodeAttributes Attributes; + CodeSpecifiers Specs; + CodeTypename ReturnType; + CodeParams Params; + CodeBody Body; + char _PAD_PROPERTIES_ [ sizeof(AST*) ]; }; }; - + StrCached Name; Code Prev; Code Next; - Parser::Token* Token; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; ModuleFlag ModuleFlags; - OperatorT Op; + Operator Op; }; - -static_assert( sizeof( AST_Operator ) == sizeof( AST ), "ERROR: AST_Operator is not the same size as AST" ); +static_assert( sizeof(AST_Operator) == sizeof(AST), "ERROR: AST_Operator is not the same size as AST"); struct AST_OpCast { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { - CodeComment InlineCmt; - char _PAD_PROPERTIES_[ sizeof( AST* ) ]; - CodeSpecifiers Specs; - CodeType ValueType; - char _PAD_PROPERTIES_2_[ sizeof( AST* ) ]; - CodeBody Body; - char _PAD_PROPERTIES_3_[ sizeof( AST* ) ]; + CodeComment InlineCmt; + char _PAD_PROPERTIES_[ sizeof(AST*) ]; + CodeSpecifiers Specs; + CodeTypename ValueType; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; + CodeBody Body; + char _PAD_PROPERTIES_3_[ sizeof(AST*) ]; }; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; +static_assert( sizeof(AST_OpCast) == sizeof(AST), "ERROR: AST_OpCast is not the same size as AST"); -static_assert( sizeof( AST_OpCast ) == sizeof( AST ), "ERROR: AST_OpCast is not the same size as AST" ); - -struct AST_Param +struct AST_Params { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { - char _PAD_PROPERTIES_2_[ sizeof( AST* ) * 3 ]; - CodeType ValueType; - char _PAD_PROPERTIES_[ sizeof( AST* ) ]; - Code Value; - char _PAD_PROPERTIES_3_[ sizeof( AST* ) ]; + char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ]; + CodeTypename ValueType; + Code Macro; + Code Value; + Code PostNameMacro; // Thanks Unreal + // char _PAD_PROPERTIES_3_[sizeof( AST* )]; }; }; - - CodeParam Last; - CodeParam Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) ]; - s32 NumEntries; + StrCached Name; + CodeParams Last; + CodeParams Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; + s32 NumEntries; }; - -static_assert( sizeof( AST_Param ) == sizeof( AST ), "ERROR: AST_Param is not the same size as AST" ); +static_assert( sizeof(AST_Params) == sizeof(AST), "ERROR: AST_Params is not the same size as AST"); struct AST_Pragma { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - StringCached Content; + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + StrCached Content; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; - -static_assert( sizeof( AST_Pragma ) == sizeof( AST ), "ERROR: AST_Pragma is not the same size as AST" ); +static_assert( sizeof(AST_Pragma) == sizeof(AST), "ERROR: AST_Pragma is not the same size as AST"); struct AST_PreprocessCond { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - StringCached Content; + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + StrCached Content; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; - -static_assert( sizeof( AST_PreprocessCond ) == sizeof( AST ), "ERROR: AST_PreprocessCond is not the same size as AST" ); +static_assert( sizeof(AST_PreprocessCond) == sizeof(AST), "ERROR: AST_PreprocessCond is not the same size as AST"); struct AST_Specifiers { - SpecifierT ArrSpecs[ AST::ArrSpecs_Cap ]; - CodeSpecifiers NextSpecs; - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) ]; - s32 NumEntries; + Specifier ArrSpecs[ AST_ArrSpecs_Cap ]; + StrCached Name; + CodeSpecifiers NextSpecs; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; + s32 NumEntries; }; +static_assert( sizeof(AST_Specifiers) == sizeof(AST), "ERROR: AST_Specifier is not the same size as AST"); -static_assert( sizeof( AST_Specifiers ) == sizeof( AST ), "ERROR: AST_Specifier is not the same size as AST" ); +#if GEN_EXECUTION_EXPRESSION_SUPPORT +struct AST_Stmt +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt) == sizeof(AST), "ERROR: AST_Stmt is not the same size as AST"); + +struct AST_Stmt_Break +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Break) == sizeof(AST), "ERROR: AST_Stmt_Break is not the same size as AST"); + +struct AST_Stmt_Case +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Case) == sizeof(AST), "ERROR: AST_Stmt_Case is not the same size as AST"); + +struct AST_Stmt_Continue +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Continue) == sizeof(AST), "ERROR: AST_Stmt_Continue is not the same size as AST"); + +struct AST_Stmt_Decl +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Decl) == sizeof(AST), "ERROR: AST_Stmt_Decl is not the same size as AST"); + +struct AST_Stmt_Do +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Do) == sizeof(AST), "ERROR: AST_Stmt_Do is not the same size as AST"); + +struct AST_Stmt_Expr +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Expr) == sizeof(AST), "ERROR: AST_Stmt_Expr is not the same size as AST"); + +struct AST_Stmt_Else +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Else) == sizeof(AST), "ERROR: AST_Stmt_Else is not the same size as AST"); + +struct AST_Stmt_If +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_If) == sizeof(AST), "ERROR: AST_Stmt_If is not the same size as AST"); + +struct AST_Stmt_For +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_For) == sizeof(AST), "ERROR: AST_Stmt_For is not the same size as AST"); + +struct AST_Stmt_Goto +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Goto) == sizeof(AST), "ERROR: AST_Stmt_Goto is not the same size as AST"); + +struct AST_Stmt_Label +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Label) == sizeof(AST), "ERROR: AST_Stmt_Label is not the same size as AST"); + +struct AST_Stmt_Switch +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_Switch) == sizeof(AST), "ERROR: AST_Stmt_Switch is not the same size as AST"); + +struct AST_Stmt_While +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StrCached Name; + CodeExpr Prev; + CodeExpr Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; +}; +static_assert( sizeof(AST_Stmt_While) == sizeof(AST), "ERROR: AST_Stmt_While is not the same size as AST"); +#endif struct AST_Struct { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; CodeAttributes Attributes; - char _PAD_SPECS_[ sizeof( AST* ) ]; - CodeType ParentType; - char _PAD_PARAMS_[ sizeof( AST* ) ]; + char _PAD_SPECS_ [ sizeof(AST*) ]; + CodeTypename ParentType; + char _PAD_PARAMS_[ sizeof(AST*) ]; CodeBody Body; - char _PAD_PROPERTIES_2_[ sizeof( AST* ) ]; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; - - CodeType Prev; - CodeType Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - AccessSpec ParentAccess; + StrCached Name; + CodeTypename Prev; + CodeTypename Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + AccessSpec ParentAccess; }; - -static_assert( sizeof( AST_Struct ) == sizeof( AST ), "ERROR: AST_Struct is not the same size as AST" ); +static_assert( sizeof(AST_Struct) == sizeof(AST), "ERROR: AST_Struct is not the same size as AST"); struct AST_Template { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { - char _PAD_PROPERTIES_[ sizeof( AST* ) * 4 ]; - CodeParam Params; - Code Declaration; - char _PAD_PROPERTIES_2_[ sizeof( AST* ) ]; + char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ]; + CodeParams Params; + Code Declaration; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - char _PAD_UNUSED_[ sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(u32) ]; }; +static_assert( sizeof(AST_Template) == sizeof(AST), "ERROR: AST_Template is not the same size as AST"); -static_assert( sizeof( AST_Template ) == sizeof( AST ), "ERROR: AST_Template is not the same size as AST" ); - +#if 0 +// WIP... The type ast is going to become more advanced and lead to a major change to AST design. struct AST_Type { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { - char _PAD_INLINE_CMT_[ sizeof( AST* ) ]; - CodeAttributes Attributes; - CodeSpecifiers Specs; - CodeType ReturnType; // Only used for function signatures - CodeParam Params; // Only used for function signatures - Code ArrExpr; - CodeSpecifiers SpecsFuncSuffix; // Only used for function signatures + char _PAD_INLINE_CMT_[ sizeof(AST*) ]; + CodeAttributes Attributes; + CodeSpecifiers Specs; + Code QualifierID; + // CodeTypename ReturnType; // Only used for function signatures + // CodeParams Params; // Only used for function signatures + Code ArrExpr; + // CodeSpecifiers SpecsFuncSuffix; // Only used for function signatures }; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - char _PAD_UNUSED_[ sizeof( ModuleFlag ) ]; - b32 IsParamPack; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; + b32 IsParamPack; }; +static_assert( sizeof(AST_Type) == sizeof(AST), "ERROR: AST_Type is not the same size as AST"); +#endif -static_assert( sizeof( AST_Type ) == sizeof( AST ), "ERROR: AST_Type is not the same size as AST" ); +struct AST_Typename +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + char _PAD_INLINE_CMT_[ sizeof(AST*) ]; + CodeAttributes Attributes; + CodeSpecifiers Specs; + CodeTypename ReturnType; // Only used for function signatures + CodeParams Params; // Only used for function signatures + Code ArrExpr; + CodeSpecifiers SpecsFuncSuffix; // Only used for function signatures + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; + struct { + b16 IsParamPack; // Used by typename to know if type should be considered a parameter pack. + ETypenameTag TypeTag; // Used by typename to keep track of explicitly declared tags for the identifier (enum, struct, union) + }; +}; +static_assert( sizeof(AST_Typename) == sizeof(AST), "ERROR: AST_Type is not the same size as AST"); struct AST_Typedef { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - - struct - { - CodeComment InlineCmt; - char _PAD_PROPERTIES_[ sizeof( AST* ) * 2 ]; - Code UnderlyingType; - char _PAD_PROPERTIES_2_[ sizeof( AST* ) * 3 ]; - }; - }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - b32 IsFunction; -}; - -static_assert( sizeof( AST_Typedef ) == sizeof( AST ), "ERROR: AST_Typedef is not the same size as AST" ); - -struct AST_Union -{ - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - - struct - { - char _PAD_INLINE_CMT_[ sizeof( AST* ) ]; - CodeAttributes Attributes; - char _PAD_PROPERTIES_[ sizeof( AST* ) * 3 ]; - CodeBody Body; - char _PAD_PROPERTIES_2_[ sizeof( AST* ) ]; - }; - }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - char _PAD_UNUSED_[ sizeof( u32 ) ]; -}; - -static_assert( sizeof( AST_Union ) == sizeof( AST ), "ERROR: AST_Union is not the same size as AST" ); - -struct AST_Using -{ - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; - CodeAttributes Attributes; - char _PAD_SPECS_[ sizeof( AST* ) ]; - CodeType UnderlyingType; - char _PAD_PROPERTIES_[ sizeof( AST* ) * 3 ]; + char _PAD_PROPERTIES_[ sizeof(AST*) * 2 ]; + Code UnderlyingType; + char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ]; }; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - char _PAD_UNUSED_[ sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + b32 IsFunction; }; +static_assert( sizeof(AST_Typedef) == sizeof(AST), "ERROR: AST_Typedef is not the same size as AST"); -static_assert( sizeof( AST_Using ) == sizeof( AST ), "ERROR: AST_Using is not the same size as AST" ); +struct AST_Union +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + char _PAD_INLINE_CMT_[ sizeof(AST*) ]; + CodeAttributes Attributes; + char _PAD_PROPERTIES_[ sizeof(AST*) * 3 ]; + CodeBody Body; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(u32) ]; +}; +static_assert( sizeof(AST_Union) == sizeof(AST), "ERROR: AST_Union is not the same size as AST"); + +struct AST_Using +{ + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + struct + { + CodeComment InlineCmt; + CodeAttributes Attributes; + char _PAD_SPECS_ [ sizeof(AST*) ]; + CodeTypename UnderlyingType; + char _PAD_PROPERTIES_[ sizeof(AST*) * 3 ]; + }; + }; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(u32) ]; +}; +static_assert( sizeof(AST_Using) == sizeof(AST), "ERROR: AST_Using is not the same size as AST"); struct AST_Var { - union - { - char _PAD_[ sizeof( SpecifierT ) * AST::ArrSpecs_Cap + sizeof( AST* ) ]; - + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; CodeAttributes Attributes; CodeSpecifiers Specs; - CodeType ValueType; + CodeTypename ValueType; Code BitfieldSize; Code Value; - CodeVar NextVar; + CodeVar NextVar; }; }; - - Code Prev; - Code Next; - Parser::Token* Token; - Code Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - char _PAD_UNUSED_[ sizeof( u32 ) ]; + StrCached Name; + Code Prev; + Code Next; + Token* Tok; + Code Parent; + CodeType Type; + ModuleFlag ModuleFlags; + s32 VarParenthesizedInit; }; - -static_assert( sizeof( AST_Var ) == sizeof( AST ), "ERROR: AST_Var is not the same size as AST" ); +static_assert( sizeof(AST_Var) == sizeof(AST), "ERROR: AST_Var is not the same size as AST"); #pragma endregion AST Types #pragma endregion AST #pragma region Gen Interface +/* + / \ | \ | \ / \ +| ▓▓▓▓▓▓\ ______ _______ \▓▓▓▓▓▓_______ _| ▓▓_ ______ ______ | ▓▓▓▓▓▓\ ______ _______ ______ +| ▓▓ __\▓▓/ \| \ | ▓▓ | \| ▓▓ \ / \ / \| ▓▓_ \▓▓| \ / \/ \ +| ▓▓| \ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓\ | ▓▓ | ▓▓▓▓▓▓▓\\▓▓▓▓▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓ \ \▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\ +| ▓▓ \▓▓▓▓ ▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ __| ▓▓ ▓▓ ▓▓ \▓▓ ▓▓▓▓ / ▓▓ ▓▓ | ▓▓ ▓▓ +| ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ _| ▓▓_| ▓▓ | ▓▓ | ▓▓| \ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ | ▓▓▓▓▓▓▓ ▓▓_____| ▓▓▓▓▓▓▓▓ + \▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ | ▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \\▓▓ \ + \▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ +*/ -// Initialize the library. -// This currently just initializes the CodePool. -void init(); +#if 0 +enum LogLevel : u32 +{ + Info, + Warning, + Panic, +}; + +struct LogEntry +{ + Str msg; + u32 line_num; + void* data; +}; + +typedef void LoggerCallback(LogEntry entry); +#endif + +// Note(Ed): This is subject to heavily change +// with upcoming changes to the library's fallback (default) allocations strategy; +// and major changes to lexer/parser context usage. +struct Context +{ +// User Configuration + +// Persistent Data Allocation + AllocatorInfo Allocator_DyanmicContainers; // By default will use a genral slab allocator (TODO(Ed): Currently does not) + AllocatorInfo Allocator_Pool; // By default will use the growing vmem reserve (TODO(Ed): Currently does not) + AllocatorInfo Allocator_StrCache; // By default will use a dedicated slab allocator (TODO(Ed): Currently does not) + +// Temporary Allocation + AllocatorInfo Allocator_Temp; + + // LoggerCallaback* log_callback; // TODO(Ed): Impl user logger callback as an option. + + u32 Max_CommentLineLength; // Used by def_comment + u32 Max_StrCacheLength; // Any cached string longer than this is always allocated again. + + u32 InitSize_BuilderBuffer; + u32 InitSize_CodePoolsArray; + u32 InitSize_StringArenasArray; + + u32 CodePool_NumBlocks; + + // TODO(Ed): Review these... (No longer needed if using the proper allocation strategy) + u32 InitSize_LexArena; + u32 SizePer_StringArena; + +// TODO(Ed): Symbol Table + // Keep track of all resolved symbols (naemspaced identifiers) + +// Parser + + // Used by the lexer to persistently treat all these identifiers as preprocessor defines. + // Populate with strings via gen::cache_str. + // Functional defines must have format: id( ;at minimum to indicate that the define is only valid with arguments. + Array(StrCached) PreprocessorDefines; + +// Backend + + // The fallback allocator is utilized if any fo the three above allocators is not specified by the user. + u32 InitSize_Fallback_Allocator_Bucket_Size; + Array(Arena) Fallback_AllocatorBuckets; + + // Array(Token) LexerTokens; + + Array(Pool) CodePools; + Array(Arena) StringArenas; + + StringTable StrCache; + + // TODO(Ed): This needs to be just handled by a parser context + + Arena LexArena; + StringTable Lexer_defines; + Array(Token) Lexer_Tokens; + + // TODO(Ed): Active parse context vs a parse result need to be separated conceptually + ParseContext parser; +}; + +// Initialize the library. There first ctx initialized must exist for lifetime of other contextes that come after as its the one that +GEN_API void init(Context* ctx); // Currently manually free's the arenas, code for checking for leaks. // However on Windows at least, it doesn't need to occur as the OS will clean up after the process. -void deinit(); +GEN_API void deinit(Context* ctx); -// Clears the allocations, but doesn't return to the heap, the calls init() again. +// Clears the allocations, but doesn't free the memoery, then calls init() again. // Ease of use. -void reset(); +GEN_API void reset(Context* ctx); + +GEN_API void set_context(Context* ctx); + +// Alternative way to add a preprocess define entry for the lexer & parser to utilize +// if the user doesn't want to use def_define +GEN_API void set_preprocess_define( Str id, b32 is_functional ); // Used internally to retrive or make string allocations. // Strings are stored in a series of string arenas of fixed size (SizePer_StringArena) -StringCached get_cached_string( StrC str ); +GEN_API StrCached cache_str( Str str ); /* - This provides a fresh Code AST. - The gen interface use this as their method from getting a new AST object from the CodePool. - Use this if you want to make your own API for formatting the supported Code Types. + This provides a fresh Code AST. + The gen interface use this as their method from getting a new AST object from the CodePool. + Use this if you want to make your own API for formatting the supported Code Types. */ -Code make_code(); +GEN_API Code make_code(); // Set these before calling gen's init() procedure. -// Data - -void set_allocator_data_arrays( AllocatorInfo data_array_allocator ); -void set_allocator_code_pool( AllocatorInfo pool_allocator ); -void set_allocator_lexer( AllocatorInfo lex_allocator ); -void set_allocator_string_arena( AllocatorInfo string_allocator ); -void set_allocator_string_table( AllocatorInfo string_allocator ); -void set_allocator_type_table( AllocatorInfo type_reg_allocator ); #pragma region Upfront -CodeAttributes def_attributes( StrC content ); -CodeComment def_comment( StrC content ); +GEN_API CodeAttributes def_attributes( Str content ); +GEN_API CodeComment def_comment ( Str content ); -CodeClass def_class( - StrC name, - Code body = NoCode, - CodeType parent = NoCode, - AccessSpec access = AccessSpec::Default, - CodeAttributes attributes = NoCode, - ModuleFlag mflags = ModuleFlag::None, - CodeType* interfaces = nullptr, - s32 num_interfaces = 0 -); +struct Opts_def_struct { + CodeBody body; + CodeTypename parent; + AccessSpec parent_access; + CodeAttributes attributes; + CodeTypename* interfaces; + s32 num_interfaces; + ModuleFlag mflags; +}; +GEN_API CodeClass def_class( Str name, Opts_def_struct opts GEN_PARAM_DEFAULT ); -CodeConstructor def_constructor( CodeParam params = NoCode, Code initializer_list = NoCode, Code body = NoCode ); +struct Opts_def_constructor { + CodeParams params; + Code initializer_list; + Code body; +}; +GEN_API CodeConstructor def_constructor( Opts_def_constructor opts GEN_PARAM_DEFAULT ); -CodeDefine def_define( StrC name, StrC content ); +struct Opts_def_define { + b32 dont_append_preprocess_defines; +}; +GEN_API CodeDefine def_define( Str name, Str content, Opts_def_define opts GEN_PARAM_DEFAULT ); -CodeDestructor def_destructor( Code body = NoCode, CodeSpecifiers specifiers = NoCode ); +struct Opts_def_destructor { + Code body; + CodeSpecifiers specifiers; +}; +GEN_API CodeDestructor def_destructor( Opts_def_destructor opts GEN_PARAM_DEFAULT ); -CodeEnum def_enum( - StrC name, - Code body = NoCode, - CodeType type = NoCode, - EnumT specifier = EnumRegular, - CodeAttributes attributes = NoCode, - ModuleFlag mflags = ModuleFlag::None -); +struct Opts_def_enum { + CodeBody body; + CodeTypename type; + EnumT specifier; + CodeAttributes attributes; + ModuleFlag mflags; + Code type_macro; +}; +GEN_API CodeEnum def_enum( Str name, Opts_def_enum opts GEN_PARAM_DEFAULT ); -CodeExec def_execution( StrC content ); -CodeExtern def_extern_link( StrC name, Code body ); -CodeFriend def_friend( Code symbol ); +GEN_API CodeExec def_execution ( Str content ); +GEN_API CodeExtern def_extern_link( Str name, CodeBody body ); +GEN_API 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 -); +struct Opts_def_function { + CodeParams params; + CodeTypename ret_type; + CodeBody body; + CodeSpecifiers specs; + CodeAttributes attrs; + ModuleFlag mflags; +}; +GEN_API CodeFn def_function( Str name, Opts_def_function opts GEN_PARAM_DEFAULT ); -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 ); +struct Opts_def_include { b32 foreign; }; +struct Opts_def_module { ModuleFlag mflags; }; +struct Opts_def_namespace { ModuleFlag mflags; }; +GEN_API CodeInclude def_include ( Str content, Opts_def_include opts GEN_PARAM_DEFAULT ); +GEN_API CodeModule def_module ( Str name, Opts_def_module opts GEN_PARAM_DEFAULT ); +GEN_API CodeNS def_namespace( Str name, CodeBody body, Opts_def_namespace opts GEN_PARAM_DEFAULT ); -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 -); +struct Opts_def_operator { + CodeParams params; + CodeTypename ret_type; + CodeBody body; + CodeSpecifiers specifiers; + CodeAttributes attributes; + ModuleFlag mflags; +}; +GEN_API CodeOperator def_operator( Operator op, Str nspace, Opts_def_operator opts GEN_PARAM_DEFAULT ); -CodeOpCast def_operator_cast( CodeType type, Code body = NoCode, CodeSpecifiers specs = NoCode ); +struct Opts_def_operator_cast { + CodeBody body; + CodeSpecifiers specs; +}; +GEN_API CodeOpCast def_operator_cast( CodeTypename type, Opts_def_operator_cast opts GEN_PARAM_DEFAULT ); -CodeParam def_param( CodeType type, StrC name, Code value = NoCode ); -CodePragma def_pragma( StrC directive ); +struct Opts_def_param { Code value; }; +GEN_API CodeParams def_param ( CodeTypename type, Str name, Opts_def_param opts GEN_PARAM_DEFAULT ); +GEN_API CodePragma def_pragma( Str directive ); -CodePreprocessCond def_preprocess_cond( EPreprocessCond type, StrC content ); +GEN_API CodePreprocessCond def_preprocess_cond( EPreprocessCond type, Str content ); -CodeSpecifiers def_specifier( SpecifierT specifier ); +GEN_API CodeSpecifiers def_specifier( Specifier specifier ); -CodeStruct def_struct( - StrC name, - Code body = NoCode, - CodeType parent = NoCode, - AccessSpec access = AccessSpec::Default, - CodeAttributes attributes = NoCode, - ModuleFlag mflags = ModuleFlag::None, - CodeType* interfaces = nullptr, - s32 num_interfaces = 0 -); +GEN_API CodeStruct def_struct( Str name, Opts_def_struct opts GEN_PARAM_DEFAULT ); -CodeTemplate def_template( CodeParam params, Code definition, ModuleFlag mflags = ModuleFlag::None ); +struct Opts_def_template { ModuleFlag mflags; }; +GEN_API CodeTemplate def_template( CodeParams params, Code definition, Opts_def_template opts GEN_PARAM_DEFAULT ); -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 ); +struct Opts_def_type { + ETypenameTag type_tag; + Code arrayexpr; + CodeSpecifiers specifiers; + CodeAttributes attributes; +}; +GEN_API CodeTypename def_type( Str name, Opts_def_type opts GEN_PARAM_DEFAULT ); -CodeUnion def_union( StrC name, Code body, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag::None ); +struct Opts_def_typedef { + CodeAttributes attributes; + ModuleFlag mflags; +}; +GEN_API CodeTypedef def_typedef( Str name, Code type, Opts_def_typedef opts GEN_PARAM_DEFAULT ); -CodeUsing def_using( StrC name, CodeType type = NoCode, CodeAttributes attributess = NoCode, ModuleFlag mflags = ModuleFlag::None ); +struct Opts_def_union { + CodeAttributes attributes; + ModuleFlag mflags; +}; +GEN_API CodeUnion def_union( Str name, CodeBody body, Opts_def_union opts GEN_PARAM_DEFAULT ); -CodeUsing def_using_namespace( StrC name ); +struct Opts_def_using { + CodeAttributes attributes; + ModuleFlag mflags; +}; +GEN_API CodeUsing def_using( Str name, CodeTypename type, Opts_def_using opts GEN_PARAM_DEFAULT ); -CodeVar def_variable( - CodeType type, - StrC name, - Code value = NoCode, - CodeSpecifiers specifiers = NoCode, - CodeAttributes attributes = NoCode, - ModuleFlag mflags = ModuleFlag::None -); +GEN_API CodeUsing def_using_namespace( Str name ); + +struct Opts_def_variable +{ + Code value; + CodeSpecifiers specifiers; + CodeAttributes attributes; + ModuleFlag mflags; +}; +GEN_API CodeVar def_variable( CodeTypename type, Str name, Opts_def_variable opts GEN_PARAM_DEFAULT ); // Constructs an empty body. Use AST::validate_body() to check if the body is was has valid entries. -CodeBody def_body( CodeT type ); +GEN_API CodeBody def_body( CodeType type ); // There are two options for defining a struct body, either varadically provided with the args macro to auto-deduce the arg num, /// or provide as an array of Code objects. -CodeBody def_class_body( s32 num, ... ); -CodeBody def_class_body( s32 num, Code* codes ); -CodeBody def_enum_body( s32 num, ... ); -CodeBody def_enum_body( s32 num, Code* codes ); -CodeBody def_export_body( s32 num, ... ); -CodeBody def_export_body( s32 num, Code* codes ); -CodeBody def_extern_link_body( s32 num, ... ); -CodeBody def_extern_link_body( s32 num, Code* codes ); -CodeBody def_function_body( s32 num, ... ); -CodeBody def_function_body( s32 num, Code* codes ); -CodeBody def_global_body( s32 num, ... ); -CodeBody def_global_body( s32 num, Code* codes ); -CodeBody def_namespace_body( s32 num, ... ); -CodeBody def_namespace_body( s32 num, Code* codes ); -CodeParam def_params( s32 num, ... ); -CodeParam def_params( s32 num, CodeParam* params ); -CodeSpecifiers def_specifiers( s32 num, ... ); -CodeSpecifiers def_specifiers( s32 num, SpecifierT* specs ); -CodeBody def_struct_body( s32 num, ... ); -CodeBody def_struct_body( s32 num, Code* codes ); -CodeBody def_union_body( s32 num, ... ); -CodeBody def_union_body( s32 num, Code* codes ); +GEN_API CodeBody def_class_body ( s32 num, ... ); +GEN_API CodeBody def_class_body ( s32 num, Code* codes ); +GEN_API CodeBody def_enum_body ( s32 num, ... ); +GEN_API CodeBody def_enum_body ( s32 num, Code* codes ); +GEN_API CodeBody def_export_body ( s32 num, ... ); +GEN_API CodeBody def_export_body ( s32 num, Code* codes); +GEN_API CodeBody def_extern_link_body( s32 num, ... ); +GEN_API CodeBody def_extern_link_body( s32 num, Code* codes ); +GEN_API CodeBody def_function_body ( s32 num, ... ); +GEN_API CodeBody def_function_body ( s32 num, Code* codes ); +GEN_API CodeBody def_global_body ( s32 num, ... ); +GEN_API CodeBody def_global_body ( s32 num, Code* codes ); +GEN_API CodeBody def_namespace_body ( s32 num, ... ); +GEN_API CodeBody def_namespace_body ( s32 num, Code* codes ); +GEN_API CodeParams def_params ( s32 num, ... ); +GEN_API CodeParams def_params ( s32 num, CodeParams* params ); +GEN_API CodeSpecifiers def_specifiers ( s32 num, ... ); +GEN_API CodeSpecifiers def_specifiers ( s32 num, Specifier* specs ); +GEN_API CodeBody def_struct_body ( s32 num, ... ); +GEN_API CodeBody def_struct_body ( s32 num, Code* codes ); +GEN_API CodeBody def_union_body ( s32 num, ... ); +GEN_API CodeBody def_union_body ( s32 num, Code* codes ); #pragma endregion Upfront #pragma region Parsing -CodeClass parse_class( StrC class_def ); -CodeConstructor parse_constructor( StrC constructor_def ); -CodeDestructor parse_destructor( StrC destructor_def ); -CodeEnum parse_enum( StrC enum_def ); -CodeBody parse_export_body( StrC export_def ); -CodeExtern parse_extern_link( StrC exten_link_def ); -CodeFriend parse_friend( StrC friend_def ); -CodeFn parse_function( StrC fn_def ); -CodeBody parse_global_body( StrC body_def ); -CodeNS parse_namespace( StrC namespace_def ); -CodeOperator parse_operator( StrC operator_def ); -CodeOpCast parse_operator_cast( StrC operator_def ); -CodeStruct parse_struct( StrC struct_def ); -CodeTemplate parse_template( StrC template_def ); -CodeType parse_type( StrC type_def ); -CodeTypedef parse_typedef( StrC typedef_def ); -CodeUnion parse_union( StrC union_def ); -CodeUsing parse_using( StrC using_def ); -CodeVar parse_variable( StrC var_def ); +// TODO(Ed) : Implmeent the new parser API design. + +#if 0 +struct StackNode +{ + StackNode* Prev; + + Token Start; + Token Name; // The name of the AST node (if parsed) + Str FailedProc; // The name of the procedure that failed +}; +// Stack nodes are allocated the error's allocator + +struct Error +{ + StrBuilder message; + StackNode* context_stack; +}; + +struct ParseInfo +{ + Arena FileMem; + Arena TokMem; + Arena CodeMem; + + FileContents FileContent; + Array Tokens; + Array Errors; + // Errors are allocated to a dedicated general arena. +}; + +CodeBody parse_file( Str path ); +#endif + +GEN_API CodeClass parse_class ( Str class_def ); +GEN_API CodeConstructor parse_constructor ( Str constructor_def ); +GEN_API CodeDestructor parse_destructor ( Str destructor_def ); +GEN_API CodeEnum parse_enum ( Str enum_def ); +GEN_API CodeBody parse_export_body ( Str export_def ); +GEN_API CodeExtern parse_extern_link ( Str exten_link_def ); +GEN_API CodeFriend parse_friend ( Str friend_def ); +GEN_API CodeFn parse_function ( Str fn_def ); +GEN_API CodeBody parse_global_body ( Str body_def ); +GEN_API CodeNS parse_namespace ( Str namespace_def ); +GEN_API CodeOperator parse_operator ( Str operator_def ); +GEN_API CodeOpCast parse_operator_cast( Str operator_def ); +GEN_API CodeStruct parse_struct ( Str struct_def ); +GEN_API CodeTemplate parse_template ( Str template_def ); +GEN_API CodeTypename parse_type ( Str type_def ); +GEN_API CodeTypedef parse_typedef ( Str typedef_def ); +GEN_API CodeUnion parse_union ( Str union_def ); +GEN_API CodeUsing parse_using ( Str using_def ); +GEN_API CodeVar parse_variable ( Str var_def ); #pragma endregion Parsing #pragma region Untyped text -sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va ); +GEN_API ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ); //! Do not use directly. Use the token_fmt macro instead. -StrC token_fmt_impl( sw, ... ); +GEN_API Str token_fmt_impl( ssize, ... ); -Code untyped_str( StrC content ); -Code untyped_fmt( char const* fmt, ... ); -Code untyped_token_fmt( char const* fmt, s32 num_tokens, ... ); +GEN_API Code untyped_str( Str content); +GEN_API Code untyped_fmt ( char const* fmt, ... ); +GEN_API Code untyped_token_fmt( s32 num_tokens, char const* fmt, ... ); #pragma endregion Untyped text +#pragma region Macros + +#ifndef gen_main +#define gen_main main +#endif + +#ifndef name +// Convienence for defining any name used with the gen api. +// Lets you provide the length and string literal to the functions without the need for the DSL. +#define name( Id_ ) { stringize(Id_), sizeof(stringize( Id_ )) - 1 } +#endif + +#ifndef code +// Same as name just used to indicate intention of literal for code instead of names. +#define code( ... ) { stringize( __VA_ARGS__ ), sizeof(stringize(__VA_ARGS__)) - 1 } +#endif + +#ifndef args +// Provides the number of arguments while passing args inplace. +#define args( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__ +#endif + +#ifndef code_str +// Just wrappers over common untyped code definition constructions. +#define code_str( ... ) GEN_NS untyped_str( code( __VA_ARGS__ ) ) +#endif + +#ifndef code_fmt +#define code_fmt( ... ) GEN_NS untyped_str( token_fmt( __VA_ARGS__ ) ) +#endif + +#ifndef parse_fmt +#define parse_fmt( type, ... ) GEN_NS parse_##type( token_fmt( __VA_ARGS__ ) ) +#endif + +#ifndef token_fmt +/* +Takes a format string (char const*) and a list of tokens (Str) and returns a Str of the formatted string. +Tokens are provided in '<'identifier'>' format where '<' '>' are just angle brackets (you can change it in token_fmt_va) +--------------------------------------------------------- + Example - A string with: + typedef ; + Will have a token_fmt arguments populated with: + "type", str_for_type, + "name", str_for_name, + and: + stringize( typedef ; ) +----------------------------------------------------------- +So the full call for this example would be: + token_fmt( + "type", str_for_type + , "name", str_for_name + , stringize( + typedef + )); +!---------------------------------------------------------- +! Note: token_fmt_va is whitespace sensitive for the tokens. +! This can be alleviated by skipping whitespace between brackets but it was choosen to not have that implementation by default. +*/ +#define token_fmt( ... ) GEN_NS token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ ) +#endif + +#pragma endregion Macros + #pragma endregion Gen Interface #pragma region Inlines -void AST::append( AST* other ) +#pragma region Code +inline +void code_append( Code self, Code other ) { - if ( other->Parent ) - other = other->duplicate(); + GEN_ASSERT(self); + GEN_ASSERT(other); + GEN_ASSERT_MSG(self != other, "Attempted to recursively append Code AST to itself."); - other->Parent = this; + if ( other->Parent != nullptr ) + other = code_duplicate(other); - if ( Front == nullptr ) + other->Parent = self; + + if ( self->Front == nullptr ) { - Front = other; - Back = other; + self->Front = other; + self->Back = other; - NumEntries++; + self->NumEntries++; return; } - AST* Current = Back; + Code + Current = self->Back; Current->Next = other; other->Prev = Current; - Back = other; - NumEntries++; + self->Back = other; + self->NumEntries++; } - -Code& AST::entry( u32 idx ) +inline +bool code_is_body(Code self) { - AST** current = &Front; + GEN_ASSERT(self); + switch (self->Type) + { + case CT_Enum_Body: + case CT_Class_Body: + case CT_Union_Body: + case CT_Export_Body: + case CT_Global_Body: + case CT_Struct_Body: + case CT_Function_Body: + case CT_Namespace_Body: + case CT_Extern_Linkage_Body: + return true; + } + return false; +} +inline +Code* code_entry( Code self, u32 idx ) +{ + GEN_ASSERT(self != nullptr); + Code* current = & self->Front; while ( idx >= 0 && current != nullptr ) { if ( idx == 0 ) - return *rcast( Code*, current ); + return rcast( Code*, current); - current = &( *current )->Next; + current = & ( * current )->Next; idx--; } - return *rcast( Code*, current ); + return rcast( Code*, current); } - -bool AST::has_entries() +forceinline +bool code_is_valid(Code self) { - return NumEntries; + GEN_ASSERT(self); + return self != nullptr && self->Type != CT_Invalid; } - -char const* AST::type_str() +forceinline +bool code_has_entries(AST* self) { - return ECode::to_str( Type ); + GEN_ASSERT(self); + return self->NumEntries > 0; } - -AST::operator Code() +forceinline +void code_set_global(Code self) { - return { this }; -} + if ( self == nullptr ) + { + log_failure("Code::set_global: Cannot set code as global, AST is null!"); + return; + } -Code& Code::operator++() + self->Parent = Code_Global; +} +#if GEN_COMPILER_CPP +forceinline +Code& Code::operator ++() { if ( ast ) - ast = ast->Next; + ast = ast->Next.ast; - return *this; + return * this; } - -void CodeClass::add_interface( CodeType type ) +#endif +forceinline +Str code_type_str(Code self) { - CodeType possible_slot = ast->ParentType; - if ( possible_slot.ast ) + GEN_ASSERT(self != nullptr); + return codetype_to_str( self->Type ); +} +#pragma endregion Code + +#pragma region CodeBody +inline +void body_append( CodeBody self, Code other ) +{ + GEN_ASSERT(self); + GEN_ASSERT(other); + + if (code_is_body(other)) { + body_append_body( self, cast(CodeBody, other) ); + return; + } + + code_append( cast(Code, self), other ); +} +inline +void body_append_body( CodeBody self, CodeBody body ) +{ + GEN_ASSERT(self); + GEN_ASSERT(body); + GEN_ASSERT_MSG(self != body, "Attempted to append body to itself."); + + for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); entry = next_CodeBody(body, entry) ) { + body_append( self, entry ); + } +} +inline +Code begin_CodeBody( CodeBody body) { + GEN_ASSERT(body); + if ( body != nullptr ) + return body->Front; + + return NullCode; +} +forceinline +Code end_CodeBody(CodeBody body ){ + GEN_ASSERT(body); + return body->Back->Next; +} +inline +Code next_CodeBody(CodeBody body, Code entry) { + GEN_ASSERT(body); + GEN_ASSERT(entry); + return entry->Next; +} +#pragma endregion CodeBody + +#pragma region CodeClass +inline +void class_add_interface( CodeClass self, CodeTypename type ) +{ + GEN_ASSERT(self); + GEN_ASSERT(type); + CodeTypename possible_slot = self->ParentType; + if ( possible_slot != nullptr ) { // 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. } - while ( possible_slot.ast != nullptr ) + while ( possible_slot != nullptr ) { - possible_slot.ast = ( AST_Type* )possible_slot->Next.ast; + possible_slot = cast(CodeTypename, possible_slot->Next); } - possible_slot.ast = type.ast; + possible_slot = type; } +#pragma endregion CodeClass -void CodeParam::append( CodeParam other ) +#pragma region CodeParams +inline +void params_append( CodeParams appendee, CodeParams other ) { - AST* self = ( AST* )ast; - AST* entry = ( AST* )other.ast; + GEN_ASSERT(appendee); + GEN_ASSERT(other); + GEN_ASSERT_MSG(appendee != other, "Attempted to append parameter to itself."); + Code self = cast(Code, appendee); + Code entry = cast(Code, other); - if ( entry->Parent ) - entry = entry->duplicate(); + if ( entry->Parent != nullptr ) + entry = code_duplicate( entry ); entry->Parent = self; @@ -5408,2809 +8333,1019 @@ void CodeParam::append( CodeParam other ) self->Last = entry; self->NumEntries++; } - -CodeParam CodeParam::get( s32 idx ) +inline +CodeParams params_get(CodeParams self, s32 idx ) { - CodeParam param = *this; + GEN_ASSERT(self); + CodeParams param = self; do { - if ( ! ++param ) - return { nullptr }; + if ( ++ param != nullptr ) + return NullCode; - return { ( AST_Param* )param.raw()->Next }; - } while ( --idx ); + param = cast(CodeParams, cast(Code, param)->Next); + } + while ( --idx ); - return { nullptr }; + return param; } - -bool CodeParam::has_entries() +forceinline +bool params_has_entries(CodeParams self) { - return ast->NumEntries > 0; + GEN_ASSERT(self); + return self->NumEntries > 0; } - -CodeParam& CodeParam::operator++() +#if GEN_COMPILER_CPP +forceinline +CodeParams& CodeParams::operator ++() { - ast = ast->Next.ast; - return *this; + * this = ast->Next; + return * this; } - -void CodeStruct::add_interface( CodeType type ) +#endif +forceinline +CodeParams begin_CodeParams(CodeParams params) { - CodeType possible_slot = ast->ParentType; - if ( possible_slot.ast ) + if ( params != nullptr ) + return params; + + return NullCode; +} +forceinline +CodeParams end_CodeParams(CodeParams params) +{ + // return { (AST_Params*) rcast( AST*, ast)->Last }; + return NullCode; +} +forceinline +CodeParams next_CodeParams(CodeParams params, CodeParams param_iter) +{ + GEN_ASSERT(param_iter); + return param_iter->Next; +} +#pragma endregion CodeParams + +#pragma region CodeSpecifiers +inline +bool specifiers_append(CodeSpecifiers self, Specifier spec ) +{ + if ( self == nullptr ) + { + log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!"); + return false; + } + if ( self->NumEntries == AST_ArrSpecs_Cap ) + { + log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST_ArrSpecs_Cap ); + return false; + } + + self->ArrSpecs[ self->NumEntries ] = spec; + self->NumEntries++; + return true; +} +inline +s32 specifiers_has(CodeSpecifiers self, Specifier spec) +{ + GEN_ASSERT(self != nullptr); + for ( s32 idx = 0; idx < self->NumEntries; idx++ ) { + if ( self->ArrSpecs[ idx ] == spec ) + return idx; + } + return -1; +} +inline +s32 specifiers_remove( CodeSpecifiers self, Specifier to_remove ) +{ + if ( self == nullptr ) + { + log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!"); + return -1; + } + if ( self->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 < self->NumEntries; ++ curr, ++ next) + { + Specifier spec = self->ArrSpecs[next]; + if (spec == to_remove) + { + result = next; + + next ++; + if (next >= self->NumEntries) + break; + + spec = self->ArrSpecs[next]; + } + + self->ArrSpecs[ curr ] = spec; + } + + if (result > -1) { + self->NumEntries --; + } + return result; +} +forceinline +Specifier* begin_CodeSpecifiers(CodeSpecifiers self) +{ + if ( self != nullptr ) + return & self->ArrSpecs[0]; + + return nullptr; +} +forceinline +Specifier* end_CodeSpecifiers(CodeSpecifiers self) +{ + return self->ArrSpecs + self->NumEntries; +} +forceinline +Specifier* next_CodeSpecifiers(CodeSpecifiers self, Specifier* spec_iter) +{ + return spec_iter + 1; +} +#pragma endregion CodeSpecifiers + +#pragma region CodeStruct +inline +void struct_add_interface(CodeStruct self, CodeTypename type ) +{ + CodeTypename possible_slot = self->ParentType; + if ( possible_slot != nullptr ) { // 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. } - while ( possible_slot.ast != nullptr ) + while ( possible_slot != nullptr ) { - possible_slot.ast = ( AST_Type* )possible_slot->Next.ast; + possible_slot = cast(CodeTypename, possible_slot->Next); } - possible_slot.ast = type.ast; + possible_slot = type; } +#pragma endregion Code -CodeBody def_body( CodeT type ) +#pragma region Interface +inline +CodeBody def_body( CodeType type ) { switch ( type ) { - using namespace ECode; - case Class_Body : - case Enum_Body : - case Export_Body : - case Extern_Linkage : - case Function_Body : - case Global_Body : - case Namespace_Body : - case Struct_Body : - case Union_Body : + case CT_Class_Body: + case CT_Enum_Body: + case CT_Export_Body: + case CT_Extern_Linkage: + case CT_Function_Body: + case CT_Global_Body: + case CT_Namespace_Body: + case CT_Struct_Body: + case CT_Union_Body: break; - default : - log_failure( "def_body: Invalid type %s", ( char const* )ECode::to_str( type ) ); - return ( CodeBody )Code::Invalid; + default: + log_failure( "def_body: Invalid type %s", codetype_to_str(type).Ptr ); + return (CodeBody)Code_Invalid; } - Code result = make_code(); + Code + result = make_code(); result->Type = type; - return ( CodeBody )result; + return (CodeBody)result; } -StrC token_fmt_impl( sw num, ... ) +inline +Str token_fmt_impl( ssize num, ... ) { - local_persist thread_local char buf[ GEN_PRINTF_MAXLEN ] = { 0 }; + local_persist thread_local + char buf[GEN_PRINTF_MAXLEN] = { 0 }; mem_set( buf, 0, GEN_PRINTF_MAXLEN ); va_list va; - va_start( va, num ); - sw result = token_fmt_va( buf, GEN_PRINTF_MAXLEN, num, va ); - va_end( va ); + va_start(va, num ); + ssize result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va); + va_end(va); - return { result, buf }; + Str str = { buf, result }; + return str; } - +#pragma endregion Interface #pragma region generated code inline implementation -char const* Code::debug_str() +inline Code& Code::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code Code::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool Code::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool Code::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void Code::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; -} - -String Code::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -Code& Code::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool Code::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool Code::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -Code::operator bool() +inline Code::operator bool() { return ast != nullptr; } -char const* CodeBody::debug_str() +inline CodeBody& CodeBody::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeBody::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeBody::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeBody::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeBody::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; -} - -String CodeBody::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeBody& CodeBody::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeBody::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeBody::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeBody::operator bool() +inline CodeBody::operator bool() { return ast != nullptr; } -char const* CodeAttributes::debug_str() +inline CodeAttributes& CodeAttributes::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeAttributes::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeAttributes::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeAttributes::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeAttributes::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; -} - -String CodeAttributes::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeAttributes& CodeAttributes::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeAttributes::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeAttributes::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeAttributes::operator bool() +inline CodeAttributes::operator bool() { return ast != nullptr; } -AST* CodeAttributes::raw() -{ - return rcast( AST*, ast ); -} - -CodeAttributes::operator Code() +inline CodeAttributes::operator Code() { return *rcast( Code*, this ); } -AST_Attributes* CodeAttributes::operator->() +inline AST_Attributes* CodeAttributes::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeComment::debug_str() +inline CodeComment& CodeComment::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeComment::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeComment::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeComment::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeComment::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; -} - -String CodeComment::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeComment& CodeComment::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeComment::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeComment::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeComment::operator bool() +inline CodeComment::operator bool() { return ast != nullptr; } -AST* CodeComment::raw() -{ - return rcast( AST*, ast ); -} - -CodeComment::operator Code() +inline CodeComment::operator Code() { return *rcast( Code*, this ); } -AST_Comment* CodeComment::operator->() +inline AST_Comment* CodeComment::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeConstructor::debug_str() +inline CodeConstructor& CodeConstructor::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeConstructor::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeConstructor::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeConstructor::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeConstructor::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; -} - -String CodeConstructor::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeConstructor& CodeConstructor::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeConstructor::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeConstructor::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeConstructor::operator bool() +inline CodeConstructor::operator bool() { return ast != nullptr; } -AST* CodeConstructor::raw() -{ - return rcast( AST*, ast ); -} - -CodeConstructor::operator Code() +inline CodeConstructor::operator Code() { return *rcast( Code*, this ); } -AST_Constructor* CodeConstructor::operator->() +inline AST_Constructor* CodeConstructor::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeClass::debug_str() +inline CodeClass& CodeClass::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeClass::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeClass::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeClass::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeClass::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; -} - -String CodeClass::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeClass& CodeClass::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeClass::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeClass::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeClass::operator bool() +inline CodeClass::operator bool() { return ast != nullptr; } -char const* CodeDefine::debug_str() +inline CodeDefine& CodeDefine::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeDefine::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeDefine::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeDefine::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeDefine::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; -} - -String CodeDefine::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeDefine& CodeDefine::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeDefine::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeDefine::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeDefine::operator bool() +inline CodeDefine::operator bool() { return ast != nullptr; } -AST* CodeDefine::raw() -{ - return rcast( AST*, ast ); -} - -CodeDefine::operator Code() +inline CodeDefine::operator Code() { return *rcast( Code*, this ); } -AST_Define* CodeDefine::operator->() +inline AST_Define* CodeDefine::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeDestructor::debug_str() +inline CodeDestructor& CodeDestructor::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeDestructor::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeDestructor::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeDestructor::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeDestructor::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; -} - -String CodeDestructor::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeDestructor& CodeDestructor::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeDestructor::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeDestructor::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeDestructor::operator bool() +inline CodeDestructor::operator bool() { return ast != nullptr; } -AST* CodeDestructor::raw() -{ - return rcast( AST*, ast ); -} - -CodeDestructor::operator Code() +inline CodeDestructor::operator Code() { return *rcast( Code*, this ); } -AST_Destructor* CodeDestructor::operator->() +inline AST_Destructor* CodeDestructor::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeEnum::debug_str() +inline CodeEnum& CodeEnum::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeEnum::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeEnum::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeEnum::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeEnum::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; -} - -String CodeEnum::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeEnum& CodeEnum::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeEnum::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeEnum::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeEnum::operator bool() +inline CodeEnum::operator bool() { return ast != nullptr; } -AST* CodeEnum::raw() -{ - return rcast( AST*, ast ); -} - -CodeEnum::operator Code() +inline CodeEnum::operator Code() { return *rcast( Code*, this ); } -AST_Enum* CodeEnum::operator->() +inline AST_Enum* CodeEnum::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeExec::debug_str() +inline CodeExec& CodeExec::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeExec::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeExec::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeExec::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeExec::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; -} - -String CodeExec::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeExec& CodeExec::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeExec::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeExec::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeExec::operator bool() +inline CodeExec::operator bool() { return ast != nullptr; } -AST* CodeExec::raw() -{ - return rcast( AST*, ast ); -} - -CodeExec::operator Code() +inline CodeExec::operator Code() { return *rcast( Code*, this ); } -AST_Exec* CodeExec::operator->() +inline AST_Exec* CodeExec::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeExtern::debug_str() +inline CodeExtern& CodeExtern::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeExtern::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeExtern::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeExtern::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeExtern::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; -} - -String CodeExtern::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeExtern& CodeExtern::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeExtern::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeExtern::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeExtern::operator bool() +inline CodeExtern::operator bool() { return ast != nullptr; } -AST* CodeExtern::raw() -{ - return rcast( AST*, ast ); -} - -CodeExtern::operator Code() +inline CodeExtern::operator Code() { return *rcast( Code*, this ); } -AST_Extern* CodeExtern::operator->() +inline AST_Extern* CodeExtern::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeFriend::debug_str() +inline CodeFriend& CodeFriend::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeFriend::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeFriend::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeFriend::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeFriend::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; -} - -String CodeFriend::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeFriend& CodeFriend::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeFriend::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeFriend::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeFriend::operator bool() +inline CodeFriend::operator bool() { return ast != nullptr; } -AST* CodeFriend::raw() -{ - return rcast( AST*, ast ); -} - -CodeFriend::operator Code() +inline CodeFriend::operator Code() { return *rcast( Code*, this ); } -AST_Friend* CodeFriend::operator->() +inline AST_Friend* CodeFriend::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeFn::debug_str() +inline CodeFn& CodeFn::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeFn::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeFn::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeFn::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeFn::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; -} - -String CodeFn::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeFn& CodeFn::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeFn::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeFn::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeFn::operator bool() +inline CodeFn::operator bool() { return ast != nullptr; } -AST* CodeFn::raw() -{ - return rcast( AST*, ast ); -} - -CodeFn::operator Code() +inline CodeFn::operator Code() { return *rcast( Code*, this ); } -AST_Fn* CodeFn::operator->() +inline AST_Fn* CodeFn::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeInclude::debug_str() +inline CodeInclude& CodeInclude::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeInclude::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeInclude::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeInclude::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeInclude::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; -} - -String CodeInclude::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeInclude& CodeInclude::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeInclude::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeInclude::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeInclude::operator bool() +inline CodeInclude::operator bool() { return ast != nullptr; } -AST* CodeInclude::raw() -{ - return rcast( AST*, ast ); -} - -CodeInclude::operator Code() +inline CodeInclude::operator Code() { return *rcast( Code*, this ); } -AST_Include* CodeInclude::operator->() +inline AST_Include* CodeInclude::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeModule::debug_str() +inline CodeModule& CodeModule::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeModule::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeModule::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeModule::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeModule::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; -} - -String CodeModule::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeModule& CodeModule::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeModule::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeModule::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeModule::operator bool() +inline CodeModule::operator bool() { return ast != nullptr; } -AST* CodeModule::raw() -{ - return rcast( AST*, ast ); -} - -CodeModule::operator Code() +inline CodeModule::operator Code() { return *rcast( Code*, this ); } -AST_Module* CodeModule::operator->() +inline AST_Module* CodeModule::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeNS::debug_str() +inline CodeNS& CodeNS::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeNS::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeNS::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeNS::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeNS::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; -} - -String CodeNS::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeNS& CodeNS::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeNS::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeNS::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeNS::operator bool() +inline CodeNS::operator bool() { return ast != nullptr; } -AST* CodeNS::raw() -{ - return rcast( AST*, ast ); -} - -CodeNS::operator Code() +inline CodeNS::operator Code() { return *rcast( Code*, this ); } -AST_NS* CodeNS::operator->() +inline AST_NS* CodeNS::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeOperator::debug_str() +inline CodeOperator& CodeOperator::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeOperator::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeOperator::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeOperator::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeOperator::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; -} - -String CodeOperator::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeOperator& CodeOperator::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeOperator::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeOperator::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeOperator::operator bool() +inline CodeOperator::operator bool() { return ast != nullptr; } -AST* CodeOperator::raw() -{ - return rcast( AST*, ast ); -} - -CodeOperator::operator Code() +inline CodeOperator::operator Code() { return *rcast( Code*, this ); } -AST_Operator* CodeOperator::operator->() +inline AST_Operator* CodeOperator::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeOpCast::debug_str() +inline CodeOpCast& CodeOpCast::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeOpCast::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeOpCast::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeOpCast::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeOpCast::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; -} - -String CodeOpCast::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeOpCast& CodeOpCast::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeOpCast::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeOpCast::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeOpCast::operator bool() +inline CodeOpCast::operator bool() { return ast != nullptr; } -AST* CodeOpCast::raw() -{ - return rcast( AST*, ast ); -} - -CodeOpCast::operator Code() +inline CodeOpCast::operator Code() { return *rcast( Code*, this ); } -AST_OpCast* CodeOpCast::operator->() +inline AST_OpCast* CodeOpCast::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeParam::debug_str() +inline CodeParams& CodeParams::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeParam::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeParam::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeParam::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeParam::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; -} - -String CodeParam::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeParam& CodeParam::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeParam::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeParam::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeParam::operator bool() +inline CodeParams::operator bool() { return ast != nullptr; } -char const* CodePragma::debug_str() +inline CodePragma& CodePragma::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodePragma::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodePragma::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodePragma::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodePragma::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; -} - -String CodePragma::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodePragma& CodePragma::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodePragma::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodePragma::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodePragma::operator bool() +inline CodePragma::operator bool() { return ast != nullptr; } -AST* CodePragma::raw() -{ - return rcast( AST*, ast ); -} - -CodePragma::operator Code() +inline CodePragma::operator Code() { return *rcast( Code*, this ); } -AST_Pragma* CodePragma::operator->() +inline AST_Pragma* CodePragma::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodePreprocessCond::debug_str() +inline CodePreprocessCond& CodePreprocessCond::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodePreprocessCond::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodePreprocessCond::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodePreprocessCond::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodePreprocessCond::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; -} - -String CodePreprocessCond::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodePreprocessCond& CodePreprocessCond::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodePreprocessCond::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodePreprocessCond::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodePreprocessCond::operator bool() +inline CodePreprocessCond::operator bool() { return ast != nullptr; } -AST* CodePreprocessCond::raw() -{ - return rcast( AST*, ast ); -} - -CodePreprocessCond::operator Code() +inline CodePreprocessCond::operator Code() { return *rcast( Code*, this ); } -AST_PreprocessCond* CodePreprocessCond::operator->() +inline AST_PreprocessCond* CodePreprocessCond::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeSpecifiers::debug_str() +inline CodeSpecifiers& CodeSpecifiers::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeSpecifiers::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeSpecifiers::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeSpecifiers::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeSpecifiers::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; -} - -String CodeSpecifiers::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeSpecifiers& CodeSpecifiers::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeSpecifiers::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeSpecifiers::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeSpecifiers::operator bool() +inline CodeSpecifiers::operator bool() { return ast != nullptr; } -char const* CodeStruct::debug_str() +inline CodeStruct& CodeStruct::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeStruct::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeStruct::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeStruct::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeStruct::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; -} - -String CodeStruct::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeStruct& CodeStruct::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeStruct::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeStruct::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeStruct::operator bool() +inline CodeStruct::operator bool() { return ast != nullptr; } -char const* CodeTemplate::debug_str() +inline CodeTemplate& CodeTemplate::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeTemplate::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeTemplate::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeTemplate::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeTemplate::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; -} - -String CodeTemplate::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeTemplate& CodeTemplate::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeTemplate::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeTemplate::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeTemplate::operator bool() +inline CodeTemplate::operator bool() { return ast != nullptr; } -AST* CodeTemplate::raw() -{ - return rcast( AST*, ast ); -} - -CodeTemplate::operator Code() +inline CodeTemplate::operator Code() { return *rcast( Code*, this ); } -AST_Template* CodeTemplate::operator->() +inline AST_Template* CodeTemplate::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeType::debug_str() +inline CodeTypename& CodeTypename::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeType::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeType::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeType::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeType::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; -} - -String CodeType::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeType& CodeType::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeType::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeType::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeType::operator bool() +inline CodeTypename::operator bool() { return ast != nullptr; } -AST* CodeType::raw() -{ - return rcast( AST*, ast ); -} - -CodeType::operator Code() +inline CodeTypename::operator Code() { return *rcast( Code*, this ); } -AST_Type* CodeType::operator->() +inline AST_Typename* CodeTypename::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeTypedef::debug_str() +inline CodeTypedef& CodeTypedef::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeTypedef::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeTypedef::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeTypedef::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeTypedef::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; -} - -String CodeTypedef::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeTypedef& CodeTypedef::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeTypedef::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeTypedef::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeTypedef::operator bool() +inline CodeTypedef::operator bool() { return ast != nullptr; } -AST* CodeTypedef::raw() -{ - return rcast( AST*, ast ); -} - -CodeTypedef::operator Code() +inline CodeTypedef::operator Code() { return *rcast( Code*, this ); } -AST_Typedef* CodeTypedef::operator->() +inline AST_Typedef* CodeTypedef::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeUnion::debug_str() +inline CodeUnion& CodeUnion::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeUnion::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeUnion::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeUnion::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeUnion::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; -} - -String CodeUnion::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeUnion& CodeUnion::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeUnion::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeUnion::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeUnion::operator bool() +inline CodeUnion::operator bool() { return ast != nullptr; } -AST* CodeUnion::raw() -{ - return rcast( AST*, ast ); -} - -CodeUnion::operator Code() +inline CodeUnion::operator Code() { return *rcast( Code*, this ); } -AST_Union* CodeUnion::operator->() +inline AST_Union* CodeUnion::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeUsing::debug_str() +inline CodeUsing& CodeUsing::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeUsing::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeUsing::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeUsing::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeUsing::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; -} - -String CodeUsing::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeUsing& CodeUsing::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeUsing::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeUsing::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeUsing::operator bool() +inline CodeUsing::operator bool() { return ast != nullptr; } -AST* CodeUsing::raw() -{ - return rcast( AST*, ast ); -} - -CodeUsing::operator Code() +inline CodeUsing::operator Code() { return *rcast( Code*, this ); } -AST_Using* CodeUsing::operator->() +inline AST_Using* CodeUsing::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; } -char const* CodeVar::debug_str() +inline CodeVar& CodeVar::operator=( Code other ) { - if ( ast == nullptr ) - return "Code::debug_str: AST is null!"; - return rcast( AST*, ast )->debug_str(); -} - -Code CodeVar::duplicate() -{ - if ( ast == nullptr ) + if ( other.ast != nullptr && other->Parent != nullptr ) { - log_failure( "Code::duplicate: Cannot duplicate code, AST is null!" ); - return Code::Invalid; - } - return { rcast( AST*, ast )->duplicate() }; -} - -bool CodeVar::is_equal( Code other ) -{ - if ( ast == nullptr || other.ast == nullptr ) - { - log_failure( "Code::is_equal: Cannot compare code, AST is null!" ); - return false; - } - return rcast( AST*, ast )->is_equal( other.ast ); -} - -bool CodeVar::is_valid() -{ - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; -} - -void CodeVar::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; -} - -String CodeVar::to_string() -{ - if ( ast == nullptr ) - { - log_failure( "Code::to_string: Cannot convert code to string, AST is null!" ); - return { nullptr }; - } - return rcast( AST*, ast )->to_string(); -} - -CodeVar& CodeVar::operator=( Code other ) -{ - if ( other.ast && other->Parent ) - { - ast = rcast( decltype( ast ), other.ast->duplicate() ); - rcast( AST*, ast )->Parent = nullptr; + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; } ast = rcast( decltype( ast ), other.ast ); return *this; } -bool CodeVar::operator==( Code other ) -{ - return ( AST* )ast == other.ast; -} - -bool CodeVar::operator!=( Code other ) -{ - return ( AST* )ast != other.ast; -} - -CodeVar::operator bool() +inline CodeVar::operator bool() { return ast != nullptr; } -AST* CodeVar::raw() -{ - return rcast( AST*, ast ); -} - -CodeVar::operator Code() +inline CodeVar::operator Code() { return *rcast( Code*, this ); } -AST_Var* CodeVar::operator->() +inline AST_Var* CodeVar::operator->() { if ( ast == nullptr ) { - log_failure( "Attempt to dereference a nullptr!" ); + log_failure( "Attempt to dereference a nullptr!\n" ); return nullptr; } return ast; @@ -8219,339 +9354,156 @@ AST_Var* CodeVar::operator->() #pragma endregion generated code inline implementation #pragma region generated AST/Code cast implementation +GEN_OPTIMIZE_MAPPINGS_BEGIN -AST::operator CodeBody() +forceinline Code::operator CodeBody() const { - return { rcast( AST_Body*, this ) }; + return { (AST_Body*)ast }; } -Code::operator CodeBody() const +forceinline Code::operator CodeAttributes() const { - return { ( AST_Body* )ast }; + return { (AST_Attributes*)ast }; } -AST::operator CodeAttributes() +forceinline Code::operator CodeComment() const { - return { rcast( AST_Attributes*, this ) }; + return { (AST_Comment*)ast }; } -Code::operator CodeAttributes() const +forceinline Code::operator CodeConstructor() const { - return { ( AST_Attributes* )ast }; + return { (AST_Constructor*)ast }; } -AST::operator CodeComment() +forceinline Code::operator CodeClass() const { - return { rcast( AST_Comment*, this ) }; + return { (AST_Class*)ast }; } -Code::operator CodeComment() const +forceinline Code::operator CodeDefine() const { - return { ( AST_Comment* )ast }; + return { (AST_Define*)ast }; } -AST::operator CodeConstructor() +forceinline Code::operator CodeDestructor() const { - return { rcast( AST_Constructor*, this ) }; + return { (AST_Destructor*)ast }; } -Code::operator CodeConstructor() const +forceinline Code::operator CodeEnum() const { - return { ( AST_Constructor* )ast }; + return { (AST_Enum*)ast }; } -AST::operator CodeClass() +forceinline Code::operator CodeExec() const { - return { rcast( AST_Class*, this ) }; + return { (AST_Exec*)ast }; } -Code::operator CodeClass() const +forceinline Code::operator CodeExtern() const { - return { ( AST_Class* )ast }; + return { (AST_Extern*)ast }; } -AST::operator CodeDefine() +forceinline Code::operator CodeFriend() const { - return { rcast( AST_Define*, this ) }; + return { (AST_Friend*)ast }; } -Code::operator CodeDefine() const +forceinline Code::operator CodeFn() const { - return { ( AST_Define* )ast }; + return { (AST_Fn*)ast }; } -AST::operator CodeDestructor() +forceinline Code::operator CodeInclude() const { - return { rcast( AST_Destructor*, this ) }; + return { (AST_Include*)ast }; } -Code::operator CodeDestructor() const +forceinline Code::operator CodeModule() const { - return { ( AST_Destructor* )ast }; + return { (AST_Module*)ast }; } -AST::operator CodeEnum() +forceinline Code::operator CodeNS() const { - return { rcast( AST_Enum*, this ) }; + return { (AST_NS*)ast }; } -Code::operator CodeEnum() const +forceinline Code::operator CodeOperator() const { - return { ( AST_Enum* )ast }; + return { (AST_Operator*)ast }; } -AST::operator CodeExec() +forceinline Code::operator CodeOpCast() const { - return { rcast( AST_Exec*, this ) }; + return { (AST_OpCast*)ast }; } -Code::operator CodeExec() const +forceinline Code::operator CodeParams() const { - return { ( AST_Exec* )ast }; + return { (AST_Params*)ast }; } -AST::operator CodeExtern() +forceinline Code::operator CodePragma() const { - return { rcast( AST_Extern*, this ) }; + return { (AST_Pragma*)ast }; } -Code::operator CodeExtern() const +forceinline Code::operator CodePreprocessCond() const { - return { ( AST_Extern* )ast }; + return { (AST_PreprocessCond*)ast }; } -AST::operator CodeFriend() +forceinline Code::operator CodeSpecifiers() const { - return { rcast( AST_Friend*, this ) }; + return { (AST_Specifiers*)ast }; } -Code::operator CodeFriend() const +forceinline Code::operator CodeStruct() const { - return { ( AST_Friend* )ast }; + return { (AST_Struct*)ast }; } -AST::operator CodeFn() +forceinline Code::operator CodeTemplate() const { - return { rcast( AST_Fn*, this ) }; + return { (AST_Template*)ast }; } -Code::operator CodeFn() const +forceinline Code::operator CodeTypename() const { - return { ( AST_Fn* )ast }; + return { (AST_Typename*)ast }; } -AST::operator CodeInclude() +forceinline Code::operator CodeTypedef() const { - return { rcast( AST_Include*, this ) }; + return { (AST_Typedef*)ast }; } -Code::operator CodeInclude() const +forceinline Code::operator CodeUnion() const { - return { ( AST_Include* )ast }; + return { (AST_Union*)ast }; } -AST::operator CodeModule() +forceinline Code::operator CodeUsing() const { - return { rcast( AST_Module*, this ) }; + return { (AST_Using*)ast }; } -Code::operator CodeModule() const +forceinline Code::operator CodeVar() const { - return { ( AST_Module* )ast }; -} - -AST::operator CodeNS() -{ - return { rcast( AST_NS*, this ) }; -} - -Code::operator CodeNS() const -{ - return { ( AST_NS* )ast }; -} - -AST::operator CodeOperator() -{ - return { rcast( AST_Operator*, this ) }; -} - -Code::operator CodeOperator() const -{ - return { ( AST_Operator* )ast }; -} - -AST::operator CodeOpCast() -{ - return { rcast( AST_OpCast*, this ) }; -} - -Code::operator CodeOpCast() const -{ - return { ( AST_OpCast* )ast }; -} - -AST::operator CodeParam() -{ - return { rcast( AST_Param*, this ) }; -} - -Code::operator CodeParam() const -{ - return { ( AST_Param* )ast }; -} - -AST::operator CodePragma() -{ - return { rcast( AST_Pragma*, this ) }; -} - -Code::operator CodePragma() const -{ - return { ( AST_Pragma* )ast }; -} - -AST::operator CodePreprocessCond() -{ - return { rcast( AST_PreprocessCond*, this ) }; -} - -Code::operator CodePreprocessCond() const -{ - return { ( AST_PreprocessCond* )ast }; -} - -AST::operator CodeSpecifiers() -{ - return { rcast( AST_Specifiers*, this ) }; -} - -Code::operator CodeSpecifiers() const -{ - return { ( AST_Specifiers* )ast }; -} - -AST::operator CodeStruct() -{ - return { rcast( AST_Struct*, this ) }; -} - -Code::operator CodeStruct() const -{ - return { ( AST_Struct* )ast }; -} - -AST::operator CodeTemplate() -{ - return { rcast( AST_Template*, this ) }; -} - -Code::operator CodeTemplate() const -{ - return { ( AST_Template* )ast }; -} - -AST::operator CodeType() -{ - return { rcast( AST_Type*, this ) }; -} - -Code::operator CodeType() const -{ - return { ( AST_Type* )ast }; -} - -AST::operator CodeTypedef() -{ - return { rcast( AST_Typedef*, this ) }; -} - -Code::operator CodeTypedef() const -{ - return { ( AST_Typedef* )ast }; -} - -AST::operator CodeUnion() -{ - return { rcast( AST_Union*, this ) }; -} - -Code::operator CodeUnion() const -{ - return { ( AST_Union* )ast }; -} - -AST::operator CodeUsing() -{ - return { rcast( AST_Using*, this ) }; -} - -Code::operator CodeUsing() const -{ - return { ( AST_Using* )ast }; -} - -AST::operator CodeVar() -{ - return { rcast( AST_Var*, this ) }; -} - -Code::operator CodeVar() const -{ - return { ( AST_Var* )ast }; + return { (AST_Var*)ast }; } +GEN_OPITMIZE_MAPPINGS_END #pragma endregion generated AST / Code cast implementation #pragma endregion Inlines #pragma region Constants -#ifndef GEN_GLOBAL_BUCKET_SIZE -#define GEN_GLOBAL_BUCKET_SIZE megabytes( 4 ) -#endif -#ifndef GEN_CODEPOOL_NUM_BLOCKS -#define GEN_CODEPOOL_NUM_BLOCKS kilobytes( 16 ) -#endif -#ifndef GEN_SIZE_PER_STRING_ARENA -#define GEN_SIZE_PER_STRING_ARENA megabytes( 1 ) -#endif -#ifndef GEN_MAX_COMMENT_LINE_LENGTH -#define GEN_MAX_COMMENT_LINE_LENGTH 1024 -#endif -#ifndef GEN_MAX_NAME_LENGTH -#define GEN_MAX_NAME_LENGTH 128 -#endif -#ifndef GEN_MAX_UNTYPED_STR_LENGTH -#define GEN_MAX_UNTYPED_STR_LENGTH megabytes( 1 ) -#endif -#ifndef GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE -#define GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE kilobytes( 4 ) -#endif -#ifndef GEN_LEX_ALLOCATOR_SIZE -#define GEN_LEX_ALLOCATOR_SIZE megabytes( 4 ) -#endif -#ifndef GEN_BUILDER_STR_BUFFER_RESERVE -#define GEN_BUILDER_STR_BUFFER_RESERVE megabytes( 1 ) -#endif - -// These constexprs are used for allocation behavior of data structures -// or string handling while constructing or serializing. -// Change them to suit your needs. - -constexpr s32 InitSize_DataArrays = 16; - -// NOTE: This limits the maximum size of an allocation -// If you are generating a string larger than this, increase the size of the bucket here. -constexpr uw Global_BucketSize = GEN_GLOBAL_BUCKET_SIZE; -constexpr s32 CodePool_NumBlocks = GEN_CODEPOOL_NUM_BLOCKS; -constexpr s32 SizePer_StringArena = GEN_SIZE_PER_STRING_ARENA; - -constexpr s32 MaxCommentLineLength = GEN_MAX_COMMENT_LINE_LENGTH; -constexpr s32 MaxNameLength = GEN_MAX_NAME_LENGTH; -constexpr s32 MaxUntypedStrLength = GEN_MAX_UNTYPED_STR_LENGTH; -constexpr s32 TokenFmt_TokenMap_MemSize = GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE; -constexpr s32 LexAllocator_Size = GEN_LEX_ALLOCATOR_SIZE; -constexpr s32 Builder_StrBufferReserve = GEN_BUILDER_STR_BUFFER_RESERVE; +extern Str enum_underlying_sig; extern Code access_public; extern Code access_protected; @@ -8563,12 +9515,11 @@ extern CodeAttributes attrib_api_import; extern Code module_global_fragment; extern Code module_private_fragment; -// Exposed, but this is really used for parsing. extern Code fmt_newline; extern CodePragma pragma_once; -extern CodeParam param_varadic; +extern CodeParams param_varadic; extern CodePreprocessCond preprocess_else; extern CodePreprocessCond preprocess_endif; @@ -8598,209 +9549,223 @@ extern CodeSpecifiers spec_thread_local; extern CodeSpecifiers spec_virtual; extern CodeSpecifiers spec_volatile; -extern CodeType t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance) -extern CodeType t_auto; -extern CodeType t_void; -extern CodeType t_int; -extern CodeType t_bool; -extern CodeType t_char; -extern CodeType t_wchar_t; -extern CodeType t_class; -extern CodeType t_typename; +extern CodeTypename t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance) +extern CodeTypename t_auto; +extern CodeTypename t_void; +extern CodeTypename t_int; +extern CodeTypename t_bool; +extern CodeTypename t_char; +extern CodeTypename t_wchar_t; +extern CodeTypename t_class; +extern CodeTypename t_typename; #ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS -// Predefined typename codes. Are set to readonly and are setup during gen::init() + // Predefined typename codes. Are set to readonly and are setup during gen::init() + extern Context* _ctx; -extern CodeType t_b32; + extern CodeTypename t_b32; -extern CodeType t_s8; -extern CodeType t_s16; -extern CodeType t_s32; -extern CodeType t_s64; + extern CodeTypename t_s8; + extern CodeTypename t_s16; + extern CodeTypename t_s32; + extern CodeTypename t_s64; -extern CodeType t_u8; -extern CodeType t_u16; -extern CodeType t_u32; -extern CodeType t_u64; + extern CodeTypename t_u8; + extern CodeTypename t_u16; + extern CodeTypename t_u32; + extern CodeTypename t_u64; -extern CodeType t_sw; -extern CodeType t_uw; + extern CodeTypename t_ssize; + extern CodeTypename t_usize; -extern CodeType t_f32; -extern CodeType t_f64; + extern CodeTypename t_f32; + extern CodeTypename t_f64; #endif #pragma endregion Constants -#pragma region Macros - -#define gen_main main - -#define __ NoCode - -// Convienence for defining any name used with the gen api. -// Lets you provide the length and string literal to the functions without the need for the DSL. -#define name( Id_ ) \ - { \ - sizeof( stringize( Id_ ) ) - 1, stringize( Id_ ) \ - } - -// Same as name just used to indicate intention of literal for code instead of names. -#define code( ... ) \ - { \ - sizeof( stringize( __VA_ARGS__ ) ) - 1, stringize( __VA_ARGS__ ) \ - } - -#define args( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__ - -#define code_str( ... ) GEN_NS untyped_str( code( __VA_ARGS__ ) ) -#define code_fmt( ... ) GEN_NS untyped_str( token_fmt( __VA_ARGS__ ) ) - -// 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__ ) - -#pragma endregion Macros - -#ifdef GEN_EXPOSE_BACKEND - -// Global allocator used for data with process lifetime. -extern AllocatorInfo GlobalAllocator; -extern Array< Arena > Global_AllocatorBuckets; - -extern Array< Pool > CodePools; -extern Array< Arena > StringArenas; - -extern StringTable StringCache; - -extern Arena LexArena; - -extern AllocatorInfo Allocator_DataArrays; -extern AllocatorInfo Allocator_CodePool; -extern AllocatorInfo Allocator_Lexer; -extern AllocatorInfo Allocator_StringArena; -extern AllocatorInfo Allocator_StringTable; -extern AllocatorInfo Allocator_TypeTable; - -#endif - #pragma region Builder +struct Builder; +typedef struct Builder Builder; + +Builder builder_open ( char const* path ); +void builder_pad_lines ( Builder* builder, s32 num ); +void builder_print ( Builder* builder, Code code ); +void builder_print_fmt_va( Builder* builder, char const* fmt, va_list va ); +void builder_print_fmt ( Builder* builder, char const* fmt, ... ) { + va_list va; + va_start( va, fmt ); + builder_print_fmt_va( builder, fmt, va ); + va_end( va ); +} +void builder_write( Builder* builder ); + struct Builder { FileInfo File; - String Buffer; + StrBuilder Buffer; - static Builder open( char const* path ); +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP + forceinline static Builder open( char const* path ) { return builder_open(path); } - void pad_lines( s32 num ); + forceinline void pad_lines( s32 num ) { return builder_pad_lines(this, num); } - void print( Code ); - void print_fmt( char const* fmt, ... ); + forceinline void print( Code code ) { return builder_print(this, code); } + forceinline void print_fmt( char const* fmt, ... ) { + va_list va; + va_start( va, fmt ); + builder_print_fmt_va( this, fmt, va ); + va_end( va ); + } - void write(); + forceinline void write() { return builder_write(this); } +#endif }; +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +void builder_pad_lines( Builder& builder, s32 num ) { return builder_pad_lines(& builder, num); } +void builder_print ( Builder& builder, Code code ) { return builder_print(& builder, code); } +void builder_write ( Builder& builder ) { return builder_write(& builder ); } +void builder_print_fmt( Builder& builder, char const* fmt, ...) { + va_list va; + va_start( va, fmt ); + builder_print_fmt_va( & builder, fmt, va ); + va_end( va ); +} +#endif + #pragma endregion Builder + +#pragma region Scanner + +// This is a simple file reader that reads the entire file into memory. +// It has an extra option to skip the first few lines for undesired includes. +// This is done so that includes can be kept in dependency and component files so that intellisense works. +Code scan_file( char const* path ); + +CodeBody parse_file( const char* path ); + +// The follow is basic support for light csv parsing (use it as an example) +// Make something robust if its more serious. + +typedef struct CSV_Column CSV_Column; +struct CSV_Column { + CSV_Object ADT; + Array(ADT_Node) Content; +}; + +typedef struct CSV_Columns2 CSV_Columns2; +struct CSV_Columns2 { + CSV_Object ADT; + Array(ADT_Node) Col_1; + Array(ADT_Node) Col_2; +}; + +CSV_Column parse_csv_one_column(AllocatorInfo allocator, char const* path); +CSV_Columns2 parse_csv_two_columns(AllocatorInfo allocator, char const* path); + +#pragma endregion Scanner + GEN_NS_END #pragma region GENCPP IMPLEMENTATION GUARD -#if defined( GEN_IMPLEMENTATION ) && ! defined( GEN_IMPLEMENTED ) -#define GEN_IMPLEMENTED +#if defined(GEN_IMPLEMENTATION) && ! defined(GEN_IMPLEMENTED) +# define GEN_IMPLEMENTED //! 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 -GEN_NS_BEGIN - - #pragma region Macros and Includes -#include +# include // NOTE: Ensure we use standard methods for these calls if we use GEN_PICO -#if ! defined( GEN_PICO_CUSTOM_ROUTINES ) -#if ! defined( GEN_MODULE_CORE ) -#define _strlen strlen -#define _printf_err( fmt, ... ) fprintf( stderr, fmt, __VA_ARGS__ ) -#define _printf_err_va( fmt, va ) vfprintf( stderr, fmt, va ) -#else -#define _strlen str_len -#define _printf_err( fmt, ... ) str_fmt_out_err( fmt, __VA_ARGS__ ) -#define _printf_err_va( fmt, va ) str_fmt_out_err_va( fmt, va ) -#endif -#endif +# if ! defined( GEN_PICO_CUSTOM_ROUTINES ) +# if ! defined( GEN_MODULE_CORE ) +# define _strlen strlen +# define _printf_err( fmt, ... ) fprintf( stderr, fmt, __VA_ARGS__ ) +# define _printf_err_va( fmt, va ) vfprintf( stderr, fmt, va ) +# else +# define _strlen c_str_len +# define _printf_err( fmt, ... ) c_str_fmt_out_err( fmt, __VA_ARGS__ ) +# define _printf_err_va( fmt, va ) c_str_fmt_out_err_va( fmt, va ) +# endif +# endif # -#include +# include # -#if defined( GEN_SYSTEM_UNIX ) || defined( GEN_SYSTEM_MACOS ) -#include -#elif defined( GEN_SYSTEM_WINDOWS ) -#if ! defined( GEN_NO_WINDOWS_H ) -#ifndef WIN32_LEAN_AND_MEAN -#ifndef NOMINMAX -#define NOMINMAX -#endif +# if defined( GEN_SYSTEM_UNIX ) || defined( GEN_SYSTEM_MACOS ) +# include +# elif defined( GEN_SYSTEM_WINDOWS ) +# if ! defined( GEN_NO_WINDOWS_H ) +# ifndef WIN32_LEAN_AND_MEAN +# ifndef NOMINMAX +# define NOMINMAX +# endif # -#define WIN32_LEAN_AND_MEAN -#define WIN32_MEAN_AND_LEAN -#define VC_EXTRALEAN -#endif -#include -#undef NOMINMAX -#undef WIN32_LEAN_AND_MEAN -#undef WIN32_MEAN_AND_LEAN -#undef VC_EXTRALEAN -#endif -#endif +# define WIN32_LEAN_AND_MEAN +# define WIN32_MEAN_AND_LEAN +# define VC_EXTRALEAN +# endif +# include +# undef NOMINMAX +# undef WIN32_LEAN_AND_MEAN +# undef WIN32_MEAN_AND_LEAN +# undef VC_EXTRALEAN +# endif +# endif #include #ifdef GEN_SYSTEM_MACOS -#include +# include #endif #ifdef GEN_SYSTEM_CYGWIN -#include +# include #endif #if defined( GEN_SYSTEM_WINDOWS ) && ! defined( GEN_COMPILER_GCC ) -#include +# include #endif #if defined( GEN_SYSTEM_LINUX ) -#include +# include #endif #ifdef GEN_BENCHMARK // Timing includes #if defined( GEN_SYSTEM_MACOS ) || GEN_SYSTEM_UNIX -#include -#include +# include +# include #endif #if defined( GEN_SYSTEM_MACOS ) -#include -#include -#include +# include +# include +# include #endif #if defined( GEN_SYSTEM_EMSCRIPTEN ) -#include +# include #endif #if defined( GEN_SYSTEM_WINDOWS ) -#include +# include #endif #endif #pragma endregion Macros and Includes +GEN_NS_BEGIN + #pragma region Debug -void assert_handler( char const* condition, char const* file, s32 line, char const* msg, ... ) +void assert_handler( char const* condition, char const* file, char const* function, s32 line, char const* msg, ... ) { - _printf_err( "%s:(%d): Assert Failure: ", file, line ); + _printf_err( "%s - %s:(%d): Assert Failure: ", file, function, line ); if ( condition ) _printf_err( "`%s` \n", condition ); @@ -8823,24 +9788,25 @@ s32 assert_crash( char const* condition ) } #if defined( GEN_SYSTEM_WINDOWS ) -void process_exit( u32 code ) -{ - ExitProcess( code ); -} + void process_exit( u32 code ) + { + ExitProcess( code ); + } #else -#include +# include -void process_exit( u32 code ) -{ - exit( code ); -} + void process_exit( u32 code ) + { + exit( code ); + } #endif #pragma endregion Debug #pragma region String Ops -internal sw _scan_zpl_i64( const char* text, s32 base, s64* value ) +internal +ssize _scan_zpl_i64( const char* text, s32 base, s64* value ) { const char* text_begin = text; s64 result = 0; @@ -8852,7 +9818,7 @@ internal sw _scan_zpl_i64( const char* text, s32 base, s64* value ) text++; } - if ( base == 16 && str_compare( text, "0x", 2 ) == 0 ) + if ( base == 16 && c_str_compare_len( text, "0x", 2 ) == 0 ) text += 2; for ( ;; ) @@ -8882,19 +9848,19 @@ internal sw _scan_zpl_i64( const char* text, s32 base, s64* value ) // TODO : Are these good enough for characters? global const char _num_to_char_table[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "@$"; + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "@$"; -s64 str_to_i64( const char* str, char** end_ptr, s32 base ) +s64 c_str_to_i64( const char* str, char** end_ptr, s32 base ) { - sw len; + ssize len; s64 value; if ( ! base ) { - if ( ( str_len( str ) > 2 ) && ( str_compare( str, "0x", 2 ) == 0 ) ) + if ( ( c_str_len( str ) > 2 ) && ( c_str_compare_len( str, "0x", 2 ) == 0 ) ) base = 16; else base = 10; @@ -8918,7 +9884,7 @@ void i64_to_str( s64 value, char* string, s32 base ) value = -value; } - v = zpl_cast( u64 ) value; + v = scast( u64, value); if ( v != 0 ) { while ( v > 0 ) @@ -8934,7 +9900,7 @@ void i64_to_str( s64 value, char* string, s32 base ) if ( negative ) *buf++ = '-'; *buf = '\0'; - str_reverse( string ); + c_str_reverse( string ); } void u64_to_str( u64 value, char* string, s32 base ) @@ -8955,10 +9921,10 @@ void u64_to_str( u64 value, char* string, s32 base ) } *buf = '\0'; - str_reverse( string ); + c_str_reverse( string ); } -f64 str_to_f64( const char* str, char** end_ptr ) +f64 c_str_to_f64( const char* str, char** end_ptr ) { f64 result, value, sign, scale; s32 frac; @@ -9040,7 +10006,7 @@ f64 str_to_f64( const char* str, char** end_ptr ) result = sign * ( frac ? ( value / scale ) : ( value * scale ) ); if ( end_ptr ) - *end_ptr = zpl_cast( char* ) str; + * end_ptr = rcast( char*, ccast(char*, str) ); return result; } @@ -9051,30 +10017,31 @@ f64 str_to_f64( const char* str, char** end_ptr ) enum { - GEN_FMT_MINUS = bit( 0 ), - GEN_FMT_PLUS = bit( 1 ), - GEN_FMT_ALT = bit( 2 ), - GEN_FMT_SPACE = bit( 3 ), - GEN_FMT_ZERO = bit( 4 ), + GEN_FMT_MINUS = bit( 0 ), + GEN_FMT_PLUS = bit( 1 ), + GEN_FMT_ALT = bit( 2 ), + GEN_FMT_SPACE = bit( 3 ), + GEN_FMT_ZERO = bit( 4 ), - GEN_FMT_CHAR = bit( 5 ), - GEN_FMT_SHORT = bit( 6 ), - GEN_FMT_INT = bit( 7 ), - GEN_FMT_LONG = bit( 8 ), - GEN_FMT_LLONG = bit( 9 ), - GEN_FMT_SIZE = bit( 10 ), - GEN_FMT_INTPTR = bit( 11 ), + GEN_FMT_CHAR = bit( 5 ), + GEN_FMT_SHORT = bit( 6 ), + GEN_FMT_INT = bit( 7 ), + GEN_FMT_LONG = bit( 8 ), + GEN_FMT_LLONG = bit( 9 ), + GEN_FMT_SIZE = bit( 10 ), + GEN_FMT_INTPTR = bit( 11 ), GEN_FMT_UNSIGNED = bit( 12 ), GEN_FMT_LOWER = bit( 13 ), GEN_FMT_UPPER = bit( 14 ), GEN_FMT_WIDTH = bit( 15 ), - GEN_FMT_DONE = bit( 30 ), + GEN_FMT_DONE = bit( 30 ), - GEN_FMT_INTS = GEN_FMT_CHAR | GEN_FMT_SHORT | GEN_FMT_INT | GEN_FMT_LONG | GEN_FMT_LLONG | GEN_FMT_SIZE | GEN_FMT_INTPTR + GEN_FMT_INTS = GEN_FMT_CHAR | GEN_FMT_SHORT | GEN_FMT_INT | GEN_FMT_LONG | GEN_FMT_LLONG | GEN_FMT_SIZE | GEN_FMT_INTPTR }; +typedef struct _format_info _format_info; struct _format_info { s32 base; @@ -9083,15 +10050,15 @@ struct _format_info s32 precision; }; -internal sw _print_string( char* text, sw max_len, _format_info* info, char const* str ) +internal ssize _print_string( char* text, ssize max_len, _format_info* info, char const* str ) { - sw res = 0, len = 0; - sw remaining = max_len; + ssize res = 0, len = 0; + ssize remaining = max_len; char* begin = text; if ( str == NULL && max_len >= 6 ) { - res += str_copy_nulpad( text, "(null)", 6 ); + res += c_str_copy_nulpad( text, "(null)", 6 ); return res; } @@ -9099,7 +10066,7 @@ internal sw _print_string( char* text, sw max_len, _format_info* info, char cons // Made the design decision for this library that precision is the length of the string. len = info->precision; else - len = str_len( str ); + len = c_str_len( str ); if ( info && ( info->width == 0 && info->flags & GEN_FMT_WIDTH ) ) { @@ -9112,14 +10079,14 @@ internal sw _print_string( char* text, sw max_len, _format_info* info, char cons len = info->precision < len ? info->precision : len; if ( res + len > max_len ) return res; - res += str_copy_nulpad( text, str, len ); + res += c_str_copy_nulpad( text, str, len ); text += res; if ( info->width > res ) { - sw padding = info->width - len; + ssize padding = info->width - len; - char pad = ( info->flags & GEN_FMT_ZERO ) ? '0' : ' '; + char pad = ( info->flags & GEN_FMT_ZERO ) ? '0' : ' '; while ( padding-- > 0 && remaining-- > 0 ) *text++ = pad, res++; } @@ -9128,7 +10095,7 @@ internal sw _print_string( char* text, sw max_len, _format_info* info, char cons { if ( info && ( info->width > res ) ) { - sw padding = info->width - len; + ssize padding = info->width - len; char pad = ( info->flags & GEN_FMT_ZERO ) ? '0' : ' '; while ( padding-- > 0 && remaining-- > 0 ) *text++ = pad, res++; @@ -9136,30 +10103,30 @@ internal sw _print_string( char* text, sw max_len, _format_info* info, char cons if ( res + len > max_len ) return res; - res += str_copy_nulpad( text, str, len ); + res += c_str_copy_nulpad( text, str, len ); } if ( info ) { if ( info->flags & GEN_FMT_UPPER ) - str_to_upper( begin ); + c_str_to_upper( begin ); else if ( info->flags & GEN_FMT_LOWER ) - str_to_lower( begin ); + c_str_to_lower( begin ); } return res; } -internal sw _print_char( char* text, sw max_len, _format_info* info, char arg ) +internal ssize _print_char( char* text, ssize max_len, _format_info* info, char arg ) { char str[ 2 ] = ""; str[ 0 ] = arg; return _print_string( text, max_len, info, str ); } -internal sw _print_repeated_char( char* text, sw max_len, _format_info* info, char arg ) +internal ssize _print_repeated_char( char* text, ssize max_len, _format_info* info, char arg ) { - sw res = 0; + ssize res = 0; s32 rem = ( info ) ? ( info->width > 0 ) ? info->width : 1 : 1; res = rem; while ( rem-- > 0 ) @@ -9168,24 +10135,24 @@ internal sw _print_repeated_char( char* text, sw max_len, _format_info* info, ch return res; } -internal sw _print_i64( char* text, sw max_len, _format_info* info, s64 value ) +internal ssize _print_i64( char* text, ssize max_len, _format_info* info, s64 value ) { char num[ 130 ]; i64_to_str( value, num, info ? info->base : 10 ); return _print_string( text, max_len, info, num ); } -internal sw _print_u64( char* text, sw max_len, _format_info* info, u64 value ) +internal ssize _print_u64( char* text, ssize max_len, _format_info* info, u64 value ) { char num[ 130 ]; u64_to_str( value, num, info ? info->base : 10 ); return _print_string( text, max_len, info, num ); } -internal sw _print_f64( char* text, sw max_len, _format_info* info, b32 is_hexadecimal, f64 arg ) +internal ssize _print_f64( char* text, ssize max_len, _format_info* info, b32 is_hexadecimal, f64 arg ) { // TODO: Handle exponent notation - sw width, len, remaining = max_len; + ssize width, len, remaining = max_len; char* text_begin = text; if ( arg ) @@ -9205,7 +10172,7 @@ internal sw _print_f64( char* text, sw max_len, _format_info* info, b32 is_hexad text++; } - value = zpl_cast( u64 ) arg; + value = scast( u64, arg); len = _print_u64( text, remaining, NULL, value ); text += len; @@ -9226,14 +10193,14 @@ internal sw _print_f64( char* text, sw max_len, _format_info* info, b32 is_hexad text++; while ( info->precision-- > 0 ) { - value = zpl_cast( u64 )( arg * mult ); + value = scast( u64, arg * mult ); len = _print_u64( text, remaining, NULL, value ); text += len; if ( len >= remaining ) remaining = min( remaining, 1 ); else remaining -= len; - arg -= zpl_cast( f64 ) value / mult; + arg -= scast( f64, value / mult); mult *= 10; } } @@ -9281,15 +10248,15 @@ internal sw _print_f64( char* text, sw max_len, _format_info* info, b32 is_hexad return ( text - text_begin ); } -neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) +neverinline ssize c_str_fmt_va( char* text, ssize max_len, char const* fmt, va_list va ) { char const* text_begin = text; - sw remaining = max_len, res; + ssize remaining = max_len, res; while ( *fmt ) { _format_info info = { 0 }; - sw len = 0; + ssize len = 0; info.precision = -1; while ( *fmt && *fmt != '%' && remaining ) @@ -9302,35 +10269,35 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) switch ( *++fmt ) { case '-' : - { - info.flags |= GEN_FMT_MINUS; - break; - } + { + info.flags |= GEN_FMT_MINUS; + break; + } case '+' : - { - info.flags |= GEN_FMT_PLUS; - break; - } + { + info.flags |= GEN_FMT_PLUS; + break; + } case '#' : - { - info.flags |= GEN_FMT_ALT; - break; - } + { + info.flags |= GEN_FMT_ALT; + break; + } case ' ' : - { - info.flags |= GEN_FMT_SPACE; - break; - } + { + info.flags |= GEN_FMT_SPACE; + break; + } case '0' : - { - info.flags |= ( GEN_FMT_ZERO | GEN_FMT_WIDTH ); - break; - } + { + info.flags |= ( GEN_FMT_ZERO | GEN_FMT_WIDTH ); + break; + } default : - { - info.flags |= GEN_FMT_DONE; - break; - } + { + info.flags |= GEN_FMT_DONE; + break; + } } } while ( ! ( info.flags & GEN_FMT_DONE ) ); } @@ -9353,7 +10320,7 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) } else { - info.width = zpl_cast( s32 ) str_to_i64( fmt, zpl_cast( char** ) & fmt, 10 ); + info.width = scast( s32, c_str_to_i64( fmt, ccast( char**, & fmt), 10 )); if ( info.width != 0 ) { info.flags |= GEN_FMT_WIDTH; @@ -9371,7 +10338,7 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) } else { - info.precision = zpl_cast( s32 ) str_to_i64( fmt, zpl_cast( char** ) & fmt, 10 ); + info.precision = scast( s32, c_str_to_i64( fmt, ccast( char**, & fmt), 10 )); } info.flags &= ~GEN_FMT_ZERO; } @@ -9453,19 +10420,29 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) break; case 'c' : - len = _print_char( text, remaining, &info, zpl_cast( char ) va_arg( va, int ) ); + len = _print_char( text, remaining, &info, scast( char, va_arg( va, int ) )); break; case 's' : len = _print_string( text, remaining, &info, va_arg( va, char* ) ); break; - case 'S' : + case 'S': { - String gen_str = String { va_arg( va, char* ) }; + if ( *(fmt + 1) == 'B' ) + { - info.precision = gen_str.length(); - len = _print_string( text, remaining, &info, gen_str ); + ++ fmt; + StrBuilder gen_str = { va_arg( va, char*) }; + + info.precision = strbuilder_length(gen_str); + len = _print_string( text, remaining, &info, gen_str ); + break; + } + + Str gen_str = va_arg( va, Str); + info.precision = gen_str.Len; + len = _print_string( text, remaining, &info, gen_str.Ptr ); } break; @@ -9497,25 +10474,25 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) switch ( info.flags & GEN_FMT_INTS ) { case GEN_FMT_CHAR : - value = zpl_cast( u64 ) zpl_cast( u8 ) va_arg( va, int ); + value = scast( u64, scast( u8, va_arg( va, int ))); break; case GEN_FMT_SHORT : - value = zpl_cast( u64 ) zpl_cast( u16 ) va_arg( va, int ); + value = scast( u64, scast( u16, va_arg( va, int ))); break; - case GEN_FMT_LONG : - value = zpl_cast( u64 ) va_arg( va, unsigned long ); + case GEN_FMT_LONG: + value = scast( u64, va_arg( va, unsigned long )); break; case GEN_FMT_LLONG : - value = zpl_cast( u64 ) va_arg( va, unsigned long long ); + value = scast( u64, va_arg( va, unsigned long long )); break; case GEN_FMT_SIZE : - value = zpl_cast( u64 ) va_arg( va, uw ); + value = scast( u64, va_arg( va, usize )); break; case GEN_FMT_INTPTR : - value = zpl_cast( u64 ) va_arg( va, uptr ); + value = scast( u64, va_arg( va, uptr )); break; default : - value = zpl_cast( u64 ) va_arg( va, unsigned int ); + value = scast( u64, va_arg( va, unsigned int )); break; } @@ -9527,25 +10504,25 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) switch ( info.flags & GEN_FMT_INTS ) { case GEN_FMT_CHAR : - value = zpl_cast( s64 ) zpl_cast( s8 ) va_arg( va, int ); + value = scast( s64, scast( s8, va_arg( va, int ))); break; case GEN_FMT_SHORT : - value = zpl_cast( s64 ) zpl_cast( s16 ) va_arg( va, int ); + value = scast( s64, scast( s16, va_arg( va, int ))); break; case GEN_FMT_LONG : - value = zpl_cast( s64 ) va_arg( va, long ); + value = scast( s64, va_arg( va, long )); break; case GEN_FMT_LLONG : - value = zpl_cast( s64 ) va_arg( va, long long ); + value = scast( s64, va_arg( va, long long )); break; case GEN_FMT_SIZE : - value = zpl_cast( s64 ) va_arg( va, uw ); + value = scast( s64, va_arg( va, usize )); break; case GEN_FMT_INTPTR : - value = zpl_cast( s64 ) va_arg( va, uptr ); + value = scast( s64, va_arg( va, uptr )); break; default : - value = zpl_cast( s64 ) va_arg( va, int ); + value = scast( s64, va_arg( va, int )); break; } @@ -9565,67 +10542,67 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va ) return ( res >= max_len || res < 0 ) ? -1 : res; } -char* str_fmt_buf_va( char const* fmt, va_list va ) +char* c_str_fmt_buf_va( char const* fmt, va_list va ) { local_persist thread_local char buffer[ GEN_PRINTF_MAXLEN ]; - str_fmt_va( buffer, size_of( buffer ), fmt, va ); + c_str_fmt_va( buffer, size_of( buffer ), fmt, va ); return buffer; } -char* str_fmt_buf( char const* fmt, ... ) +char* c_str_fmt_buf( char const* fmt, ... ) { va_list va; char* str; va_start( va, fmt ); - str = str_fmt_buf_va( fmt, va ); + str = c_str_fmt_buf_va( fmt, va ); va_end( va ); return str; } -sw str_fmt_file_va( struct FileInfo* f, char const* fmt, va_list va ) +ssize c_str_fmt_file_va( FileInfo* f, char const* fmt, va_list va ) { local_persist thread_local char buf[ GEN_PRINTF_MAXLEN ]; - sw len = str_fmt_va( buf, size_of( buf ), fmt, va ); + ssize len = c_str_fmt_va( buf, size_of( buf ), fmt, va ); b32 res = file_write( f, buf, len - 1 ); // NOTE: prevent extra whitespace return res ? len : -1; } -sw str_fmt_file( struct FileInfo* f, char const* fmt, ... ) +ssize c_str_fmt_file( FileInfo* f, char const* fmt, ... ) { - sw res; + ssize res; va_list va; va_start( va, fmt ); - res = str_fmt_file_va( f, fmt, va ); + res = c_str_fmt_file_va( f, fmt, va ); va_end( va ); return res; } -sw str_fmt( char* str, sw n, char const* fmt, ... ) +ssize c_str_fmt( char* str, ssize n, char const* fmt, ... ) { - sw res; + ssize res; va_list va; va_start( va, fmt ); - res = str_fmt_va( str, n, fmt, va ); + res = c_str_fmt_va( str, n, fmt, va ); va_end( va ); return res; } -sw str_fmt_out_va( char const* fmt, va_list va ) +ssize c_str_fmt_out_va( char const* fmt, va_list va ) { - return str_fmt_file_va( file_get_standard( EFileStandard_OUTPUT ), fmt, va ); + return c_str_fmt_file_va( file_get_standard( EFileStandard_OUTPUT ), fmt, va ); } -sw str_fmt_out_err_va( char const* fmt, va_list va ) +ssize c_str_fmt_out_err_va( char const* fmt, va_list va ) { - return str_fmt_file_va( file_get_standard( EFileStandard_ERROR ), fmt, va ); + return c_str_fmt_file_va( file_get_standard( EFileStandard_ERROR ), fmt, va ); } -sw str_fmt_out_err( char const* fmt, ... ) +ssize c_str_fmt_out_err( char const* fmt, ... ) { - sw res; + ssize res; va_list va; va_start( va, fmt ); - res = str_fmt_out_err_va( fmt, va ); + res = c_str_fmt_out_err_va( fmt, va ); va_end( va ); return res; } @@ -9634,35 +10611,35 @@ sw str_fmt_out_err( char const* fmt, ... ) #pragma region Memory -void* mem_copy( void* dest, void const* source, sw n ) +void* mem_copy( void* dest, void const* source, ssize n ) { - if ( dest == NULL ) + if ( dest == nullptr ) { - return NULL; + return nullptr; } return memcpy( dest, source, n ); } -void const* mem_find( void const* data, u8 c, sw n ) +void const* mem_find( void const* data, u8 c, ssize n ) { - u8 const* s = zpl_cast( u8 const* ) data; - while ( ( zpl_cast( uptr ) s & ( sizeof( uw ) - 1 ) ) && n && *s != c ) + u8 const* s = rcast( u8 const*, data); + while ( ( rcast( uptr, s) & ( sizeof( usize ) - 1 ) ) && n && *s != c ) { s++; n--; } if ( n && *s != c ) { - sw const* w; - sw k = GEN__ONES * c; - w = zpl_cast( sw const* ) s; - while ( n >= size_of( sw ) && ! GEN__HAS_ZERO( *w ^ k ) ) + ssize const* w; + ssize k = GEN__ONES * c; + w = rcast( ssize const*, s); + while ( n >= size_of( ssize ) && ! GEN__HAS_ZERO( *w ^ k ) ) { w++; - n -= size_of( sw ); + n -= size_of( ssize ); } - s = zpl_cast( u8 const* ) w; + s = rcast( u8 const*, w); while ( n && *s != c ) { s++; @@ -9670,16 +10647,17 @@ void const* mem_find( void const* data, u8 c, sw n ) } } - return n ? zpl_cast( void const* ) s : NULL; + return n ? rcast( void const*, s ) : NULL; } #define GEN_HEAP_STATS_MAGIC 0xDEADC0DE +typedef struct _heap_stats _heap_stats; struct _heap_stats { u32 magic; - sw used_memory; - sw alloc_count; + ssize used_memory; + ssize alloc_count; }; global _heap_stats _heap_stats_info; @@ -9690,13 +10668,13 @@ void heap_stats_init( void ) _heap_stats_info.magic = GEN_HEAP_STATS_MAGIC; } -sw heap_stats_used_memory( void ) +ssize heap_stats_used_memory( void ) { GEN_ASSERT_MSG( _heap_stats_info.magic == GEN_HEAP_STATS_MAGIC, "heap_stats is not initialised yet, call heap_stats_init first!" ); return _heap_stats_info.used_memory; } -sw heap_stats_alloc_count( void ) +ssize heap_stats_alloc_count( void ) { GEN_ASSERT_MSG( _heap_stats_info.magic == GEN_HEAP_STATS_MAGIC, "heap_stats is not initialised yet, call heap_stats_init first!" ); return _heap_stats_info.alloc_count; @@ -9709,13 +10687,14 @@ void heap_stats_check( void ) GEN_ASSERT( _heap_stats_info.alloc_count == 0 ); } +typedef struct _heap_alloc_info _heap_alloc_info; struct _heap_alloc_info { - sw size; + ssize size; void* physical_start; }; -void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ) +void* heap_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) { void* ptr = NULL; // unused( allocator_data ); @@ -9724,26 +10703,26 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw ali alignment = GEN_DEFAULT_MEMORY_ALIGNMENT; #ifdef GEN_HEAP_ANALYSIS - sw alloc_info_size = size_of( _heap_alloc_info ); - sw alloc_info_remainder = ( alloc_info_size % alignment ); - sw track_size = max( alloc_info_size, alignment ) + alloc_info_remainder; + ssize alloc_info_size = size_of( _heap_alloc_info ); + ssize alloc_info_remainder = ( alloc_info_size % alignment ); + ssize track_size = max( alloc_info_size, alignment ) + alloc_info_remainder; switch ( type ) { case EAllocation_FREE : - { - if ( ! old_memory ) - break; - _heap_alloc_info* alloc_info = zpl_cast( _heap_alloc_info* ) old_memory - 1; - _heap_stats_info.used_memory -= alloc_info->size; - _heap_stats_info.alloc_count--; - old_memory = alloc_info->physical_start; - } - break; + { + if ( ! old_memory ) + break; + _heap_alloc_info* alloc_info = rcast( _heap_alloc_info*, old_memory) - 1; + _heap_stats_info.used_memory -= alloc_info->size; + _heap_stats_info.alloc_count--; + old_memory = alloc_info->physical_start; + } + break; case EAllocation_ALLOC : - { - size += track_size; - } - break; + { + size += track_size; + } + break; default : break; } @@ -9751,8 +10730,7 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw ali switch ( type ) { -#if defined( GEN_COMPILER_MSVC ) || ( defined( GEN_COMPILER_GCC ) && defined( GEN_SYSTEM_WINDOWS ) ) \ - || ( defined( GEN_COMPILER_TINYC ) && defined( GEN_SYSTEM_WINDOWS ) ) +#if defined( GEN_COMPILER_MSVC ) || ( defined( GEN_COMPILER_GCC ) && defined( GEN_SYSTEM_WINDOWS ) ) || ( defined( GEN_COMPILER_TINYC ) && defined( GEN_SYSTEM_WINDOWS ) ) case EAllocation_ALLOC : ptr = _aligned_malloc( size, alignment ); if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO ) @@ -9762,60 +10740,60 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw ali _aligned_free( old_memory ); break; case EAllocation_RESIZE : - { - AllocatorInfo a = heap(); - ptr = default_resize_align( a, old_memory, old_size, size, alignment ); - } - break; + { + AllocatorInfo a = heap(); + ptr = default_resize_align( a, old_memory, old_size, size, alignment ); + } + break; #elif defined( GEN_SYSTEM_LINUX ) && ! defined( GEN_CPU_ARM ) && ! defined( GEN_COMPILER_TINYC ) case EAllocation_ALLOC : - { - ptr = aligned_alloc( alignment, ( size + alignment - 1 ) & ~( alignment - 1 ) ); - - if ( flags & GEN_ALLOCATOR_FLAG_CLEAR_TO_ZERO ) { - zero_size( ptr, size ); + ptr = aligned_alloc( alignment, ( size + alignment - 1 ) & ~( alignment - 1 ) ); + + if ( flags & GEN_ALLOCATOR_FLAG_CLEAR_TO_ZERO ) + { + zero_size( ptr, size ); + } } - } - break; + break; case EAllocation_FREE : - { - free( old_memory ); - } - break; + { + free( old_memory ); + } + break; case EAllocation_RESIZE : - { - AllocatorInfo a = heap(); - ptr = default_resize_align( a, old_memory, old_size, size, alignment ); - } - break; + { + AllocatorInfo a = heap(); + ptr = default_resize_align( a, old_memory, old_size, size, alignment ); + } + break; #else case EAllocation_ALLOC : - { - posix_memalign( &ptr, alignment, size ); - - if ( flags & GEN_ALLOCATOR_FLAG_CLEAR_TO_ZERO ) { - zero_size( ptr, size ); + posix_memalign( &ptr, alignment, size ); + + if ( flags & GEN_ALLOCATOR_FLAG_CLEAR_TO_ZERO ) + { + zero_size( ptr, size ); + } } - } - break; + break; case EAllocation_FREE : - { - free( old_memory ); - } - break; + { + free( old_memory ); + } + break; case EAllocation_RESIZE : - { - AllocatorInfo a = heap(); - ptr = default_resize_align( a, old_memory, old_size, size, alignment ); - } - break; + { + AllocatorInfo a = heap(); + ptr = default_resize_align( a, old_memory, old_size, size, alignment ); + } + break; #endif case EAllocation_FREE_ALL : @@ -9825,11 +10803,11 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw ali #ifdef GEN_HEAP_ANALYSIS if ( type == EAllocation_ALLOC ) { - _heap_alloc_info* alloc_info = zpl_cast( _heap_alloc_info* )( zpl_cast( char* ) ptr + alloc_info_remainder ); + _heap_alloc_info* alloc_info = rcast( _heap_alloc_info*, rcast( char*, ptr) + alloc_info_remainder ); zero_item( alloc_info ); alloc_info->size = size - track_size; alloc_info->physical_start = ptr; - ptr = zpl_cast( void* )( alloc_info + 1 ); + ptr = rcast( void*, alloc_info + 1 ); _heap_stats_info.used_memory += alloc_info->size; _heap_stats_info.alloc_count++; } @@ -9839,8 +10817,7 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw ali } #pragma region VirtualMemory - -VirtualMemory vm_from_memory( void* data, sw size ) +VirtualMemory vm_from_memory( void* data, ssize size ) { VirtualMemory vm; vm.data = data; @@ -9849,7 +10826,7 @@ VirtualMemory vm_from_memory( void* data, sw size ) } #if defined( GEN_SYSTEM_WINDOWS ) -VirtualMemory vm_alloc( void* addr, sw size ) +VirtualMemory vm_alloc( void* addr, ssize size ) { VirtualMemory vm; GEN_ASSERT( size > 0 ); @@ -9865,7 +10842,7 @@ b32 vm_free( VirtualMemory vm ) { if ( VirtualQuery( vm.data, &info, size_of( info ) ) == 0 ) return false; - if ( info.BaseAddress != vm.data || info.AllocationBase != vm.data || info.State != MEM_COMMIT || info.RegionSize > zpl_cast( uw ) vm.size ) + if ( info.BaseAddress != vm.data || info.AllocationBase != vm.data || info.State != MEM_COMMIT || info.RegionSize > scast( usize, vm.size) ) { return false; } @@ -9877,10 +10854,10 @@ b32 vm_free( VirtualMemory vm ) return true; } -VirtualMemory vm_trim( VirtualMemory vm, sw lead_size, sw size ) +VirtualMemory vm_trim( VirtualMemory vm, ssize lead_size, ssize size ) { VirtualMemory new_vm = { 0 }; - void* ptr; + void* ptr; GEN_ASSERT( vm.size >= lead_size + size ); ptr = pointer_add( vm.data, lead_size ); @@ -9901,7 +10878,7 @@ b32 vm_purge( VirtualMemory vm ) return true; } -sw virtual_memory_page_size( sw* alignment_out ) +ssize virtual_memory_page_size( ssize* alignment_out ) { SYSTEM_INFO info; GetSystemInfo( &info ); @@ -9911,12 +10888,12 @@ sw virtual_memory_page_size( sw* alignment_out ) } #else -#include +# include -#ifndef MAP_ANONYMOUS -#define MAP_ANONYMOUS MAP_ANON -#endif -VirtualMemory vm_alloc( void* addr, sw size ) +# ifndef MAP_ANONYMOUS +# define MAP_ANONYMOUS MAP_ANON +# endif +VirtualMemory vm_alloc( void* addr, ssize size ) { VirtualMemory vm; GEN_ASSERT( size > 0 ); @@ -9931,10 +10908,10 @@ b32 vm_free( VirtualMemory vm ) return true; } -VirtualMemory vm_trim( VirtualMemory vm, sw lead_size, sw size ) +VirtualMemory vm_trim( VirtualMemory vm, ssize lead_size, ssize size ) { - void* ptr; - sw trail_size; + void* ptr; + ssize trail_size; GEN_ASSERT( vm.size >= lead_size + size ); ptr = pointer_add( vm.data, lead_size ); @@ -9953,10 +10930,10 @@ b32 vm_purge( VirtualMemory vm ) return err != 0; } -sw virtual_memory_page_size( sw* alignment_out ) +ssize virtual_memory_page_size( ssize* alignment_out ) { // TODO: Is this always true? - sw result = zpl_cast( sw ) sysconf( _SC_PAGE_SIZE ); + ssize result = scast( ssize, sysconf( _SC_PAGE_SIZE )); if ( alignment_out ) *alignment_out = result; return result; @@ -9965,35 +10942,35 @@ sw virtual_memory_page_size( sw* alignment_out ) #pragma endregion VirtualMemory -void* Arena::allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw 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; + Arena* arena = rcast(Arena*, allocator_data); + void* ptr = NULL; // unused( old_size ); switch ( type ) { case EAllocation_ALLOC : - { - void* end = pointer_add( arena->PhysicalStart, arena->TotalUsed ); - sw total_size = align_forward_i64( size, alignment ); - - // NOTE: Out of memory - if ( arena->TotalUsed + total_size > ( sw )arena->TotalSize ) { - // zpl__printf_err("%s", "Arena out of memory\n"); - GEN_FATAL( "Arena out of memory! (Possibly could not fit for the largest size Arena!!)" ); - return nullptr; + void* end = pointer_add( arena->PhysicalStart, arena->TotalUsed ); + ssize total_size = align_forward_s64( size, alignment ); + + // NOTE: Out of memory + if ( arena->TotalUsed + total_size > (ssize) arena->TotalSize ) + { + // zpl__printf_err("%s", "Arena out of memory\n"); + GEN_FATAL("Arena out of memory! (Possibly could not fit for the largest size Arena!!)"); + return nullptr; + } + + ptr = align_forward( end, alignment ); + arena->TotalUsed += total_size; + + if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO ) + zero_size( ptr, size ); } - - ptr = align_forward( end, alignment ); - arena->TotalUsed += total_size; - - if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO ) - zero_size( ptr, size ); - } - break; + break; case EAllocation_FREE : // NOTE: Free all at once @@ -10005,19 +10982,19 @@ void* Arena::allocator_proc( void* allocator_data, AllocType type, sw size, sw a break; case EAllocation_RESIZE : - { - // TODO : Check if ptr is on top of stack and just extend - AllocatorInfo a = arena->Backing; - ptr = default_resize_align( a, old_memory, old_size, size, alignment ); - } - break; + { + // TODO : Check if ptr is on top of stack and just extend + AllocatorInfo a = arena->Backing; + ptr = default_resize_align( a, old_memory, old_size, size, alignment ); + } + break; } return ptr; } -void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw 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 = zpl_cast( Pool* ) allocator_data; + Pool* pool = rcast( Pool*, allocator_data); void* ptr = NULL; // unused( old_size ); @@ -10025,59 +11002,59 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw al switch ( type ) { case EAllocation_ALLOC : - { - uptr next_free; + { + uptr next_free; - GEN_ASSERT( size == pool->BlockSize ); - GEN_ASSERT( alignment == pool->BlockAlign ); - GEN_ASSERT( pool->FreeList != NULL ); + GEN_ASSERT( size == pool->BlockSize ); + GEN_ASSERT( alignment == pool->BlockAlign ); + GEN_ASSERT( pool->FreeList != NULL ); - next_free = *zpl_cast( uptr* ) pool->FreeList; - ptr = pool->FreeList; - pool->FreeList = zpl_cast( void* ) next_free; - pool->TotalSize += pool->BlockSize; + next_free = * rcast( uptr*, pool->FreeList); + ptr = pool->FreeList; + pool->FreeList = rcast( void*, next_free); + pool->TotalSize += pool->BlockSize; - if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO ) - zero_size( ptr, size ); - } - break; + if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO ) + zero_size( ptr, size ); + } + break; case EAllocation_FREE : - { - uptr* next; - if ( old_memory == NULL ) - return NULL; + { + uptr* next; + if ( old_memory == NULL ) + return NULL; - next = zpl_cast( uptr* ) old_memory; - *next = zpl_cast( uptr ) pool->FreeList; - pool->FreeList = old_memory; - pool->TotalSize -= pool->BlockSize; - } - break; + next = rcast( uptr*, old_memory); + *next = rcast( uptr, pool->FreeList); + pool->FreeList = old_memory; + pool->TotalSize -= pool->BlockSize; + } + break; case EAllocation_FREE_ALL : - { - sw actual_block_size, block_index; - void* curr; - uptr* end; - - actual_block_size = pool->BlockSize + pool->BlockAlign; - pool->TotalSize = 0; - - // NOTE: Init intrusive freelist - curr = pool->PhysicalStart; - for ( block_index = 0; block_index < pool->NumBlocks - 1; block_index++ ) { - uptr* next = zpl_cast( uptr* ) curr; - *next = zpl_cast( uptr ) curr + actual_block_size; - curr = pointer_add( curr, actual_block_size ); - } + ssize actual_block_size, block_index; + void* curr; + uptr* end; - end = zpl_cast( uptr* ) curr; - *end = zpl_cast( uptr ) NULL; - pool->FreeList = pool->PhysicalStart; - } - break; + actual_block_size = pool->BlockSize + pool->BlockAlign; + pool->TotalSize = 0; + + // NOTE: Init intrusive freelist + curr = pool->PhysicalStart; + for ( block_index = 0; block_index < pool->NumBlocks - 1; block_index++ ) + { + uptr* next = rcast( uptr*, curr); + * next = rcast( uptr, curr) + actual_block_size; + curr = pointer_add( curr, actual_block_size ); + } + + end = rcast( uptr*, curr); + * end = scast( uptr, NULL); + pool->FreeList = pool->PhysicalStart; + } + break; case EAllocation_RESIZE : // NOTE: Cannot resize @@ -10088,37 +11065,37 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw al return ptr; } -Pool Pool::init_align( AllocatorInfo backing, sw num_blocks, sw block_size, sw block_align ) +Pool pool_init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align ) { Pool pool = {}; - sw actual_block_size, pool_size, block_index; + ssize actual_block_size, pool_size, block_index; void *data, *curr; uptr* end; zero_item( &pool ); - pool.Backing = backing; - pool.BlockSize = block_size; - pool.BlockAlign = block_align; - pool.NumBlocks = num_blocks; + pool.Backing = backing; + pool.BlockSize = block_size; + pool.BlockAlign = block_align; + pool.NumBlocks = num_blocks; actual_block_size = block_size + block_align; pool_size = num_blocks * actual_block_size; - data = alloc_align( backing, pool_size, block_align ); + data = alloc_align( backing, pool_size, block_align ); // NOTE: Init intrusive freelist curr = data; for ( block_index = 0; block_index < num_blocks - 1; block_index++ ) { - uptr* next = ( uptr* )curr; - *next = ( uptr )curr + actual_block_size; + uptr* next = ( uptr* ) curr; + *next = ( uptr ) curr + actual_block_size; curr = pointer_add( curr, actual_block_size ); } - end = ( uptr* )curr; - *end = ( uptr )NULL; + end = ( uptr* ) curr; + *end = ( uptr ) NULL; pool.PhysicalStart = data; pool.FreeList = data; @@ -10126,26 +11103,26 @@ Pool Pool::init_align( AllocatorInfo backing, sw num_blocks, sw block_size, sw b return pool; } -void Pool::clear() +void pool_clear(Pool* pool) { - sw 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; + uptr* next = ( uptr* ) curr; + *next = ( uptr ) curr + actual_block_size; curr = pointer_add( curr, actual_block_size ); } - end = ( uptr* )curr; - *end = ( uptr )NULL; + end = ( uptr* ) curr; + *end = ( uptr ) NULL; - FreeList = PhysicalStart; + pool->FreeList = pool->PhysicalStart; } #pragma endregion Memory @@ -10153,89 +11130,82 @@ void Pool::clear() #pragma region Hashing global u32 const _crc32_table[ 256 ] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, - 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, - 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, - 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, - 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, - 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, - 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, - 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, - 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, - 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, - 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, - 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, - 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, - 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, + 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, + 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, + 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, + 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, + 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, }; -u32 crc32( void const* data, sw len ) +u32 crc32( void const* data, ssize len ) { - sw remaining; - u32 result = ~( zpl_cast( u32 ) 0 ); - u8 const* c = zpl_cast( u8 const* ) data; + ssize remaining; + u32 result = ~( scast( u32, 0) ); + u8 const* c = rcast( u8 const*, data); for ( remaining = len; remaining--; c++ ) result = ( result >> 8 ) ^ ( _crc32_table[ ( result ^ *c ) & 0xff ] ); return ~result; } global u64 const _crc64_table[ 256 ] = { - 0x0000000000000000ull, 0x7ad870c830358979ull, 0xf5b0e190606b12f2ull, 0x8f689158505e9b8bull, 0xc038e5739841b68full, 0xbae095bba8743ff6ull, - 0x358804e3f82aa47dull, 0x4f50742bc81f2d04ull, 0xab28ecb46814fe75ull, 0xd1f09c7c5821770cull, 0x5e980d24087fec87ull, 0x24407dec384a65feull, - 0x6b1009c7f05548faull, 0x11c8790fc060c183ull, 0x9ea0e857903e5a08ull, 0xe478989fa00bd371ull, 0x7d08ff3b88be6f81ull, 0x07d08ff3b88be6f8ull, - 0x88b81eabe8d57d73ull, 0xf2606e63d8e0f40aull, 0xbd301a4810ffd90eull, 0xc7e86a8020ca5077ull, 0x4880fbd87094cbfcull, 0x32588b1040a14285ull, - 0xd620138fe0aa91f4ull, 0xacf86347d09f188dull, 0x2390f21f80c18306ull, 0x594882d7b0f40a7full, 0x1618f6fc78eb277bull, 0x6cc0863448deae02ull, - 0xe3a8176c18803589ull, 0x997067a428b5bcf0ull, 0xfa11fe77117cdf02ull, 0x80c98ebf2149567bull, 0x0fa11fe77117cdf0ull, 0x75796f2f41224489ull, - 0x3a291b04893d698dull, 0x40f16bccb908e0f4ull, 0xcf99fa94e9567b7full, 0xb5418a5cd963f206ull, 0x513912c379682177ull, 0x2be1620b495da80eull, - 0xa489f35319033385ull, 0xde51839b2936bafcull, 0x9101f7b0e12997f8ull, 0xebd98778d11c1e81ull, 0x64b116208142850aull, 0x1e6966e8b1770c73ull, - 0x8719014c99c2b083ull, 0xfdc17184a9f739faull, 0x72a9e0dcf9a9a271ull, 0x08719014c99c2b08ull, 0x4721e43f0183060cull, 0x3df994f731b68f75ull, - 0xb29105af61e814feull, 0xc849756751dd9d87ull, 0x2c31edf8f1d64ef6ull, 0x56e99d30c1e3c78full, 0xd9810c6891bd5c04ull, 0xa3597ca0a188d57dull, - 0xec09088b6997f879ull, 0x96d1784359a27100ull, 0x19b9e91b09fcea8bull, 0x636199d339c963f2ull, 0xdf7adabd7a6e2d6full, 0xa5a2aa754a5ba416ull, - 0x2aca3b2d1a053f9dull, 0x50124be52a30b6e4ull, 0x1f423fcee22f9be0ull, 0x659a4f06d21a1299ull, 0xeaf2de5e82448912ull, 0x902aae96b271006bull, - 0x74523609127ad31aull, 0x0e8a46c1224f5a63ull, 0x81e2d7997211c1e8ull, 0xfb3aa75142244891ull, 0xb46ad37a8a3b6595ull, 0xceb2a3b2ba0eececull, - 0x41da32eaea507767ull, 0x3b024222da65fe1eull, 0xa2722586f2d042eeull, 0xd8aa554ec2e5cb97ull, 0x57c2c41692bb501cull, 0x2d1ab4dea28ed965ull, - 0x624ac0f56a91f461ull, 0x1892b03d5aa47d18ull, 0x97fa21650afae693ull, 0xed2251ad3acf6feaull, 0x095ac9329ac4bc9bull, 0x7382b9faaaf135e2ull, - 0xfcea28a2faafae69ull, 0x8632586aca9a2710ull, 0xc9622c4102850a14ull, 0xb3ba5c8932b0836dull, 0x3cd2cdd162ee18e6ull, 0x460abd1952db919full, - 0x256b24ca6b12f26dull, 0x5fb354025b277b14ull, 0xd0dbc55a0b79e09full, 0xaa03b5923b4c69e6ull, 0xe553c1b9f35344e2ull, 0x9f8bb171c366cd9bull, - 0x10e3202993385610ull, 0x6a3b50e1a30ddf69ull, 0x8e43c87e03060c18ull, 0xf49bb8b633338561ull, 0x7bf329ee636d1eeaull, 0x012b592653589793ull, - 0x4e7b2d0d9b47ba97ull, 0x34a35dc5ab7233eeull, 0xbbcbcc9dfb2ca865ull, 0xc113bc55cb19211cull, 0x5863dbf1e3ac9decull, 0x22bbab39d3991495ull, - 0xadd33a6183c78f1eull, 0xd70b4aa9b3f20667ull, 0x985b3e827bed2b63ull, 0xe2834e4a4bd8a21aull, 0x6debdf121b863991ull, 0x1733afda2bb3b0e8ull, - 0xf34b37458bb86399ull, 0x8993478dbb8deae0ull, 0x06fbd6d5ebd3716bull, 0x7c23a61ddbe6f812ull, 0x3373d23613f9d516ull, 0x49aba2fe23cc5c6full, - 0xc6c333a67392c7e4ull, 0xbc1b436e43a74e9dull, 0x95ac9329ac4bc9b5ull, 0xef74e3e19c7e40ccull, 0x601c72b9cc20db47ull, 0x1ac40271fc15523eull, - 0x5594765a340a7f3aull, 0x2f4c0692043ff643ull, 0xa02497ca54616dc8ull, 0xdafce7026454e4b1ull, 0x3e847f9dc45f37c0ull, 0x445c0f55f46abeb9ull, - 0xcb349e0da4342532ull, 0xb1eceec59401ac4bull, 0xfebc9aee5c1e814full, 0x8464ea266c2b0836ull, 0x0b0c7b7e3c7593bdull, 0x71d40bb60c401ac4ull, - 0xe8a46c1224f5a634ull, 0x927c1cda14c02f4dull, 0x1d148d82449eb4c6ull, 0x67ccfd4a74ab3dbfull, 0x289c8961bcb410bbull, 0x5244f9a98c8199c2ull, - 0xdd2c68f1dcdf0249ull, 0xa7f41839ecea8b30ull, 0x438c80a64ce15841ull, 0x3954f06e7cd4d138ull, 0xb63c61362c8a4ab3ull, 0xcce411fe1cbfc3caull, - 0x83b465d5d4a0eeceull, 0xf96c151de49567b7ull, 0x76048445b4cbfc3cull, 0x0cdcf48d84fe7545ull, 0x6fbd6d5ebd3716b7ull, 0x15651d968d029fceull, - 0x9a0d8ccedd5c0445ull, 0xe0d5fc06ed698d3cull, 0xaf85882d2576a038ull, 0xd55df8e515432941ull, 0x5a3569bd451db2caull, 0x20ed197575283bb3ull, - 0xc49581ead523e8c2ull, 0xbe4df122e51661bbull, 0x3125607ab548fa30ull, 0x4bfd10b2857d7349ull, 0x04ad64994d625e4dull, 0x7e7514517d57d734ull, - 0xf11d85092d094cbfull, 0x8bc5f5c11d3cc5c6ull, 0x12b5926535897936ull, 0x686de2ad05bcf04full, 0xe70573f555e26bc4ull, 0x9ddd033d65d7e2bdull, - 0xd28d7716adc8cfb9ull, 0xa85507de9dfd46c0ull, 0x273d9686cda3dd4bull, 0x5de5e64efd965432ull, 0xb99d7ed15d9d8743ull, 0xc3450e196da80e3aull, - 0x4c2d9f413df695b1ull, 0x36f5ef890dc31cc8ull, 0x79a59ba2c5dc31ccull, 0x037deb6af5e9b8b5ull, 0x8c157a32a5b7233eull, 0xf6cd0afa9582aa47ull, - 0x4ad64994d625e4daull, 0x300e395ce6106da3ull, 0xbf66a804b64ef628ull, 0xc5bed8cc867b7f51ull, 0x8aeeace74e645255ull, 0xf036dc2f7e51db2cull, - 0x7f5e4d772e0f40a7ull, 0x05863dbf1e3ac9deull, 0xe1fea520be311aafull, 0x9b26d5e88e0493d6ull, 0x144e44b0de5a085dull, 0x6e963478ee6f8124ull, - 0x21c640532670ac20ull, 0x5b1e309b16452559ull, 0xd476a1c3461bbed2ull, 0xaeaed10b762e37abull, 0x37deb6af5e9b8b5bull, 0x4d06c6676eae0222ull, - 0xc26e573f3ef099a9ull, 0xb8b627f70ec510d0ull, 0xf7e653dcc6da3dd4ull, 0x8d3e2314f6efb4adull, 0x0256b24ca6b12f26ull, 0x788ec2849684a65full, - 0x9cf65a1b368f752eull, 0xe62e2ad306bafc57ull, 0x6946bb8b56e467dcull, 0x139ecb4366d1eea5ull, 0x5ccebf68aecec3a1ull, 0x2616cfa09efb4ad8ull, - 0xa97e5ef8cea5d153ull, 0xd3a62e30fe90582aull, 0xb0c7b7e3c7593bd8ull, 0xca1fc72bf76cb2a1ull, 0x45775673a732292aull, 0x3faf26bb9707a053ull, - 0x70ff52905f188d57ull, 0x0a2722586f2d042eull, 0x854fb3003f739fa5ull, 0xff97c3c80f4616dcull, 0x1bef5b57af4dc5adull, 0x61372b9f9f784cd4ull, - 0xee5fbac7cf26d75full, 0x9487ca0fff135e26ull, 0xdbd7be24370c7322ull, 0xa10fceec0739fa5bull, 0x2e675fb4576761d0ull, 0x54bf2f7c6752e8a9ull, - 0xcdcf48d84fe75459ull, 0xb71738107fd2dd20ull, 0x387fa9482f8c46abull, 0x42a7d9801fb9cfd2ull, 0x0df7adabd7a6e2d6ull, 0x772fdd63e7936bafull, - 0xf8474c3bb7cdf024ull, 0x829f3cf387f8795dull, 0x66e7a46c27f3aa2cull, 0x1c3fd4a417c62355ull, 0x935745fc4798b8deull, 0xe98f353477ad31a7ull, + 0x0000000000000000ull, 0x7ad870c830358979ull, 0xf5b0e190606b12f2ull, 0x8f689158505e9b8bull, 0xc038e5739841b68full, 0xbae095bba8743ff6ull, 0x358804e3f82aa47dull, + 0x4f50742bc81f2d04ull, 0xab28ecb46814fe75ull, 0xd1f09c7c5821770cull, 0x5e980d24087fec87ull, 0x24407dec384a65feull, 0x6b1009c7f05548faull, 0x11c8790fc060c183ull, + 0x9ea0e857903e5a08ull, 0xe478989fa00bd371ull, 0x7d08ff3b88be6f81ull, 0x07d08ff3b88be6f8ull, 0x88b81eabe8d57d73ull, 0xf2606e63d8e0f40aull, 0xbd301a4810ffd90eull, + 0xc7e86a8020ca5077ull, 0x4880fbd87094cbfcull, 0x32588b1040a14285ull, 0xd620138fe0aa91f4ull, 0xacf86347d09f188dull, 0x2390f21f80c18306ull, 0x594882d7b0f40a7full, + 0x1618f6fc78eb277bull, 0x6cc0863448deae02ull, 0xe3a8176c18803589ull, 0x997067a428b5bcf0ull, 0xfa11fe77117cdf02ull, 0x80c98ebf2149567bull, 0x0fa11fe77117cdf0ull, + 0x75796f2f41224489ull, 0x3a291b04893d698dull, 0x40f16bccb908e0f4ull, 0xcf99fa94e9567b7full, 0xb5418a5cd963f206ull, 0x513912c379682177ull, 0x2be1620b495da80eull, + 0xa489f35319033385ull, 0xde51839b2936bafcull, 0x9101f7b0e12997f8ull, 0xebd98778d11c1e81ull, 0x64b116208142850aull, 0x1e6966e8b1770c73ull, 0x8719014c99c2b083ull, + 0xfdc17184a9f739faull, 0x72a9e0dcf9a9a271ull, 0x08719014c99c2b08ull, 0x4721e43f0183060cull, 0x3df994f731b68f75ull, 0xb29105af61e814feull, 0xc849756751dd9d87ull, + 0x2c31edf8f1d64ef6ull, 0x56e99d30c1e3c78full, 0xd9810c6891bd5c04ull, 0xa3597ca0a188d57dull, 0xec09088b6997f879ull, 0x96d1784359a27100ull, 0x19b9e91b09fcea8bull, + 0x636199d339c963f2ull, 0xdf7adabd7a6e2d6full, 0xa5a2aa754a5ba416ull, 0x2aca3b2d1a053f9dull, 0x50124be52a30b6e4ull, 0x1f423fcee22f9be0ull, 0x659a4f06d21a1299ull, + 0xeaf2de5e82448912ull, 0x902aae96b271006bull, 0x74523609127ad31aull, 0x0e8a46c1224f5a63ull, 0x81e2d7997211c1e8ull, 0xfb3aa75142244891ull, 0xb46ad37a8a3b6595ull, + 0xceb2a3b2ba0eececull, 0x41da32eaea507767ull, 0x3b024222da65fe1eull, 0xa2722586f2d042eeull, 0xd8aa554ec2e5cb97ull, 0x57c2c41692bb501cull, 0x2d1ab4dea28ed965ull, + 0x624ac0f56a91f461ull, 0x1892b03d5aa47d18ull, 0x97fa21650afae693ull, 0xed2251ad3acf6feaull, 0x095ac9329ac4bc9bull, 0x7382b9faaaf135e2ull, 0xfcea28a2faafae69ull, + 0x8632586aca9a2710ull, 0xc9622c4102850a14ull, 0xb3ba5c8932b0836dull, 0x3cd2cdd162ee18e6ull, 0x460abd1952db919full, 0x256b24ca6b12f26dull, 0x5fb354025b277b14ull, + 0xd0dbc55a0b79e09full, 0xaa03b5923b4c69e6ull, 0xe553c1b9f35344e2ull, 0x9f8bb171c366cd9bull, 0x10e3202993385610ull, 0x6a3b50e1a30ddf69ull, 0x8e43c87e03060c18ull, + 0xf49bb8b633338561ull, 0x7bf329ee636d1eeaull, 0x012b592653589793ull, 0x4e7b2d0d9b47ba97ull, 0x34a35dc5ab7233eeull, 0xbbcbcc9dfb2ca865ull, 0xc113bc55cb19211cull, + 0x5863dbf1e3ac9decull, 0x22bbab39d3991495ull, 0xadd33a6183c78f1eull, 0xd70b4aa9b3f20667ull, 0x985b3e827bed2b63ull, 0xe2834e4a4bd8a21aull, 0x6debdf121b863991ull, + 0x1733afda2bb3b0e8ull, 0xf34b37458bb86399ull, 0x8993478dbb8deae0ull, 0x06fbd6d5ebd3716bull, 0x7c23a61ddbe6f812ull, 0x3373d23613f9d516ull, 0x49aba2fe23cc5c6full, + 0xc6c333a67392c7e4ull, 0xbc1b436e43a74e9dull, 0x95ac9329ac4bc9b5ull, 0xef74e3e19c7e40ccull, 0x601c72b9cc20db47ull, 0x1ac40271fc15523eull, 0x5594765a340a7f3aull, + 0x2f4c0692043ff643ull, 0xa02497ca54616dc8ull, 0xdafce7026454e4b1ull, 0x3e847f9dc45f37c0ull, 0x445c0f55f46abeb9ull, 0xcb349e0da4342532ull, 0xb1eceec59401ac4bull, + 0xfebc9aee5c1e814full, 0x8464ea266c2b0836ull, 0x0b0c7b7e3c7593bdull, 0x71d40bb60c401ac4ull, 0xe8a46c1224f5a634ull, 0x927c1cda14c02f4dull, 0x1d148d82449eb4c6ull, + 0x67ccfd4a74ab3dbfull, 0x289c8961bcb410bbull, 0x5244f9a98c8199c2ull, 0xdd2c68f1dcdf0249ull, 0xa7f41839ecea8b30ull, 0x438c80a64ce15841ull, 0x3954f06e7cd4d138ull, + 0xb63c61362c8a4ab3ull, 0xcce411fe1cbfc3caull, 0x83b465d5d4a0eeceull, 0xf96c151de49567b7ull, 0x76048445b4cbfc3cull, 0x0cdcf48d84fe7545ull, 0x6fbd6d5ebd3716b7ull, + 0x15651d968d029fceull, 0x9a0d8ccedd5c0445ull, 0xe0d5fc06ed698d3cull, 0xaf85882d2576a038ull, 0xd55df8e515432941ull, 0x5a3569bd451db2caull, 0x20ed197575283bb3ull, + 0xc49581ead523e8c2ull, 0xbe4df122e51661bbull, 0x3125607ab548fa30ull, 0x4bfd10b2857d7349ull, 0x04ad64994d625e4dull, 0x7e7514517d57d734ull, 0xf11d85092d094cbfull, + 0x8bc5f5c11d3cc5c6ull, 0x12b5926535897936ull, 0x686de2ad05bcf04full, 0xe70573f555e26bc4ull, 0x9ddd033d65d7e2bdull, 0xd28d7716adc8cfb9ull, 0xa85507de9dfd46c0ull, + 0x273d9686cda3dd4bull, 0x5de5e64efd965432ull, 0xb99d7ed15d9d8743ull, 0xc3450e196da80e3aull, 0x4c2d9f413df695b1ull, 0x36f5ef890dc31cc8ull, 0x79a59ba2c5dc31ccull, + 0x037deb6af5e9b8b5ull, 0x8c157a32a5b7233eull, 0xf6cd0afa9582aa47ull, 0x4ad64994d625e4daull, 0x300e395ce6106da3ull, 0xbf66a804b64ef628ull, 0xc5bed8cc867b7f51ull, + 0x8aeeace74e645255ull, 0xf036dc2f7e51db2cull, 0x7f5e4d772e0f40a7ull, 0x05863dbf1e3ac9deull, 0xe1fea520be311aafull, 0x9b26d5e88e0493d6ull, 0x144e44b0de5a085dull, + 0x6e963478ee6f8124ull, 0x21c640532670ac20ull, 0x5b1e309b16452559ull, 0xd476a1c3461bbed2ull, 0xaeaed10b762e37abull, 0x37deb6af5e9b8b5bull, 0x4d06c6676eae0222ull, + 0xc26e573f3ef099a9ull, 0xb8b627f70ec510d0ull, 0xf7e653dcc6da3dd4ull, 0x8d3e2314f6efb4adull, 0x0256b24ca6b12f26ull, 0x788ec2849684a65full, 0x9cf65a1b368f752eull, + 0xe62e2ad306bafc57ull, 0x6946bb8b56e467dcull, 0x139ecb4366d1eea5ull, 0x5ccebf68aecec3a1ull, 0x2616cfa09efb4ad8ull, 0xa97e5ef8cea5d153ull, 0xd3a62e30fe90582aull, + 0xb0c7b7e3c7593bd8ull, 0xca1fc72bf76cb2a1ull, 0x45775673a732292aull, 0x3faf26bb9707a053ull, 0x70ff52905f188d57ull, 0x0a2722586f2d042eull, 0x854fb3003f739fa5ull, + 0xff97c3c80f4616dcull, 0x1bef5b57af4dc5adull, 0x61372b9f9f784cd4ull, 0xee5fbac7cf26d75full, 0x9487ca0fff135e26ull, 0xdbd7be24370c7322ull, 0xa10fceec0739fa5bull, + 0x2e675fb4576761d0ull, 0x54bf2f7c6752e8a9ull, 0xcdcf48d84fe75459ull, 0xb71738107fd2dd20ull, 0x387fa9482f8c46abull, 0x42a7d9801fb9cfd2ull, 0x0df7adabd7a6e2d6ull, + 0x772fdd63e7936bafull, 0xf8474c3bb7cdf024ull, 0x829f3cf387f8795dull, 0x66e7a46c27f3aa2cull, 0x1c3fd4a417c62355ull, 0x935745fc4798b8deull, 0xe98f353477ad31a7ull, 0xa6df411fbfb21ca3ull, 0xdc0731d78f8795daull, 0x536fa08fdfd90e51ull, 0x29b7d047efec8728ull, }; -u64 crc64( void const* data, sw len ) +u64 crc64( void const* data, ssize len ) { - sw remaining; - u64 result = ( zpl_cast( u64 ) 0 ); - u8 const* c = zpl_cast( u8 const* ) data; + ssize remaining; + u64 result = ( scast( u64, 0) ); + u8 const* c = rcast( u8 const*, data); for ( remaining = len; remaining--; c++ ) result = ( result >> 8 ) ^ ( _crc64_table[ ( result ^ *c ) & 0xff ] ); return result; @@ -10243,32 +11213,27 @@ u64 crc64( void const* data, sw len ) #pragma endregion Hashing -#pragma region String +#pragma region StrBuilder -String String::fmt( AllocatorInfo allocator, char* buf, sw buf_size, char const* fmt, ... ) +StrBuilder strbuilder_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 ); + ssize const header_size = sizeof( StrBuilderHeader ); - return make( allocator, buf ); -} + s32 alloc_size = header_size + length + 1; + void* allocation = alloc( allocator, alloc_size ); -String String::make_length( AllocatorInfo allocator, char const* str, sw length ) -{ - constexpr sw header_size = sizeof( Header ); + if ( allocation == nullptr ) { + StrBuilder null_string = {nullptr}; + return null_string; + } - s32 alloc_size = header_size + length + 1; - void* allocation = alloc( allocator, alloc_size ); + StrBuilderHeader* + header = rcast(StrBuilderHeader*, allocation); + header->Allocator = allocator; + header->Capacity = length; + header->Length = length; - if ( allocation == nullptr ) - return { nullptr }; - - Header& header = *rcast( Header*, allocation ); - header = { allocator, length, length }; - - String result = { rcast( char*, allocation ) + header_size }; + StrBuilder result = { rcast( char*, allocation) + header_size }; if ( length && str ) mem_copy( result, str, length ); @@ -10280,115 +11245,54 @@ String String::make_length( AllocatorInfo allocator, char const* str, sw length return result; } -String String::make_reserve( AllocatorInfo allocator, sw capacity ) +StrBuilder strbuilder_make_reserve( AllocatorInfo allocator, ssize capacity ) { - constexpr sw header_size = sizeof( Header ); + ssize const header_size = sizeof( StrBuilderHeader ); - s32 alloc_size = header_size + capacity + 1; - void* allocation = alloc( allocator, alloc_size ); - - if ( allocation == nullptr ) - return { nullptr }; + s32 alloc_size = header_size + capacity + 1; + void* allocation = alloc( allocator, alloc_size ); + if ( allocation == nullptr ) { + StrBuilder null_string = {nullptr}; + return null_string; + } mem_set( allocation, 0, alloc_size ); - Header* header = rcast( Header*, allocation ); + StrBuilderHeader* + header = rcast(StrBuilderHeader*, allocation); header->Allocator = allocator; header->Capacity = capacity; header->Length = 0; - String result = { rcast( char*, allocation ) + header_size }; + StrBuilder 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, ... ) -{ - sw 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, sw add_len ) -{ - sw available = avail_space(); - - // NOTE: Return if there is enough space left - if ( available >= add_len ) - { - return true; - } - else - { - sw 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 = zpl_cast( Header* ) new_ptr; - header->Allocator = allocator; - header->Capacity = new_len; - - Data = rcast( char*, header + 1 ); - - return str; - } -} - -#pragma endregion String +#pragma endregion StrBuilder #pragma region File Handling #if defined( GEN_SYSTEM_WINDOWS ) || defined( GEN_SYSTEM_CYGWIN ) -internal wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, sw* w_len_ ) +internal +wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, ssize* w_len_ ) { wchar_t* w_text = NULL; - sw len = 0, w_len = 0, w_len1 = 0; + ssize len = 0, w_len = 0, w_len1 = 0; if ( text == NULL ) { if ( w_len_ ) *w_len_ = w_len; return NULL; } - len = str_len( text ); + len = c_str_len( text ); if ( len == 0 ) { if ( w_len_ ) *w_len_ = w_len; return NULL; } - w_len = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, zpl_cast( int ) len, NULL, 0 ); + w_len = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, scast( int, len), NULL, 0 ); if ( w_len == 0 ) { if ( w_len_ ) @@ -10396,10 +11300,10 @@ internal wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, sw* w_ return NULL; } w_text = alloc_array( a, wchar_t, w_len + 1 ); - w_len1 = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, zpl_cast( int ) len, w_text, zpl_cast( int ) w_len ); + w_len1 = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, scast( int, len), w_text, scast( int, w_len) ); if ( w_len1 == 0 ) { - free( a, w_text ); + allocator_free( a, w_text ); if ( w_len_ ) *w_len_ = 0; return NULL; @@ -10410,7 +11314,8 @@ internal wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, sw* w_ return w_text; } -internal GEN_FILE_SEEK_PROC( _win32_file_seek ) +internal +GEN_FILE_SEEK_PROC( _win32_file_seek ) { LARGE_INTEGER li_offset; li_offset.QuadPart = offset; @@ -10424,12 +11329,13 @@ internal GEN_FILE_SEEK_PROC( _win32_file_seek ) return true; } -internal GEN_FILE_READ_AT_PROC( _win32_file_read ) +internal +GEN_FILE_READ_AT_PROC( _win32_file_read ) { // unused( stop_at_newline ); b32 result = false; _win32_file_seek( fd, offset, ESeekWhence_BEGIN, NULL ); - DWORD size_ = zpl_cast( DWORD )( size > GEN_I32_MAX ? GEN_I32_MAX : size ); + DWORD size_ = scast( DWORD, ( size > GEN_I32_MAX ? GEN_I32_MAX : size )); DWORD bytes_read_; if ( ReadFile( fd.p, buffer, size_, &bytes_read_, NULL ) ) { @@ -10441,9 +11347,10 @@ internal GEN_FILE_READ_AT_PROC( _win32_file_read ) return result; } -internal GEN_FILE_WRITE_AT_PROC( _win32_file_write ) +internal +GEN_FILE_WRITE_AT_PROC( _win32_file_write ) { - DWORD size_ = zpl_cast( DWORD )( size > GEN_I32_MAX ? GEN_I32_MAX : size ); + DWORD size_ = scast( DWORD, ( size > GEN_I32_MAX ? GEN_I32_MAX : size )); DWORD bytes_written_; _win32_file_seek( fd, offset, ESeekWhence_BEGIN, NULL ); if ( WriteFile( fd.p, buffer, size_, &bytes_written_, NULL ) ) @@ -10455,14 +11362,16 @@ internal GEN_FILE_WRITE_AT_PROC( _win32_file_write ) return false; } -internal GEN_FILE_CLOSE_PROC( _win32_file_close ) +internal +GEN_FILE_CLOSE_PROC( _win32_file_close ) { CloseHandle( fd.p ); } FileOperations const default_file_operations = { _win32_file_read, _win32_file_write, _win32_file_seek, _win32_file_close }; -neverinline GEN_FILE_OPEN_PROC( _win32_file_open ) +neverinline +GEN_FILE_OPEN_PROC( _win32_file_open ) { DWORD desired_access; DWORD creation_disposition; @@ -10503,7 +11412,7 @@ neverinline GEN_FILE_OPEN_PROC( _win32_file_open ) w_text = _alloc_utf8_to_ucs2( heap(), filename, NULL ); handle = CreateFileW( w_text, desired_access, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL ); - free( heap(), w_text ); + allocator_free( heap(), w_text ); if ( handle == INVALID_HANDLE_VALUE ) { @@ -10538,15 +11447,16 @@ neverinline GEN_FILE_OPEN_PROC( _win32_file_open ) } #else // POSIX -#include +# include -internal GEN_FILE_SEEK_PROC( _posix_file_seek ) +internal +GEN_FILE_SEEK_PROC( _posix_file_seek ) { -#if defined( GEN_SYSTEM_OSX ) +# if defined( GEN_SYSTEM_OSX ) s64 res = lseek( fd.i, offset, whence ); -#else // TODO(ZaKlaus): @fixme lseek64 +# else // TODO(ZaKlaus): @fixme lseek64 s64 res = lseek( fd.i, offset, whence ); -#endif +# endif if ( res < 0 ) return false; if ( new_offset ) @@ -10554,10 +11464,11 @@ internal GEN_FILE_SEEK_PROC( _posix_file_seek ) return true; } -internal GEN_FILE_READ_AT_PROC( _posix_file_read ) +internal +GEN_FILE_READ_AT_PROC( _posix_file_read ) { unused( stop_at_newline ); - sw res = pread( fd.i, buffer, size, offset ); + ssize res = pread( fd.i, buffer, size, offset ); if ( res < 0 ) return false; if ( bytes_read ) @@ -10565,19 +11476,20 @@ internal GEN_FILE_READ_AT_PROC( _posix_file_read ) return true; } -internal GEN_FILE_WRITE_AT_PROC( _posix_file_write ) +internal +GEN_FILE_WRITE_AT_PROC( _posix_file_write ) { - sw res; + ssize res; s64 curr_offset = 0; _posix_file_seek( fd, 0, ESeekWhence_CURRENT, &curr_offset ); if ( curr_offset == offset ) { // NOTE: Writing to stdout et al. doesn't like pwrite for numerous reasons - res = write( zpl_cast( int ) fd.i, buffer, size ); + res = write( scast( int, fd.i), buffer, size ); } else { - res = pwrite( zpl_cast( int ) fd.i, buffer, size, offset ); + res = pwrite( scast( int, fd.i), buffer, size, offset ); } if ( res < 0 ) return false; @@ -10586,14 +11498,16 @@ internal GEN_FILE_WRITE_AT_PROC( _posix_file_write ) return true; } -internal GEN_FILE_CLOSE_PROC( _posix_file_close ) +internal +GEN_FILE_CLOSE_PROC( _posix_file_close ) { close( fd.i ); } FileOperations const default_file_operations = { _posix_file_read, _posix_file_write, _posix_file_seek, _posix_file_close }; -neverinline GEN_FILE_OPEN_PROC( _posix_file_open ) +neverinline +GEN_FILE_OPEN_PROC( _posix_file_open ) { s32 os_mode; switch ( mode & GEN_FILE_MODES ) @@ -10637,11 +11551,17 @@ neverinline GEN_FILE_OPEN_PROC( _posix_file_open ) internal void _dirinfo_free_entry( DirEntry* entry ); -// TODO : Is this a bad idea? +// TODO(zpl) : Is this a bad idea? global b32 _std_file_set = false; global FileInfo _std_files[ EFileStandard_COUNT ] = { - {{ nullptr, nullptr, nullptr, nullptr }, { nullptr }, 0, nullptr, 0, nullptr} -}; +{ + { nullptr, nullptr, nullptr, nullptr }, + { nullptr }, + 0, + nullptr, + 0, + nullptr +} }; #if defined( GEN_SYSTEM_WINDOWS ) || defined( GEN_SYSTEM_CYGWIN ) @@ -10649,13 +11569,13 @@ FileInfo* file_get_standard( FileStandardType std ) { if ( ! _std_file_set ) { -#define GEN__SET_STD_FILE( type, v ) \ - _std_files[ type ].fd.p = v; \ - _std_files[ type ].ops = default_file_operations - GEN__SET_STD_FILE( EFileStandard_INPUT, GetStdHandle( STD_INPUT_HANDLE ) ); - GEN__SET_STD_FILE( EFileStandard_OUTPUT, GetStdHandle( STD_OUTPUT_HANDLE ) ); - GEN__SET_STD_FILE( EFileStandard_ERROR, GetStdHandle( STD_ERROR_HANDLE ) ); -#undef GEN__SET_STD_FILE +# define GEN__SET_STD_FILE( type, v ) \ + _std_files[ type ].fd.p = v; \ + _std_files[ type ].ops = default_file_operations + GEN__SET_STD_FILE( EFileStandard_INPUT, GetStdHandle( STD_INPUT_HANDLE ) ); + GEN__SET_STD_FILE( EFileStandard_OUTPUT, GetStdHandle( STD_OUTPUT_HANDLE ) ); + GEN__SET_STD_FILE( EFileStandard_ERROR, GetStdHandle( STD_ERROR_HANDLE ) ); +# undef GEN__SET_STD_FILE _std_file_set = true; } return &_std_files[ std ]; @@ -10667,13 +11587,13 @@ FileInfo* file_get_standard( FileStandardType std ) { if ( ! _std_file_set ) { -#define GEN__SET_STD_FILE( type, v ) \ - _std_files[ type ].fd.i = v; \ - _std_files[ type ].ops = default_file_operations +# define GEN__SET_STD_FILE( type, v ) \ + _std_files[ type ].fd.i = v; \ + _std_files[ type ].ops = default_file_operations GEN__SET_STD_FILE( EFileStandard_INPUT, 0 ); GEN__SET_STD_FILE( EFileStandard_OUTPUT, 1 ); GEN__SET_STD_FILE( EFileStandard_ERROR, 2 ); -#undef GEN__SET_STD_FILE +# undef GEN__SET_STD_FILE _std_file_set = true; } return &_std_files[ std ]; @@ -10687,7 +11607,7 @@ FileError file_close( FileInfo* f ) return EFileError_INVALID; if ( f->filename ) - free( heap(), zpl_cast( char* ) f->filename ); + allocator_free( heap(), ccast( char*, f->filename )); #if defined( GEN_SYSTEM_WINDOWS ) if ( f->fd.p == INVALID_HANDLE_VALUE ) @@ -10721,15 +11641,15 @@ FileError file_close( FileInfo* f ) FileError file_new( FileInfo* f, FileDescriptor fd, FileOperations ops, char const* filename ) { - FileError err = EFileError_NONE; - sw len = str_len( filename ); + FileError err = EFileError_NONE; + ssize len = c_str_len( filename ); f->ops = ops; f->fd = fd; f->dir = nullptr; f->last_write_time = 0; f->filename = alloc_array( heap(), char, len + 1 ); - mem_copy( zpl_cast( char* ) f->filename, zpl_cast( char* ) filename, len + 1 ); + mem_copy( ccast( char*, f->filename), ccast( char*, filename), len + 1 ); return err; } @@ -10741,11 +11661,15 @@ FileError file_open( FileInfo* f, char const* filename ) FileError file_open_mode( FileInfo* f, FileMode mode, char const* filename ) { - FileInfo file_ = { + FileInfo file_ = + { { nullptr, nullptr, nullptr, nullptr }, - { nullptr }, - 0, nullptr, 0, nullptr - }; + { nullptr }, + 0, + nullptr, + 0, + nullptr + }; *f = file_; FileError err; @@ -10778,13 +11702,13 @@ s64 file_size( FileInfo* f ) FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const* filepath ) { FileContents result; - FileInfo file; + FileInfo file ; result.allocator = a; if ( file_open( &file, filepath ) == EFileError_NONE ) { - sw fsize = zpl_cast( sw ) file_size( &file ); + ssize fsize = scast( ssize , file_size( &file )); if ( fsize > 0 ) { result.data = alloc( a, zero_terminate ? fsize + 1 : fsize ); @@ -10792,7 +11716,7 @@ FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const file_read_at( &file, result.data, result.size, 0 ); if ( zero_terminate ) { - u8* str = zpl_cast( u8* ) result.data; + u8* str = rcast( u8*, result.data); str[ fsize ] = '\0'; } } @@ -10802,30 +11726,33 @@ FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const return result; } +typedef struct _memory_fd _memory_fd; struct _memory_fd { u8 magic; u8* buf; //< zpl_array OR plain buffer if we can't write - sw cursor; + ssize cursor; AllocatorInfo allocator; FileStreamFlags flags; - sw cap; + ssize cap; }; #define GEN__FILE_STREAM_FD_MAGIC 37 -GEN_DEF_INLINE FileDescriptor _file_stream_fd_make( _memory_fd* d ); -GEN_DEF_INLINE _memory_fd* _file_stream_from_fd( FileDescriptor fd ); +FileDescriptor _file_stream_fd_make( _memory_fd* d ); +_memory_fd* _file_stream_from_fd( FileDescriptor fd ); -GEN_IMPL_INLINE FileDescriptor _file_stream_fd_make( _memory_fd* d ) +inline +FileDescriptor _file_stream_fd_make( _memory_fd* d ) { FileDescriptor fd = { 0 }; fd.p = ( void* )d; return fd; } -GEN_IMPL_INLINE _memory_fd* _file_stream_from_fd( FileDescriptor fd ) +inline +_memory_fd* _file_stream_from_fd( FileDescriptor fd ) { _memory_fd* d = ( _memory_fd* )fd.p; GEN_ASSERT( d->magic == GEN__FILE_STREAM_FD_MAGIC ); @@ -10846,7 +11773,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; @@ -10860,7 +11787,7 @@ b8 file_stream_new( FileInfo* file, AllocatorInfo allocator ) return true; } -b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, sw size, FileStreamFlags flags ) +b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize size, FileStreamFlags flags ) { GEN_ASSERT_NOT_NULL( file ); _memory_fd* d = ( _memory_fd* )alloc( allocator, size_of( _memory_fd ) ); @@ -10872,16 +11799,16 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, sw siz d->flags = flags; if ( d->flags & EFileStream_CLONE_WRITABLE ) { - Array< u8 > arr = Array< u8 >::init_reserve( allocator, size ); - d->buf = arr; + Array(u8) arr = array_init_reserve(u8, allocator, size ); + d->buf = arr; if ( ! d->buf ) return false; mem_copy( d->buf, buffer, size ); - d->cap = size; + d->cap = size; - arr.get_header()->Num = size; + array_get_header(arr)->Num = size; } else { @@ -10897,7 +11824,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, sw siz return true; } -u8* file_stream_buf( FileInfo* file, sw* size ) +u8* file_stream_buf( FileInfo* file, ssize* size ) { GEN_ASSERT_NOT_NULL( file ); _memory_fd* d = _file_stream_from_fd( file->fd ); @@ -10906,10 +11833,11 @@ u8* file_stream_buf( FileInfo* file, sw* size ) return d->buf; } -internal GEN_FILE_SEEK_PROC( _memory_file_seek ) +internal +GEN_FILE_SEEK_PROC( _memory_file_seek ) { _memory_fd* d = _file_stream_from_fd( fd ); - sw buflen = d->cap; + ssize buflen = d->cap; if ( whence == ESeekWhence_BEGIN ) d->cursor = 0; @@ -10922,7 +11850,8 @@ internal GEN_FILE_SEEK_PROC( _memory_file_seek ) return true; } -internal GEN_FILE_READ_AT_PROC( _memory_file_read ) +internal +GEN_FILE_READ_AT_PROC( _memory_file_read ) { // unused( stop_at_newline ); _memory_fd* d = _file_stream_from_fd( fd ); @@ -10932,25 +11861,26 @@ internal GEN_FILE_READ_AT_PROC( _memory_file_read ) return true; } -internal GEN_FILE_WRITE_AT_PROC( _memory_file_write ) +internal +GEN_FILE_WRITE_AT_PROC( _memory_file_write ) { _memory_fd* d = _file_stream_from_fd( fd ); if ( ! ( d->flags & ( EFileStream_CLONE_WRITABLE | EFileStream_WRITABLE ) ) ) return false; - sw buflen = d->cap; - sw extralen = max( 0, size - ( buflen - offset ) ); - sw rwlen = size - extralen; - sw new_cap = buflen + extralen; + ssize buflen = d->cap; + ssize extralen = max( 0, size - ( buflen - offset ) ); + ssize rwlen = size - extralen; + ssize new_cap = buflen + extralen; if ( d->flags & EFileStream_CLONE_WRITABLE ) { - Array< u8 > arr = { d->buf }; + Array(u8) arr = { d->buf }; - if ( arr.get_header()->Capacity < new_cap ) + if ( array_get_header(arr)->Capacity < scast(usize, new_cap) ) { - if ( ! arr.grow( ( s64 )( new_cap ) ) ) + if ( ! array_grow( & arr, ( s64 )( new_cap ) ) ) return false; d->buf = arr; } @@ -10960,11 +11890,11 @@ internal GEN_FILE_WRITE_AT_PROC( _memory_file_write ) if ( ( d->flags & EFileStream_CLONE_WRITABLE ) && extralen > 0 ) { - Array< u8 > arr = { d->buf }; + Array(u8) arr = { d->buf }; mem_copy( d->buf + offset + rwlen, pointer_add_const( buffer, rwlen ), extralen ); - d->cap = new_cap; - arr.get_header()->Capacity = new_cap; + d->cap = new_cap; + array_get_header(arr)->Capacity = new_cap; } else { @@ -10976,18 +11906,19 @@ internal GEN_FILE_WRITE_AT_PROC( _memory_file_write ) return true; } -internal GEN_FILE_CLOSE_PROC( _memory_file_close ) +internal +GEN_FILE_CLOSE_PROC( _memory_file_close ) { _memory_fd* d = _file_stream_from_fd( fd ); AllocatorInfo allocator = d->allocator; if ( d->flags & EFileStream_CLONE_WRITABLE ) { - Array< u8 > arr = { d->buf }; - arr.free(); + Array(u8) arr = { d->buf }; + array_free(arr); } - free( allocator, d ); + allocator_free( allocator, d ); } FileOperations const memory_file_operations = { _memory_file_read, _memory_file_write, _memory_file_seek, _memory_file_close }; @@ -10997,162 +11928,162 @@ FileOperations const memory_file_operations = { _memory_file_read, _memory_file_ #pragma region Timing #ifdef GEN_BENCHMARK -#if defined( GEN_COMPILER_MSVC ) && ! defined( __clang__ ) -u64 read_cpu_time_stamp_counter( void ) -{ - return __rdtsc(); -} -#elif defined( __i386__ ) -u64 read_cpu_time_stamp_counter( void ) -{ - u64 x; - __asm__ volatile( ".byte 0x0f, 0x31" : "=A"( x ) ); - return x; -} -#elif defined( __x86_64__ ) -u64 read_cpu_time_stamp_counter( void ) -{ - u32 hi, lo; - __asm__ __volatile__( "rdtsc" : "=a"( lo ), "=d"( hi ) ); - return ( zpl_cast( u64 ) lo ) | ( ( zpl_cast( u64 ) hi ) << 32 ); -} -#elif defined( __powerpc__ ) -u64 read_cpu_time_stamp_counter( void ) -{ - u64 result = 0; - u32 upper, lower, tmp; - __asm__ volatile( - "0: \n" - "\tmftbu %0 \n" - "\tmftb %1 \n" - "\tmftbu %2 \n" - "\tcmpw %2,%0 \n" - "\tbne 0b \n" - : "=r"( upper ), "=r"( lower ), "=r"( tmp ) - ); - result = upper; - result = result << 32; - result = result | lower; + #if defined( GEN_COMPILER_MSVC ) && ! defined( __clang__ ) + u64 read_cpu_time_stamp_counter( void ) + { + return __rdtsc(); + } + #elif defined( __i386__ ) + u64 read_cpu_time_stamp_counter( void ) + { + u64 x; + __asm__ volatile( ".byte 0x0f, 0x31" : "=A"( x ) ); + return x; + } + #elif defined( __x86_64__ ) + u64 read_cpu_time_stamp_counter( void ) + { + u32 hi, lo; + __asm__ __volatile__( "rdtsc" : "=a"( lo ), "=d"( hi ) ); + return scast( u64, lo ) | ( scast( u64, hi ) << 32 ); + } + #elif defined( __powerpc__ ) + u64 read_cpu_time_stamp_counter( void ) + { + u64 result = 0; + u32 upper, lower, tmp; + __asm__ volatile( + "0: \n" + "\tmftbu %0 \n" + "\tmftb %1 \n" + "\tmftbu %2 \n" + "\tcmpw %2,%0 \n" + "\tbne 0b \n" + : "=r"( upper ), "=r"( lower ), "=r"( tmp ) + ); + result = upper; + result = result << 32; + result = result | lower; - return result; -} -#elif defined( GEN_SYSTEM_EMSCRIPTEN ) -u64 read_cpu_time_stamp_counter( void ) -{ - return ( u64 )( emscripten_get_now() * 1e+6 ); -} -#elif defined( GEN_CPU_ARM ) && ! defined( GEN_COMPILER_TINYC ) -u64 read_cpu_time_stamp_counter( void ) -{ -#if defined( __aarch64__ ) - int64_t r = 0; - asm volatile( "mrs %0, cntvct_el0" : "=r"( r ) ); -#elif ( __ARM_ARCH >= 6 ) - uint32_t r = 0; - uint32_t pmccntr; - uint32_t pmuseren; - uint32_t pmcntenset; + return result; + } + #elif defined( GEN_SYSTEM_EMSCRIPTEN ) + u64 read_cpu_time_stamp_counter( void ) + { + return ( u64 )( emscripten_get_now() * 1e+6 ); + } + #elif defined( GEN_CPU_ARM ) && ! defined( GEN_COMPILER_TINYC ) + u64 read_cpu_time_stamp_counter( void ) + { + # if defined( __aarch64__ ) + int64_t r = 0; + asm volatile( "mrs %0, cntvct_el0" : "=r"( r ) ); + # elif ( __ARM_ARCH >= 6 ) + uint32_t r = 0; + uint32_t pmccntr; + uint32_t pmuseren; + uint32_t pmcntenset; - // Read the user mode perf monitor counter access permissions. - asm volatile( "mrc p15, 0, %0, c9, c14, 0" : "=r"( pmuseren ) ); - if ( pmuseren & 1 ) - { // Allows reading perfmon counters for user mode code. - asm volatile( "mrc p15, 0, %0, c9, c12, 1" : "=r"( pmcntenset ) ); - if ( pmcntenset & 0x80000000ul ) - { // Is it counting? - asm volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"( pmccntr ) ); - // The counter is set up to count every 64th cycle - return ( ( int64_t )pmccntr ) * 64; // Should optimize to << 6 + // Read the user mode perf monitor counter access permissions. + asm volatile( "mrc p15, 0, %0, c9, c14, 0" : "=r"( pmuseren ) ); + if ( pmuseren & 1 ) + { // Allows reading perfmon counters for user mode code. + asm volatile( "mrc p15, 0, %0, c9, c12, 1" : "=r"( pmcntenset ) ); + if ( pmcntenset & 0x80000000ul ) + { // Is it counting? + asm volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"( pmccntr ) ); + // The counter is set up to count every 64th cycle + return ( ( int64_t )pmccntr ) * 64; // Should optimize to << 6 + } } + # else + # error "No suitable method for read_cpu_time_stamp_counter for this cpu type" + # endif + + return r; } -#else -#error "No suitable method for read_cpu_time_stamp_counter for this cpu type" -#endif - - return r; -} -#else -u64 read_cpu_time_stamp_counter( void ) -{ - GEN_PANIC( "read_cpu_time_stamp_counter is not supported on this particular setup" ); - return -0; -} -#endif - -#if defined( GEN_SYSTEM_WINDOWS ) || defined( GEN_SYSTEM_CYGWIN ) - -u64 time_rel_ms( void ) -{ - local_persist LARGE_INTEGER win32_perf_count_freq = {}; - u64 result; - LARGE_INTEGER counter; - local_persist LARGE_INTEGER win32_perf_counter = {}; - if ( ! win32_perf_count_freq.QuadPart ) + #else + u64 read_cpu_time_stamp_counter( void ) { - QueryPerformanceFrequency( &win32_perf_count_freq ); - GEN_ASSERT( win32_perf_count_freq.QuadPart != 0 ); - QueryPerformanceCounter( &win32_perf_counter ); + GEN_PANIC( "read_cpu_time_stamp_counter is not supported on this particular setup" ); + return -0; } + #endif - QueryPerformanceCounter( &counter ); + #if defined( GEN_SYSTEM_WINDOWS ) || defined( GEN_SYSTEM_CYGWIN ) - result = ( counter.QuadPart - win32_perf_counter.QuadPart ) * 1000 / ( win32_perf_count_freq.QuadPart ); - return result; -} - -#else - -#if defined( GEN_SYSTEM_LINUX ) || defined( GEN_SYSTEM_FREEBSD ) || defined( GEN_SYSTEM_OPENBSD ) || defined( GEN_SYSTEM_EMSCRIPTEN ) -u64 _unix_gettime( void ) -{ - struct timespec t; - u64 result; - - clock_gettime( 1 /*CLOCK_MONOTONIC*/, &t ); - result = 1000 * t.tv_sec + 1.0e-6 * t.tv_nsec; - return result; -} -#endif - -u64 time_rel_ms( void ) -{ -#if defined( GEN_SYSTEM_OSX ) - u64 result; - - local_persist u64 timebase = 0; - local_persist u64 timestart = 0; - - if ( ! timestart ) + u64 time_rel_ms( void ) { - mach_timebase_info_data_t tb = { 0 }; - mach_timebase_info( &tb ); - timebase = tb.numer; - timebase /= tb.denom; - timestart = mach_absolute_time(); + local_persist LARGE_INTEGER win32_perf_count_freq = {}; + u64 result; + LARGE_INTEGER counter; + local_persist LARGE_INTEGER win32_perf_counter = {}; + if ( ! win32_perf_count_freq.QuadPart ) + { + QueryPerformanceFrequency( &win32_perf_count_freq ); + GEN_ASSERT( win32_perf_count_freq.QuadPart != 0 ); + QueryPerformanceCounter( &win32_perf_counter ); + } + + QueryPerformanceCounter( &counter ); + + result = ( counter.QuadPart - win32_perf_counter.QuadPart ) * 1000 / ( win32_perf_count_freq.QuadPart ); + return result; } - // NOTE: mach_absolute_time() returns things in nanoseconds - result = 1.0e-6 * ( mach_absolute_time() - timestart ) * timebase; - return result; -#else - local_persist u64 unix_timestart = 0.0; + #else - if ( ! unix_timestart ) + # if defined( GEN_SYSTEM_LINUX ) || defined( GEN_SYSTEM_FREEBSD ) || defined( GEN_SYSTEM_OPENBSD ) || defined( GEN_SYSTEM_EMSCRIPTEN ) + u64 _unix_gettime( void ) { - unix_timestart = _unix_gettime(); + struct timespec t; + u64 result; + + clock_gettime( 1 /*CLOCK_MONOTONIC*/, &t ); + result = 1000 * t.tv_sec + 1.0e-6 * t.tv_nsec; + return result; } + # endif - u64 now = _unix_gettime(); + u64 time_rel_ms( void ) + { + # if defined( GEN_SYSTEM_OSX ) + u64 result; - return ( now - unix_timestart ); -#endif -} -#endif + local_persist u64 timebase = 0; + local_persist u64 timestart = 0; -f64 time_rel( void ) -{ - return ( f64 )( time_rel_ms() * 1e-3 ); -} + if ( ! timestart ) + { + mach_timebase_info_data_t tb = { 0 }; + mach_timebase_info( &tb ); + timebase = tb.numer; + timebase /= tb.denom; + timestart = mach_absolute_time(); + } + + // NOTE: mach_absolute_time() returns things in nanoseconds + result = 1.0e-6 * ( mach_absolute_time() - timestart ) * timebase; + return result; + # else + local_persist u64 unix_timestart = 0.0; + + if ( ! unix_timestart ) + { + unix_timestart = _unix_gettime(); + } + + u64 now = _unix_gettime(); + + return ( now - unix_timestart ); + # endif + } + #endif + + f64 time_rel( void ) + { + return ( f64 )( time_rel_ms() * 1e-3 ); + } #endif #pragma endregion Timing @@ -11164,7 +12095,7 @@ f64 time_rel( void ) #define _adt_fprintf( s_, fmt_, ... ) \ do \ { \ - if ( str_fmt_file( s_, fmt_, ##__VA_ARGS__ ) < 0 ) \ + if ( c_str_fmt_file( s_, fmt_, ##__VA_ARGS__ ) < 0 ) \ return EADT_ERROR_OUT_OF_MEMORY; \ } while ( 0 ) @@ -11180,7 +12111,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; @@ -11193,12 +12124,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 ( sw i = 0; i < node->nodes.num(); ++i ) + for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); ++i ) { adt_destroy_branch( node->nodes + i ); } - node->nodes.free(); + array_free(node->nodes); } return 0; } @@ -11223,9 +12154,9 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ) return NULL; } - for ( sw i = 0; i < node->nodes.num(); i++ ) + for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) { - if ( ! str_compare( node->nodes[ i ].name, name ) ) + if ( ! c_str_compare( node->nodes[ i ].name, name ) ) { return ( node->nodes + i ); } @@ -11233,7 +12164,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ) if ( deep_search ) { - for ( sw i = 0; i < node->nodes.num(); i++ ) + for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) { ADT_Node* res = adt_find( node->nodes + i, name, deep_search ); @@ -11251,35 +12182,35 @@ internal ADT_Node* _adt_get_value( ADT_Node* node, char const* value ) { case EADT_TYPE_MULTISTRING : case EADT_TYPE_STRING : - { - if ( node->string && ! str_compare( node->string, value ) ) { - return node; + if ( node->string && ! c_str_compare( node->string, value ) ) + { + return node; + } } - } - break; + break; case EADT_TYPE_INTEGER : case EADT_TYPE_REAL : - { - char back[ 4096 ] = { 0 }; - FileInfo tmp; - - /* allocate a file descriptor for a memory-mapped number to string conversion, input source buffer is not cloned, however. */ - file_stream_open( &tmp, heap(), ( u8* )back, size_of( back ), EFileStream_WRITABLE ); - adt_print_number( &tmp, node ); - - sw fsize = 0; - u8* buf = file_stream_buf( &tmp, &fsize ); - - if ( ! str_compare( ( char const* )buf, value ) ) { - file_close( &tmp ); - return node; - } + char back[ 4096 ] = { 0 }; + FileInfo tmp; - file_close( &tmp ); - } - break; + /* allocate a file descriptor for a memory-mapped number to string conversion, input source buffer is not cloned, however. */ + file_stream_open( &tmp, heap(), ( u8* )back, size_of( back ), EFileStream_WRITABLE ); + adt_print_number( &tmp, node ); + + ssize fsize = 0; + u8* buf = file_stream_buf( &tmp, &fsize ); + + if ( ! c_str_compare( ( char const* )buf, value ) ) + { + file_close( &tmp ); + return node; + } + + file_close( &tmp ); + } + break; default : break; /* node doesn't support value based lookup */ } @@ -11289,9 +12220,9 @@ 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 ( sw i = 0; i < node->nodes.num(); i++ ) + for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) { - if ( ! str_compare( node->nodes[ i ].name, name ) ) + if ( ! c_str_compare( node->nodes[ i ].name, name ) ) { ADT_Node* child = &node->nodes[ i ]; if ( _adt_get_value( child, value ) ) @@ -11324,22 +12255,22 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) } #if defined EADT_URI_DEBUG || 0 - str_fmt_out( "uri: %s\n", uri ); + c_str_fmt_out( "uri: %s\n", uri ); #endif char * p = ( char* )uri, *b = p, *e = p; ADT_Node* found_node = NULL; - b = p; - p = e = ( char* )str_skip( p, '/' ); - char* buf = str_fmt_buf( "%.*s", ( int )( e - b ), b ); + b = p; + p = e = ( char* )c_str_skip( p, '/' ); + char* buf = c_str_fmt_buf( "%.*s", ( int )( e - b ), b ); /* handle field value lookup */ if ( *b == '[' ) { char *l_p = buf + 1, *l_b = l_p, *l_e = l_p, *l_b2 = l_p, *l_e2 = l_p; - l_e = ( char* )str_skip( l_p, '=' ); - l_e2 = ( char* )str_skip( l_p, ']' ); + l_e = ( char* )c_str_skip( l_p, '=' ); + l_e2 = ( char* )c_str_skip( l_p, ']' ); if ( ( ! *l_e && node->type != EADT_TYPE_ARRAY ) || ! *l_e2 ) { @@ -11364,7 +12295,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 ( sw i = 0; i < node->nodes.num(); i++ ) + for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) { ADT_Node* child = &node->nodes[ i ]; if ( child->type != EADT_TYPE_OBJECT ) @@ -11382,7 +12313,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) /* [value] */ else { - for ( sw i = 0; i < node->nodes.num(); i++ ) + for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) { ADT_Node* child = &node->nodes[ i ]; if ( _adt_get_value( child, l_b2 ) ) @@ -11413,8 +12344,8 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) /* handle array index lookup */ else { - sw idx = ( sw )str_to_i64( buf, NULL, 10 ); - if ( idx >= 0 && idx < node->nodes.num() ) + ssize idx = ( ssize )c_str_to_i64( buf, NULL, 10 ); + if ( idx >= 0 && idx < scast(ssize, array_num(node->nodes)) ) { found_node = &node->nodes[ idx ]; @@ -11429,7 +12360,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri ) return found_node; } -ADT_Node* adt_alloc_at( ADT_Node* parent, sw index ) +ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index ) { if ( ! parent || ( parent->type != EADT_TYPE_OBJECT && parent->type != EADT_TYPE_ARRAY ) ) { @@ -11439,15 +12370,16 @@ ADT_Node* adt_alloc_at( ADT_Node* parent, sw index ) if ( ! parent->nodes ) return NULL; - if ( index < 0 || index > parent->nodes.num() ) + if ( index < 0 || index > scast(ssize, array_num(parent->nodes)) ) return NULL; ADT_Node o = { 0 }; o.parent = parent; - if ( ! parent->nodes.append_at( o, index ) ) + if ( ! array_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 ) @@ -11460,7 +12392,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, array_num(parent->nodes) ); } b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing ) @@ -11494,7 +12426,7 @@ b8 adt_set_int( ADT_Node* obj, char const* name, s64 value ) return true; } -ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, sw index ) +ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, ssize index ) { GEN_ASSERT_NOT_NULL( node ); GEN_ASSERT_NOT_NULL( new_parent ); @@ -11514,7 +12446,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, array_num(new_parent->nodes) ); } void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ) @@ -11523,8 +12455,8 @@ void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ) GEN_ASSERT_NOT_NULL( other_node ); ADT_Node* parent = node->parent; ADT_Node* other_parent = other_node->parent; - sw index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); - sw index2 = ( pointer_diff( other_parent->nodes, other_node ) / size_of( ADT_Node ) ); + ssize index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); + ssize index2 = ( pointer_diff( other_parent->nodes, other_node ) / size_of( ADT_Node ) ); ADT_Node temp = parent->nodes[ index ]; temp.parent = other_parent; other_parent->nodes[ index2 ].parent = parent; @@ -11537,8 +12469,8 @@ void adt_remove_node( ADT_Node* node ) GEN_ASSERT_NOT_NULL( node ); GEN_ASSERT_NOT_NULL( node->parent ); ADT_Node* parent = node->parent; - sw index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); - parent->nodes.remove_at( index ); + ssize index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); + array_remove_at( parent->nodes, index ); } ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ) @@ -11546,7 +12478,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, array_get_header(parent->nodes)->Allocator ) ) { adt_remove_node( o ); return NULL; @@ -11559,7 +12491,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 = array_get_header(parent->nodes); + if ( adt_set_arr( o, name, node_header->Allocator ) ) { adt_remove_node( o ); return NULL; @@ -11604,7 +12538,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; } @@ -11623,25 +12557,25 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) GEN_ASSERT_NOT_NULL( base_str ); char *p = base_str, *e = p; - s32 base = 0; - s32 base2 = 0; - u8 base2_offset = 0; - s8 exp = 0, orig_exp = 0; - u8 neg_zero = 0; - u8 lead_digit = 0; - ADT_Type node_type = EADT_TYPE_UNINITIALISED; - u8 node_props = 0; + s32 base = 0; + s32 base2 = 0; + u8 base2_offset = 0; + s8 exp = 0, orig_exp = 0; + u8 neg_zero = 0; + u8 lead_digit = 0; + ADT_Type node_type = EADT_TYPE_UNINITIALISED; + 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; } - node_type = EADT_TYPE_INTEGER; - neg_zero = false; + node_type = EADT_TYPE_INTEGER; + neg_zero = false; - sw ib = 0; + ssize ib = 0; char buf[ 48 ] = { 0 }; if ( *e == '+' ) @@ -11664,7 +12598,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) } else { - if ( ! str_compare( e, "0x", 2 ) || ! str_compare( e, "0X", 2 ) ) + if ( ! c_str_compare_len( e, "0x", 2 ) || ! c_str_compare_len( e, "0X", 2 ) ) { node_props = EADT_PROPS_IS_HEX; } @@ -11707,9 +12641,9 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) f32 eb = 10; char expbuf[ 6 ] = { 0 }; - sw expi = 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 ) ) @@ -11728,12 +12662,12 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) } } - orig_exp = exp = ( u8 )str_to_i64( expbuf, NULL, 10 ); + orig_exp = exp = ( u8 )c_str_to_i64( expbuf, NULL, 10 ); } if ( node_type == EADT_TYPE_INTEGER ) { - node->integer = str_to_i64( buf, 0, 0 ); + node->integer = c_str_to_i64( buf, 0, 0 ); #ifndef GEN_PARSER_DISABLE_ANALYSIS /* special case: negative zero */ if ( node->integer == 0 && buf[ 0 ] == '-' ) @@ -11748,19 +12682,19 @@ char* adt_parse_number( ADT_Node* node, char* base_str ) } else { - node->real = str_to_f64( buf, 0 ); + node->real = c_str_to_f64( buf, 0 ); #ifndef GEN_PARSER_DISABLE_ANALYSIS char *q = buf, *base_string = q, *base_string2 = q; - base_string = zpl_cast( char* ) str_skip( base_string, '.' ); + base_string = ccast( char*, c_str_skip( base_string, '.' )); *base_string = '\0'; base_string2 = base_string + 1; - char* base_string_off = base_string2; - while ( *base_string_off++ == '0' ) + char* base_strbuilder_off = base_string2; + while ( *base_strbuilder_off++ == '0' ) base2_offset++; - base = ( s32 )str_to_i64( q, 0, 0 ); - base2 = ( s32 )str_to_i64( base_string2, 0, 0 ); + base = ( s32 )c_str_to_i64( q, 0, 0 ); + base2 = ( s32 )c_str_to_i64( base_string2, 0, 0 ); if ( exp ) { exp = exp * ( ! ( eb == 10.0f ) ? -1 : 1 ); @@ -11819,67 +12753,67 @@ ADT_Error adt_print_number( FileInfo* file, ADT_Node* node ) switch ( node->type ) { case EADT_TYPE_INTEGER : - { - if ( node->props == EADT_PROPS_IS_HEX ) { - _adt_fprintf( file, "0x%llx", ( long long )node->integer ); + if ( node->props == EADT_PROPS_IS_HEX ) + { + _adt_fprintf( file, "0x%llx", ( long long )node->integer ); + } + else + { + _adt_fprintf( file, "%lld", ( long long )node->integer ); + } } - else - { - _adt_fprintf( file, "%lld", ( long long )node->integer ); - } - } - break; + break; case EADT_TYPE_REAL : - { - if ( node->props == EADT_PROPS_NAN ) { - _adt_fprintf( file, "NaN" ); - } - else if ( node->props == EADT_PROPS_NAN_NEG ) - { - _adt_fprintf( file, "-NaN" ); - } - else if ( node->props == EADT_PROPS_INFINITY ) - { - _adt_fprintf( file, "Infinity" ); - } - else if ( node->props == EADT_PROPS_INFINITY_NEG ) - { - _adt_fprintf( file, "-Infinity" ); - } - else if ( node->props == EADT_PROPS_TRUE ) - { - _adt_fprintf( file, "true" ); - } - else if ( node->props == EADT_PROPS_FALSE ) - { - _adt_fprintf( file, "false" ); - } - else if ( node->props == EADT_PROPS_NULL ) - { - _adt_fprintf( file, "null" ); + if ( node->props == EADT_PROPS_NAN ) + { + _adt_fprintf( file, "NaN" ); + } + else if ( node->props == EADT_PROPS_NAN_NEG ) + { + _adt_fprintf( file, "-NaN" ); + } + else if ( node->props == EADT_PROPS_INFINITY ) + { + _adt_fprintf( file, "Infinity" ); + } + else if ( node->props == EADT_PROPS_INFINITY_NEG ) + { + _adt_fprintf( file, "-Infinity" ); + } + else if ( node->props == EADT_PROPS_TRUE ) + { + _adt_fprintf( file, "true" ); + } + else if ( node->props == EADT_PROPS_FALSE ) + { + _adt_fprintf( file, "false" ); + } + else if ( node->props == EADT_PROPS_NULL ) + { + _adt_fprintf( file, "null" ); #ifndef GEN_PARSER_DISABLE_ANALYSIS - } - else if ( node->props == EADT_PROPS_IS_EXP ) - { - _adt_fprintf( file, "%lld.%0*d%llde%lld", ( long long )node->base, node->base2_offset, 0, ( long long )node->base2, ( long long )node->exp ); - } - else if ( node->props == EADT_PROPS_IS_PARSED_REAL ) - { - if ( ! node->lead_digit ) - _adt_fprintf( file, ".%0*d%lld", node->base2_offset, 0, ( long long )node->base2 ); - else - _adt_fprintf( file, "%lld.%0*d%lld", ( long long int )node->base2_offset, 0, ( int )node->base, ( long long )node->base2 ); + } + else if ( node->props == EADT_PROPS_IS_EXP ) + { + _adt_fprintf( file, "%lld.%0*d%llde%lld", ( long long )node->base, node->base2_offset, 0, ( long long )node->base2, ( long long )node->exp ); + } + else if ( node->props == EADT_PROPS_IS_PARSED_REAL ) + { + if ( ! node->lead_digit ) + _adt_fprintf( file, ".%0*d%lld", node->base2_offset, 0, ( long long )node->base2 ); + else + _adt_fprintf( file, "%lld.%0*d%lld", ( long long int )node->base2_offset, 0, ( int )node->base, ( long long )node->base2 ); #endif + } + else + { + _adt_fprintf( file, "%f", node->real ); + } } - else - { - _adt_fprintf( file, "%f", node->real ); - } - } - break; + break; } return EADT_ERROR_NONE; @@ -11903,9 +12837,9 @@ ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_ do { - p = str_skip_any( p, escaped_chars ); + p = c_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++; @@ -11916,7 +12850,7 @@ ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_ return EADT_ERROR_NONE; } -ADT_Error adt_str_to_number( ADT_Node* node ) +ADT_Error adt_c_str_to_number( ADT_Node* node ) { GEN_ASSERT( node ); @@ -11932,7 +12866,7 @@ ADT_Error adt_str_to_number( ADT_Node* node ) return EADT_ERROR_NONE; } -ADT_Error adt_str_to_number_strict( ADT_Node* node ) +ADT_Error adt_c_str_to_number_strict( ADT_Node* node ) { GEN_ASSERT( node ); @@ -11955,9 +12889,9 @@ ADT_Error adt_str_to_number_strict( ADT_Node* node ) #pragma region CSV #ifdef GEN_CSV_DEBUG -#define GEN_CSV_ASSERT( msg ) GEN_PANIC( msg ) +# define GEN_CSV_ASSERT( msg ) GEN_PANIC( msg ) #else -#define GEN_CSV_ASSERT( msg ) +# define GEN_CSV_ASSERT( msg ) #endif u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim ) @@ -11973,13 +12907,13 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b char* beginChar; char* endChar; - sw columnIndex = 0; - sw totalColumnIndex = 0; + ssize columnIndex = 0; + ssize totalColumnIndex = 0; do { char delimiter = 0; - currentChar = zpl_cast( char* ) str_trim( currentChar, false ); + currentChar = ccast( char*, c_str_trim( currentChar, false )); if ( *currentChar == 0 ) break; @@ -11987,23 +12921,23 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b ADT_Node rowItem = { 0 }; rowItem.type = EADT_TYPE_STRING; -#ifndef GEN_PARSER_DISABLE_ANALYSIS + #ifndef GEN_PARSER_DISABLE_ANALYSIS rowItem.name_style = EADT_NAME_STYLE_NO_QUOTES; -#endif + #endif /* handle string literals */ if ( *currentChar == '"' ) { - currentChar += 1; - beginChar = currentChar; - endChar = currentChar; - rowItem.string = beginChar; -#ifndef GEN_PARSER_DISABLE_ANALYSIS + currentChar += 1; + beginChar = currentChar; + endChar = currentChar; + rowItem.string = beginChar; + #ifndef GEN_PARSER_DISABLE_ANALYSIS rowItem.name_style = EADT_NAME_STYLE_DOUBLE_QUOTE; -#endif + #endif do { - endChar = zpl_cast( char* ) str_skip( endChar, '"' ); + endChar = ccast( char*, c_str_skip( endChar, '"' )); if ( *endChar && *( endChar + 1 ) == '"' ) { @@ -12011,7 +12945,8 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b } else break; - } while ( *endChar ); + } + while ( *endChar ); if ( *endChar == 0 ) { @@ -12021,8 +12956,8 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b } *endChar = 0; - currentChar = zpl_cast( char* ) str_trim( endChar + 1, true ); - delimiter = *currentChar; + currentChar = ccast( char*, c_str_trim( endChar + 1, true )); + delimiter = * currentChar; /* unescape escaped quotes (so that unescaped text escapes :) */ { @@ -12031,15 +12966,16 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b { if ( *escapedChar == '"' && *( escapedChar + 1 ) == '"' ) { - mem_move( escapedChar, escapedChar + 1, str_len( escapedChar ) ); + mem_move( escapedChar, escapedChar + 1, c_str_len( escapedChar ) ); } escapedChar++; - } while ( *escapedChar ); + } + while ( *escapedChar ); } } else if ( *currentChar == delim ) { - delimiter = *currentChar; + delimiter = * currentChar; rowItem.string = ""; } else if ( *currentChar ) @@ -12052,19 +12988,20 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b do { endChar++; - } while ( *endChar && *endChar != delim && *endChar != '\n' ); + } + while ( * endChar && * endChar != delim && * endChar != '\n' ); - if ( *endChar ) + if ( * endChar ) { - currentChar = zpl_cast( char* ) str_trim( endChar, true ); + currentChar = ccast( char*, c_str_trim( endChar, true )); while ( char_is_space( *( endChar - 1 ) ) ) { endChar--; } - delimiter = *currentChar; - *endChar = 0; + delimiter = * currentChar; + * endChar = 0; } else { @@ -12077,35 +13014,35 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b char* num_p = beginChar; // We only consider hexadecimal values if they start with 0x - if ( str_len( num_p ) > 2 && num_p[ 0 ] == '0' && ( num_p[ 1 ] == 'x' || num_p[ 1 ] == 'X' ) ) + if ( c_str_len(num_p) > 2 && num_p[0] == '0' && (num_p[1] == 'x' || num_p[1] == 'X') ) { - num_p += 2; // skip '0x' prefix + num_p += 2; // skip '0x' prefix do { - if ( ! char_is_hex_digit( *num_p ) ) + if (!char_is_hex_digit(*num_p)) { skip_number = true; break; } - } while ( *num_p++ ); + } while (*num_p++); } else { skip_number = true; } - if ( ! skip_number ) + if (!skip_number) { - adt_str_to_number( &rowItem ); + adt_c_str_to_number(&rowItem); } } - if ( columnIndex >= root->nodes.num() ) + if ( columnIndex >= scast(ssize, array_num(root->nodes)) ) { adt_append_arr( root, NULL ); } - root->nodes[ columnIndex ].nodes.append( rowItem ); + array_append( root->nodes[ columnIndex ].nodes, rowItem ); if ( delimiter == delim ) { @@ -12130,9 +13067,10 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b if ( delimiter != 0 ) currentChar++; } - } while ( *currentChar ); + } + while ( *currentChar ); - if ( root->nodes.num() == 0 ) + if (array_num( root->nodes) == 0 ) { GEN_CSV_ASSERT( "unexpected end of input. stream is empty." ); error = ECSV_Error__UNEXPECTED_END_OF_INPUT; @@ -12142,12 +13080,12 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b /* consider first row as a header. */ if ( has_header ) { - for ( sw i = 0; i < root->nodes.num(); i++ ) + for ( ssize i = 0; i < scast(ssize, array_num(root->nodes)); i++ ) { CSV_Object* col = root->nodes + i; CSV_Object* hdr = col->nodes; col->name = hdr->string; - col->nodes.remove_at( 0 ); + array_remove_at(col->nodes, 0 ); } } @@ -12164,36 +13102,36 @@ void _csv_write_record( FileInfo* file, CSV_Object* node ) switch ( node->type ) { case EADT_TYPE_STRING : - { -#ifndef GEN_PARSER_DISABLE_ANALYSIS - switch ( node->name_style ) { - case EADT_NAME_STYLE_DOUBLE_QUOTE : - { - str_fmt_file( file, "\"" ); - adt_print_string( file, node, "\"", "\"" ); - str_fmt_file( file, "\"" ); - } - break; - - case EADT_NAME_STYLE_NO_QUOTES : - { -#endif - str_fmt_file( file, "%s", node->string ); #ifndef GEN_PARSER_DISABLE_ANALYSIS - } - break; - } + switch ( node->name_style ) + { + case EADT_NAME_STYLE_DOUBLE_QUOTE : + { + c_str_fmt_file( file, "\"" ); + adt_print_string( file, node, "\"", "\"" ); + c_str_fmt_file( file, "\"" ); + } + break; + + case EADT_NAME_STYLE_NO_QUOTES : + { #endif - } - break; + c_str_fmt_file( file, "%s", node->string ); +#ifndef GEN_PARSER_DISABLE_ANALYSIS + } + break; + } +#endif + } + break; case EADT_TYPE_REAL : case EADT_TYPE_INTEGER : - { - adt_print_number( file, node ); - } - break; + { + adt_print_number( file, node ); + } + break; } } @@ -12210,11 +13148,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 ); - sw cols = obj->nodes.num(); + ssize cols = array_num(obj->nodes); if ( cols == 0 ) return; - sw rows = obj->nodes[ 0 ].nodes.num(); + ssize rows = array_num(obj->nodes[ 0 ].nodes); if ( rows == 0 ) return; @@ -12222,45 +13160,47 @@ void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delimiter ) if ( has_headers ) { - for ( sw i = 0; i < cols; i++ ) + for ( ssize i = 0; i < cols; i++ ) { _csv_write_header( file, &obj->nodes[ i ] ); if ( i + 1 != cols ) { - str_fmt_file( file, "%c", delimiter ); + c_str_fmt_file( file, "%c", delimiter ); } } - str_fmt_file( file, "\n" ); + c_str_fmt_file( file, "\n" ); } - for ( sw r = 0; r < rows; r++ ) + for ( ssize r = 0; r < rows; r++ ) { - for ( sw i = 0; i < cols; i++ ) + for ( ssize i = 0; i < cols; i++ ) { _csv_write_record( file, &obj->nodes[ i ].nodes[ r ] ); if ( i + 1 != cols ) { - str_fmt_file( file, "%c", delimiter ); + c_str_fmt_file( file, "%c", delimiter ); } } - str_fmt_file( file, "\n" ); + c_str_fmt_file( file, "\n" ); } } -String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delimiter ) +StrBuilder csv_write_strbuilder_delimiter( AllocatorInfo a, CSV_Object* obj, char delimiter ) { FileInfo tmp; file_stream_new( &tmp, a ); csv_write_delimiter( &tmp, obj, delimiter ); - sw fsize; + + ssize fsize; u8* buf = file_stream_buf( &tmp, &fsize ); - String output = String::make_length( a, ( char* )buf, fsize ); + StrBuilder output = strbuilder_make_length( a, ( char* )buf, fsize ); file_close( &tmp ); return output; } -#pragma endregion CSV +#undef _adt_fprintf +#pragma endregion CSV #pragma endregion Parsing GEN_NS_END @@ -12271,28 +13211,15 @@ GEN_NS_END GEN_NS_BEGIN #pragma region StaticData - -// TODO : Convert global allocation strategy to use a slab allocation strategy. -global AllocatorInfo GlobalAllocator; -global Array< Arena > Global_AllocatorBuckets; - -global Array< Pool > CodePools = { nullptr }; -global Array< Arena > StringArenas = { nullptr }; - -global StringTable StringCache; - -global Arena LexArena; - -global AllocatorInfo Allocator_DataArrays = heap(); -global AllocatorInfo Allocator_CodePool = heap(); -global AllocatorInfo Allocator_Lexer = heap(); -global AllocatorInfo Allocator_StringArena = heap(); -global AllocatorInfo Allocator_StringTable = heap(); -global AllocatorInfo Allocator_TypeTable = heap(); - -#pragma endregion StaticData +global Context* _ctx; #pragma region Constants +global u32 context_counter; + +global Str enum_underlying_sig; + +global Code Code_Global; +global Code Code_Invalid; global Code access_public; global Code access_protected; @@ -12306,7 +13233,7 @@ global Code module_private_fragment; global Code fmt_newline; -global CodeParam param_varadic; +global CodeParams param_varadic; global CodePragma pragma_once; @@ -12338,1666 +13265,839 @@ global CodeSpecifiers spec_thread_local; global CodeSpecifiers spec_virtual; global CodeSpecifiers spec_volatile; -global CodeType t_empty; -global CodeType t_auto; -global CodeType t_void; -global CodeType t_int; -global CodeType t_bool; -global CodeType t_char; -global CodeType t_wchar_t; -global CodeType t_class; -global CodeType t_typename; +global CodeTypename t_empty; +global CodeTypename t_auto; +global CodeTypename t_void; +global CodeTypename t_int; +global CodeTypename t_bool; +global CodeTypename t_char; +global CodeTypename t_wchar_t; +global CodeTypename t_class; +global CodeTypename t_typename; #ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS -global CodeType t_b32; +global CodeTypename t_b32; -global CodeType t_s8; -global CodeType t_s16; -global CodeType t_s32; -global CodeType t_s64; +global CodeTypename t_s8; +global CodeTypename t_s16; +global CodeTypename t_s32; +global CodeTypename t_s64; -global CodeType t_u8; -global CodeType t_u16; -global CodeType t_u32; -global CodeType t_u64; +global CodeTypename t_u8; +global CodeTypename t_u16; +global CodeTypename t_u32; +global CodeTypename t_u64; -global CodeType t_sw; -global CodeType t_uw; +global CodeTypename t_ssize; +global CodeTypename t_usize; -global CodeType t_f32; -global CodeType t_f64; +global CodeTypename t_f32; +global CodeTypename t_f64; #endif #pragma endregion Constants -#pragma region AST -#define GEN_AST_BODY_CLASS_UNALLOWED_TYPES \ - case PlatformAttributes : \ - case Class_Body : \ - case Enum_Body : \ - case Extern_Linkage : \ - case Function_Body : \ - case Function_Fwd : \ - case Global_Body : \ - case Namespace : \ - case Namespace_Body : \ - case Operator : \ - case Operator_Fwd : \ - case Parameters : \ - case Specifiers : \ - case Struct_Body : \ - case Typename : -#define GEN_AST_BODY_STRUCT_UNALLOWED_TYPES GEN_AST_BODY_CLASS_UNALLOWED_TYPES +#pragma endregion StaticData -#define GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES \ - case Access_Public : \ - case Access_Protected : \ - case Access_Private : \ - case PlatformAttributes : \ - case Class_Body : \ - case Enum_Body : \ - case Extern_Linkage : \ - case Friend : \ - case Function_Body : \ - case Function_Fwd : \ - case Global_Body : \ - case Namespace : \ - case Namespace_Body : \ - case Operator : \ - case Operator_Fwd : \ - case Operator_Member : \ - case Operator_Member_Fwd : \ - case Parameters : \ - case Specifiers : \ - case Struct_Body : \ - case Typename : +#pragma region AST -#define GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES \ - case Access_Public : \ - case Access_Protected : \ - case Access_Private : \ - case PlatformAttributes : \ - case Class_Body : \ - case Enum_Body : \ - case Execution : \ - case Friend : \ - case Function_Body : \ - case Namespace_Body : \ - case Operator_Member : \ - case Operator_Member_Fwd : \ - case Parameters : \ - case Specifiers : \ - case Struct_Body : \ - case Typename : -#define GEN_AST_BODY_EXPORT_UNALLOWED_TYPES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES -#define GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES +// These macros are used in the swtich cases are used within ast.cpp, inteface.upfront.cpp, parser.cpp -#define GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES \ - case Access_Public : \ - case Access_Protected : \ - case Access_Private : \ - case PlatformAttributes : \ - case Class_Body : \ - case Enum_Body : \ - case Execution : \ - case Friend : \ - case Function_Body : \ - case Namespace_Body : \ - case Operator_Member : \ - case Operator_Member_Fwd : \ - case Parameters : \ - case Specifiers : \ - case Struct_Body : \ - case Typename : +# define GEN_AST_BODY_CLASS_UNALLOWED_TYPES \ + case CT_PlatformAttributes: \ + case CT_Class_Body: \ + case CT_Enum_Body: \ + case CT_Extern_Linkage: \ + case CT_Function_Body: \ + case CT_Function_Fwd: \ + case CT_Global_Body: \ + case CT_Namespace: \ + case CT_Namespace_Body: \ + case CT_Operator: \ + case CT_Operator_Fwd: \ + case CT_Parameters: \ + case CT_Specifiers: \ + case CT_Struct_Body: \ + case CT_Typename +# define GEN_AST_BODY_STRUCT_UNALLOWED_TYPES GEN_AST_BODY_CLASS_UNALLOWED_TYPES -Code Code::Global; -Code Code::Invalid; +# define GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES \ + case CT_Access_Public: \ + case CT_Access_Protected: \ + case CT_Access_Private: \ + case CT_PlatformAttributes: \ + case CT_Class_Body: \ + case CT_Enum_Body: \ + case CT_Extern_Linkage: \ + case CT_Friend: \ + case CT_Function_Body: \ + case CT_Function_Fwd: \ + case CT_Global_Body: \ + case CT_Namespace: \ + case CT_Namespace_Body: \ + case CT_Operator: \ + case CT_Operator_Fwd: \ + case CT_Operator_Member: \ + case CT_Operator_Member_Fwd: \ + case CT_Parameters: \ + case CT_Specifiers: \ + case CT_Struct_Body: \ + case CT_Typename + +# define GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES \ + case CT_Access_Public: \ + case CT_Access_Protected: \ + case CT_Access_Private: \ + case CT_PlatformAttributes: \ + case CT_Class_Body: \ + case CT_Enum_Body: \ + case CT_Execution: \ + case CT_Friend: \ + case CT_Function_Body: \ + case CT_Namespace_Body: \ + case CT_Operator_Member: \ + case CT_Operator_Member_Fwd: \ + case CT_Parameters: \ + case CT_Specifiers: \ + case CT_Struct_Body: \ + case CT_Typename +# define GEN_AST_BODY_EXPORT_UNALLOWED_TYPES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES +# define GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES + +# define GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES \ + case CT_Access_Public: \ + case CT_Access_Protected: \ + case CT_Access_Private: \ + case CT_PlatformAttributes: \ + case CT_Class_Body: \ + case CT_Enum_Body: \ + case CT_Execution: \ + case CT_Friend: \ + case CT_Function_Body: \ + case CT_Namespace_Body: \ + case CT_Operator_Member: \ + case CT_Operator_Member_Fwd: \ + case CT_Parameters: \ + case CT_Specifiers: \ + case CT_Struct_Body: \ + case CT_Typename // This serializes all the data-members in a "debug" format, where each member is printed with its associated value. -char const* AST::debug_str() +Str code_debug_str(Code self) { - String result = String::make_reserve( GlobalAllocator, kilobytes( 1 ) ); + GEN_ASSERT(self != nullptr); + StrBuilder result_stack = strbuilder_make_reserve( _ctx->Allocator_Temp, kilobytes(1) ); + StrBuilder* result = & result_stack; - if ( Parent ) - result.append_fmt( "\n\tParent : %S %S", Parent->type_str(), Name ? Name : "" ); + if ( self->Parent ) + strbuilder_append_fmt( result, "\n\tParent : %S %S", code_type_str(self->Parent), self->Name.Len ? self->Name : txt("Null") ); else - result.append_fmt( "\n\tParent : %S", "Null" ); + strbuilder_append_fmt( result, "\n\tParent : %S", txt("Null") ); - result.append_fmt( "\n\tName : %S", Name ? Name : "Null" ); - result.append_fmt( "\n\tType : %S", type_str() ); - result.append_fmt( "\n\tModule Flags : %S", to_str( ModuleFlags ) ); + strbuilder_append_fmt( result, "\n\tName : %S", self->Name.Len ? self->Name : txt("Null") ); + strbuilder_append_fmt( result, "\n\tType : %S", code_type_str(self) ); + strbuilder_append_fmt( result, "\n\tModule Flags : %S", module_flag_to_str( self->ModuleFlags ) ); - switch ( Type ) + switch ( self->Type ) { - using namespace ECode; + case CT_Invalid: + case CT_NewLine: + case CT_Access_Private: + case CT_Access_Protected: + case CT_Access_Public: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + break; - case Invalid : - case NewLine : - case Access_Private : - case Access_Protected : - case Access_Public : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - break; + case CT_Untyped: + case CT_Execution: + case CT_Comment: + case CT_PlatformAttributes: + case CT_Preprocess_Define: + case CT_Preprocess_Include: + case CT_Preprocess_Pragma: + case CT_Preprocess_If: + case CT_Preprocess_ElIf: + case CT_Preprocess_Else: + case CT_Preprocess_IfDef: + case CT_Preprocess_IfNotDef: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Untyped : - case Execution : - case Comment : - case PlatformAttributes : - case Preprocess_Define : - case Preprocess_Include : - case Preprocess_Pragma : - case Preprocess_If : - case Preprocess_ElIf : - case Preprocess_Else : - case Preprocess_IfDef : - case Preprocess_IfNotDef : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tContent: %S", self->Content ); + break; - result.append_fmt( "\n\tContent: %S", Content ); - break; + case CT_Class: + case CT_Struct: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Class : - case Struct : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tAttributes : %S", self->Attributes ? strbuilder_to_str( code_to_strbuilder(self->Attributes) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tParentAccess: %S", self->ParentType ? access_spec_to_str( self->ParentAccess ) : txt("No Parent") ); + strbuilder_append_fmt( result, "\n\tParentType : %S", self->ParentType ? code_type_str(self->ParentType) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tBody : %S", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; - result.append_fmt( "\n\tInlineCmd : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tAttributes : %S", Attributes ? Attributes->to_string() : "Null" ); - result.append_fmt( "\n\tParentAccess: %s", ParentType ? to_str( ParentAccess ) : "No Parent" ); - result.append_fmt( "\n\tParentType : %s", ParentType ? ParentType->type_str() : "Null" ); - result.append_fmt( "\n\tBody : %S", Body ? Body->debug_str() : "Null" ); - break; + case CT_Class_Fwd: + case CT_Struct_Fwd: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Class_Fwd : - case Struct_Fwd : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tAttributes : %S", self->Attributes ? strbuilder_to_str( code_to_strbuilder(self->Attributes) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tParentAccess: %S", self->ParentType ? access_spec_to_str( self->ParentAccess ) : txt("No Parent") ); + strbuilder_append_fmt( result, "\n\tParentType : %S", self->ParentType ? code_type_str(self->ParentType) : txt("Null") ); + break; - result.append_fmt( "\n\tInlineCmd : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tAttributes : %S", Attributes ? Attributes->to_string() : "Null" ); - result.append_fmt( "\n\tParentAccess: %s", ParentType ? to_str( ParentAccess ) : "No Parent" ); - result.append_fmt( "\n\tParentType : %s", ParentType ? ParentType->type_str() : "Null" ); - break; + case CT_Constructor: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Constructor : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tSpecs : %S", self->Specs ? strbuilder_to_str( code_to_strbuilder(self->Specs) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tInitializerList: %S", self->InitializerList ? strbuilder_to_str( code_to_strbuilder(self->InitializerList) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tParams : %S", self->Params ? strbuilder_to_str( code_to_strbuilder(self->Params) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tBody : %S", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tSpecs : %S", Specs ? Specs->to_string() : "Null" ); - result.append_fmt( "\n\tInitializerList: %S", InitializerList ? InitializerList->to_string() : "Null" ); - result.append_fmt( "\n\tParams : %S", Params ? Params->to_string() : "Null" ); - result.append_fmt( "\n\tBody : %S", Body ? Body->debug_str() : "Null" ); - break; + case CT_Constructor_Fwd: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Constructor_Fwd : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tSpecs : %S", self->Specs ? strbuilder_to_str( code_to_strbuilder(self->Specs) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tInitializerList: %S", self->InitializerList ? strbuilder_to_str( code_to_strbuilder(self->InitializerList) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tParams : %S", self->Params ? strbuilder_to_str( code_to_strbuilder(self->Params) ) : txt("Null") ); + break; - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tSpecs : %S", Specs ? Specs->to_string() : "Null" ); - result.append_fmt( "\n\tInitializerList: %S", InitializerList ? InitializerList->to_string() : "Null" ); - result.append_fmt( "\n\tParams : %S", Params ? Params->to_string() : "Null" ); - break; + case CT_Destructor: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Destructor : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tSpecs : %S", self->Specs ? strbuilder_to_str( code_to_strbuilder(self->Specs) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tBody : %S", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tSpecs : %S", Specs ? Specs->to_string() : "Null" ); - result.append_fmt( "\n\tBody : %S", Body ? Body->debug_str() : "Null" ); - break; + case CT_Destructor_Fwd: + break; - case Destructor_Fwd : - break; + case CT_Enum: + case CT_Enum_Class: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Enum : - case Enum_Class : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tAttributes : %S", self->Attributes ? strbuilder_to_str( code_to_strbuilder(self->Attributes) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tUnderlying Type : %S", self->UnderlyingType ? strbuilder_to_str( code_to_strbuilder(self->UnderlyingType)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tBody : %S", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tAttributes : %S", Attributes ? Attributes->to_string() : "Null" ); - result.append_fmt( "\n\tUnderlying Type : %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); - result.append_fmt( "\n\tBody : %S", Body ? Body->debug_str() : "Null" ); - break; + case CT_Enum_Fwd: + case CT_Enum_Class_Fwd: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Enum_Fwd : - case Enum_Class_Fwd : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tAttributes : %S", self->Attributes ? strbuilder_to_str( code_to_strbuilder(self->Attributes) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tUnderlying Type : %S", self->UnderlyingType ? strbuilder_to_str( code_to_strbuilder(self->UnderlyingType)) : txt("Null") ); + break; - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tAttributes : %S", Attributes ? Attributes->to_string() : "Null" ); - result.append_fmt( "\n\tUnderlying Type : %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); - break; + case CT_Extern_Linkage: + case CT_Namespace: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Extern_Linkage : - case Namespace : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tBody: %S", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; - result.append_fmt( "\n\tBody: %S", Body ? Body->debug_str() : "Null" ); - break; + case CT_Friend: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Friend : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tDeclaration: %S", self->Declaration ? strbuilder_to_str( code_to_strbuilder(self->Declaration)) : txt("Null") ); + break; - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tDeclaration: %S", Declaration ? Declaration->to_string() : "Null" ); - break; + case CT_Function: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Function : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tAttributes: %S", self->Attributes ? strbuilder_to_str( code_to_strbuilder(self->Attributes) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tSpecs : %S", self->Specs ? strbuilder_to_str( code_to_strbuilder(self->Specs)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tReturnType: %S", self->ReturnType ? strbuilder_to_str( code_to_strbuilder(self->ReturnType)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tParams : %S", self->Params ? strbuilder_to_str( code_to_strbuilder(self->Params)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tBody : %S", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); - result.append_fmt( "\n\tSpecs : %S", Specs ? Specs->to_string() : "Null" ); - result.append_fmt( "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); - result.append_fmt( "\n\tParams : %S", Params ? Params->to_string() : "Null" ); - result.append_fmt( "\n\tBody : %S", Body ? Body->debug_str() : "Null" ); - break; + case CT_Function_Fwd: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Function_Fwd : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tAttributes: %S", self->Attributes ? strbuilder_to_str( code_to_strbuilder(self->Attributes) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tSpecs : %S", self->Specs ? strbuilder_to_str( code_to_strbuilder(self->Specs)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tReturnType: %S", self->ReturnType ? strbuilder_to_str( code_to_strbuilder(self->ReturnType)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tParams : %S", self->Params ? strbuilder_to_str( code_to_strbuilder(self->Params)) : txt("Null") ); + break; - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); - result.append_fmt( "\n\tSpecs : %S", Specs ? Specs->to_string() : "Null" ); - result.append_fmt( "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); - result.append_fmt( "\n\tParams : %S", Params ? Params->to_string() : "Null" ); - break; + case CT_Module: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + break; - case Module : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - break; + case CT_Operator: + case CT_Operator_Member: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Operator : - case Operator_Member : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tAttributes: %S", self->Attributes ? strbuilder_to_str( code_to_strbuilder(self->Attributes) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tSpecs : %S", self->Specs ? strbuilder_to_str( code_to_strbuilder(self->Specs)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tReturnType: %S", self->ReturnType ? strbuilder_to_str( code_to_strbuilder(self->ReturnType)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tParams : %S", self->Params ? strbuilder_to_str( code_to_strbuilder(self->Params)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tBody : %S", self->Body ? code_debug_str(self->Body) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tOp : %S", operator_to_str( self->Op ) ); + break; - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); - result.append_fmt( "\n\tSpecs : %S", Specs ? Specs->to_string() : "Null" ); - result.append_fmt( "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); - result.append_fmt( "\n\tParams : %S", Params ? Params->to_string() : "Null" ); - result.append_fmt( "\n\tBody : %S", Body ? Body->debug_str() : "Null" ); - result.append_fmt( "\n\tOp : %S", to_str( Op ) ); - break; + case CT_Operator_Fwd: + case CT_Operator_Member_Fwd: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Operator_Fwd : - case Operator_Member_Fwd : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tAttributes: %S", self->Attributes ? strbuilder_to_str( code_to_strbuilder(self->Attributes) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tSpecs : %S", self->Specs ? strbuilder_to_str( code_to_strbuilder(self->Specs) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tReturnType: %S", self->ReturnType ? strbuilder_to_str( code_to_strbuilder(self->ReturnType) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tParams : %S", self->Params ? strbuilder_to_str( code_to_strbuilder(self->Params) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tOp : %S", operator_to_str( self->Op ) ); + break; - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); - result.append_fmt( "\n\tSpecs : %S", Specs ? Specs->to_string() : "Null" ); - result.append_fmt( "\n\tReturnType: %S", ReturnType ? ReturnType->to_string() : "Null" ); - result.append_fmt( "\n\tParams : %S", Params ? Params->to_string() : "Null" ); - result.append_fmt( "\n\tOp : %S", to_str( Op ) ); - break; + case CT_Operator_Cast: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Operator_Cast : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tSpecs : %S", self->Specs ? strbuilder_to_str( code_to_strbuilder(self->Specs)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tValueType : %S", self->ValueType ? strbuilder_to_str( code_to_strbuilder(self->ValueType)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tBody : %S", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tSpecs : %S", Specs ? Specs->to_string() : "Null" ); - result.append_fmt( "\n\tValueType : %S", ValueType ? ValueType->to_string() : "Null" ); - result.append_fmt( "\n\tBody : %S", Body ? Body->debug_str() : "Null" ); - break; + case CT_Operator_Cast_Fwd: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - case Operator_Cast_Fwd : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tSpecs : %S", self->Specs ? strbuilder_to_str( code_to_strbuilder(self->Specs)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tValueType : %S", self->ValueType ? strbuilder_to_str( code_to_strbuilder(self->ValueType)) : txt("Null") ); + break; - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tSpecs : %S", Specs ? Specs->to_string() : "Null" ); - result.append_fmt( "\n\tValueType : %S", ValueType ? ValueType->to_string() : "Null" ); - break; + case CT_Parameters: + strbuilder_append_fmt( result, "\n\tNumEntries: %d", self->NumEntries ); + strbuilder_append_fmt( result, "\n\tLast : %S", self->Last->Name ); + strbuilder_append_fmt( result, "\n\tNext : %S", self->Next->Name ); + strbuilder_append_fmt( result, "\n\tValueType : %S", self->ValueType ? strbuilder_to_str( code_to_strbuilder(self->ValueType)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tValue : %S", self->Value ? strbuilder_to_str( code_to_strbuilder(self->Value)) : txt("Null") ); + break; - case Parameters : - result.append_fmt( "\n\tNumEntries: %d", NumEntries ); - if ( Last ) - result.append_fmt( "\n\tLast : %S", Last->Name ); - if ( Next ) - result.append_fmt( "\n\tNext : %S", Next->Name ); - result.append_fmt( "\n\tValueType : %S", ValueType ? ValueType->to_string() : "Null" ); - result.append_fmt( "\n\tValue : %S", Value ? Value->to_string() : "Null" ); - break; - - case Specifiers : + case CT_Specifiers: { - result.append_fmt( "\n\tNumEntries: %d", NumEntries ); - result.append( "\n\tArrSpecs: " ); + strbuilder_append_fmt( result, "\n\tNumEntries: %d", self->NumEntries ); + strbuilder_append_str( result, txt("\n\tArrSpecs: ") ); s32 idx = 0; - s32 left = NumEntries; + s32 left = self->NumEntries; while ( left-- ) { - StrC spec = ESpecifier::to_str( ArrSpecs[ idx ] ); - result.append_fmt( "%.*s, ", spec.Len, spec.Ptr ); + Str spec = spec_to_str( self->ArrSpecs[idx] ); + strbuilder_append_fmt( result, "%.*s, ", spec.Len, spec.Ptr ); idx++; } - result.append_fmt( "\n\tNextSpecs: %S", NextSpecs ? NextSpecs->debug_str() : "Null" ); + strbuilder_append_fmt( result, "\n\tNextSpecs: %S", self->NextSpecs ? code_debug_str(self->NextSpecs) : txt("Null") ); } break; - case Template : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + case CT_Template: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - result.append_fmt( "\n\tParams : %S", Params ? Params->to_string() : "Null" ); - result.append_fmt( "\n\tDeclaration: %S", Declaration ? Declaration->to_string() : "Null" ); - break; + strbuilder_append_fmt( result, "\n\tParams : %S", self->Params ? strbuilder_to_str( code_to_strbuilder(self->Params)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tDeclaration: %S", self->Declaration ? strbuilder_to_str( code_to_strbuilder(self->Declaration)) : txt("Null") ); + break; - case Typedef : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + case CT_Typedef: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tUnderlyingType: %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); - break; + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tUnderlyingType: %S", self->UnderlyingType ? strbuilder_to_str( code_to_strbuilder(self->UnderlyingType)) : txt("Null") ); + break; - case Typename : - result.append_fmt( "\n\tAttributes : %S", Attributes ? Attributes->to_string() : "Null" ); - result.append_fmt( "\n\tSpecs : %S", Specs ? Specs->to_string() : "Null" ); - result.append_fmt( "\n\tReturnType : %S", ReturnType ? ReturnType->to_string() : "Null" ); - result.append_fmt( "\n\tParams : %S", Params ? Params->to_string() : "Null" ); - result.append_fmt( "\n\tArrExpr : %S", ArrExpr ? ArrExpr->to_string() : "Null" ); - break; + case CT_Typename: + strbuilder_append_fmt( result, "\n\tAttributes : %S", self->Attributes ? strbuilder_to_str( code_to_strbuilder(self->Attributes) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tSpecs : %S", self->Specs ? strbuilder_to_str( code_to_strbuilder(self->Specs)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tReturnType : %S", self->ReturnType ? strbuilder_to_str( code_to_strbuilder(self->ReturnType)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tParams : %S", self->Params ? strbuilder_to_str( code_to_strbuilder(self->Params)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tArrExpr : %S", self->ArrExpr ? strbuilder_to_str( code_to_strbuilder(self->ArrExpr)) : txt("Null") ); + break; - case Union : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + case CT_Union: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - result.append_fmt( "\n\tAttributes: %S", Attributes ? Attributes->to_string() : "Null" ); - result.append_fmt( "\n\tBody : %S", Body ? Body->debug_str() : "Null" ); - break; + strbuilder_append_fmt( result, "\n\tAttributes: %S", self->Attributes ? strbuilder_to_str( code_to_strbuilder(self->Attributes) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tBody : %S", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; - case Using : - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + case CT_Using: + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tAttributes : %S", Attributes ? Attributes->to_string() : "Null" ); - result.append_fmt( "\n\tUnderlyingType: %S", UnderlyingType ? UnderlyingType->to_string() : "Null" ); - break; + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tAttributes : %S", self->Attributes ? strbuilder_to_str( code_to_strbuilder(self->Attributes) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tUnderlyingType: %S", self->UnderlyingType ? strbuilder_to_str( code_to_strbuilder(self->UnderlyingType)) : txt("Null") ); + break; - case Variable : + case CT_Variable: - if ( Parent && Parent->Type == Variable ) + if ( self->Parent && self->Parent->Type == CT_Variable ) { // Its a NextVar - result.append_fmt( "\n\tSpecs : %S", Specs ? Specs->to_string() : "Null" ); - result.append_fmt( "\n\tValue : %S", Value ? Value->to_string() : "Null" ); - result.append_fmt( "\n\tBitfieldSize: %S", BitfieldSize ? BitfieldSize->to_string() : "Null" ); - result.append_fmt( "\n\tNextVar : %S", NextVar ? NextVar->debug_str() : "Null" ); + strbuilder_append_fmt( result, "\n\tSpecs : %S", self->Specs ? strbuilder_to_str( code_to_strbuilder(self->Specs)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tValue : %S", self->Value ? strbuilder_to_str( code_to_strbuilder(self->Value)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tBitfieldSize: %S", self->BitfieldSize ? strbuilder_to_str( code_to_strbuilder(self->BitfieldSize)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tNextVar : %S", self->NextVar ? code_debug_str(self->NextVar) : txt("Null") ); break; } - if ( Prev ) - result.append_fmt( "\n\tPrev: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); - if ( Next ) - result.append_fmt( "\n\tNext: %S %S", Prev->type_str(), Prev->Name ? Prev->Name : "Null" ); + if ( self->Prev ) + strbuilder_append_fmt( result, "\n\tPrev: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + strbuilder_append_fmt( result, "\n\tNext: %S %S", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); - result.append_fmt( "\n\tInlineCmt : %S", InlineCmt ? InlineCmt->Content : "Null" ); - result.append_fmt( "\n\tAttributes : %S", Attributes ? Attributes->to_string() : "Null" ); - result.append_fmt( "\n\tSpecs : %S", Specs ? Specs->to_string() : "Null" ); - result.append_fmt( "\n\tValueType : %S", ValueType ? ValueType->to_string() : "Null" ); - result.append_fmt( "\n\tBitfieldSize: %S", BitfieldSize ? BitfieldSize->to_string() : "Null" ); - result.append_fmt( "\n\tValue : %S", Value ? Value->to_string() : "Null" ); - result.append_fmt( "\n\tNextVar : %S", NextVar ? NextVar->debug_str() : "Null" ); - break; + strbuilder_append_fmt( result, "\n\tInlineCmt : %S", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + strbuilder_append_fmt( result, "\n\tAttributes : %S", self->Attributes ? strbuilder_to_str( code_to_strbuilder(self->Attributes) ) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tSpecs : %S", self->Specs ? strbuilder_to_str( code_to_strbuilder(self->Specs)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tValueType : %S", self->ValueType ? strbuilder_to_str( code_to_strbuilder(self->ValueType)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tBitfieldSize: %S", self->BitfieldSize ? strbuilder_to_str( code_to_strbuilder(self->BitfieldSize)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tValue : %S", self->Value ? strbuilder_to_str( code_to_strbuilder(self->Value)) : txt("Null") ); + strbuilder_append_fmt( result, "\n\tNextVar : %S", self->NextVar ? code_debug_str(self->NextVar) : txt("Null") ); + break; } + return strbuilder_to_str( * result ); +} + +Code code_duplicate(Code self) +{ + Code result = make_code(); + + void* mem_result = rcast(void*, cast(AST*, result)); + void* mem_self = rcast(void*, cast(AST*, self)); + mem_copy( mem_result, mem_self, sizeof( AST ) ); + + result->Parent = NullCode; return result; } -AST* AST::duplicate() +StrBuilder code_to_strbuilder(Code self) { - using namespace ECode; - - AST* result = make_code().ast; - - mem_copy( result, this, sizeof( AST ) ); - - result->Parent = nullptr; + StrBuilder result = strbuilder_make_str( _ctx->Allocator_Temp, txt("") ); + code_to_strbuilder_ptr( self, & result ); return result; } -String AST::to_string() +void code_to_strbuilder_ptr( Code self, StrBuilder* result ) { - local_persist thread_local char SerializationLevel = 0; + GEN_ASSERT(self != nullptr); + local_persist thread_local + char SerializationLevel = 0; - // TODO : Need to refactor so that intermeidate strings are freed conviently. - String result = String::make( GlobalAllocator, "" ); - - switch ( Type ) + switch ( self->Type ) { - using namespace ECode; - - case Invalid : -#ifdef GEN_DONT_ALLOW_INVALID_CODE - log_failure( "Attempted to serialize invalid code! - %S", Parent ? Parent->debug_str() : Name ); -#else - result.append_fmt( "Invalid Code!" ); -#endif - break; - - case NewLine : - result.append( "\n" ); - break; - - case Untyped : - case Execution : - case Comment : - case PlatformAttributes : - result.append( Content ); - break; - - case Access_Private : - case Access_Protected : - case Access_Public : - result.append( Name ); - break; - - case Class : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - result.append( "class " ); - - if ( Attributes ) - { - result.append_fmt( "%S ", Attributes->to_string() ); - } - - if ( ParentType ) - { - char const* access_level = to_str( ParentAccess ); - - result.append_fmt( "%S : %s %S", Name, access_level, ParentType ); - - CodeType interface = ParentType->Next->cast< CodeType >(); - if ( interface ) - result.append( "\n" ); - - while ( interface ) - { - result.append_fmt( ", %S", interface.to_string() ); - interface = interface->Next ? interface->Next->cast< CodeType >() : Code { nullptr }; - } - } - else if ( Name ) - { - result.append( Name ); - } - - if ( InlineCmt ) - { - result.append_fmt( " // %S", InlineCmt->Content ); - } - - result.append_fmt( "\n{\n%S\n}", Body->to_string() ); - - if ( Parent == nullptr || ( Parent->Type != ECode::Typedef && Parent->Type != ECode::Variable ) ) - result.append( ";\n" ); - } + case CT_Invalid: + #ifdef GEN_DONT_ALLOW_INVALID_CODE + log_failure("Attempted to serialize invalid code! - %S", Parent ? Parent->code_debug_str() : Name ); + #else + strbuilder_append_fmt( result, "Invalid Code!" ); + #endif break; - case Class_Fwd : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - if ( Attributes ) - result.append_fmt( "class %S %S", Attributes->to_string(), Name ); - - else - result.append_fmt( "class %S", Name ); - - // Check if it can have an end-statement - if ( Parent == nullptr || ( Parent->Type != ECode::Typedef && Parent->Type != ECode::Variable ) ) - { - if ( InlineCmt ) - result.append_fmt( "; // %S\n", InlineCmt->Content ); - else - result.append( ";\n" ); - } - } + case CT_NewLine: + strbuilder_append_str( result, txt("\n")); break; - case Constructor : - { - result.append( Parent->Name ); - - if ( Params ) - result.append_fmt( "( %S )", Params->to_string() ); - else - result.append( "(void)" ); - - if ( InitializerList ) - result.append_fmt( " : %S", InitializerList->to_string() ); - - if ( InlineCmt ) - result.append_fmt( " // %S", InlineCmt->Content ); - - result.append_fmt( "\n{\n%S\n}\n", Body->to_string() ); - } + case CT_Untyped: + case CT_Execution: + case CT_Comment: + case CT_PlatformAttributes: + strbuilder_append_str( result, self->Content ); break; - case Constructor_Fwd : - { - result.append( Parent->Name ); - - if ( Params ) - result.append_fmt( "( %S )", Params->to_string() ); - else - { - if ( InlineCmt ) - result.append_fmt( "(void); // %S\n", InlineCmt->Content ); - else - result.append( "(void);\n" ); - } - } + case CT_Access_Private: + case CT_Access_Protected: + case CT_Access_Public: + strbuilder_append_str( result, self->Name ); break; - case Destructor : - { - if ( Specs ) - { - CodeSpecifiers specs = Specs->cast< CodeSpecifiers >(); - - if ( specs.has( ESpecifier::Virtual ) ) - result.append_fmt( "virtual ~%S()", Parent->Name ); - else - result.append_fmt( "~%S()", Parent->Name ); - } - else - result.append_fmt( "~%S()", Parent->Name ); - - result.append_fmt( "\n{\n%S\n}\n", Body->to_string() ); - } + case CT_Class: + class_to_strbuilder_def(cast(CodeClass, self), result ); break; - case Destructor_Fwd : - { - if ( Specs ) - { - CodeSpecifiers specs = Specs->cast< CodeSpecifiers >(); - - if ( specs.has( ESpecifier::Virtual ) ) - result.append_fmt( "virtual ~%S();\n", Parent->Name ); - else - result.append_fmt( "~%S()", Parent->Name ); - - if ( specs.has( ESpecifier::Pure ) ) - result.append( " = 0;" ); - } - else - result.append_fmt( "~%S();", Parent->Name ); - - if ( InlineCmt ) - result.append_fmt( " %S", InlineCmt->Content ); - else - result.append( "\n" ); - } + case CT_Class_Fwd: + class_to_strbuilder_fwd(cast(CodeClass, self), result ); break; - case Enum : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - if ( Attributes || UnderlyingType ) - { - result.append( "enum " ); - - if ( Attributes ) - result.append_fmt( "%S ", Attributes->to_string() ); - - if ( UnderlyingType ) - result.append_fmt( "%S : %S\n{\n%S\n}", Name, UnderlyingType->to_string(), Body->to_string() ); - - else - result.append_fmt( "%S\n{\n%S\n}", Name, Body->to_string() ); - } - else - result.append_fmt( "enum %S\n{\n%S\n}", Name, Body->to_string() ); - - if ( Parent == nullptr || ( Parent->Type != ECode::Typedef && Parent->Type != ECode::Variable ) ) - result.append( ";\n" ); - } + case CT_Constructor: + constructor_to_strbuilder_def(cast(CodeConstructor, self), result ); break; - case Enum_Fwd : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - if ( Attributes ) - result.append_fmt( "%S ", Attributes->to_string() ); - - result.append_fmt( "enum %S : %S", Name, UnderlyingType->to_string() ); - - if ( Parent == nullptr || ( Parent->Type != ECode::Typedef && Parent->Type != ECode::Variable ) ) - { - if ( InlineCmt ) - result.append_fmt( "; %S", InlineCmt->Content ); - else - result.append( ";\n" ); - } - } + case CT_Constructor_Fwd: + constructor_to_strbuilder_fwd(cast(CodeConstructor, self), result ); break; - case Enum_Class : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - if ( Attributes || UnderlyingType ) - { - result.append( "enum class " ); - - if ( Attributes ) - { - result.append_fmt( "%S ", Attributes->to_string() ); - } - - if ( UnderlyingType ) - { - result.append_fmt( "%S : %S\n{\n%S\n}", Name, UnderlyingType->to_string(), Body->to_string() ); - } - else - { - result.append_fmt( "%S\n{\n%S\n}", Name, Body->to_string() ); - } - } - else - { - result.append_fmt( "enum class %S\n{\n%S\n}", Body->to_string() ); - } - - if ( Parent == nullptr || ( Parent->Type != ECode::Typedef && Parent->Type != ECode::Variable ) ) - result.append( ";\n" ); - } + case CT_Destructor: + destructor_to_strbuilder_def(cast(CodeDestructor, self), result ); break; - case Enum_Class_Fwd : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - result.append( "enum class " ); - - if ( Attributes ) - result.append_fmt( "%S ", Attributes->to_string() ); - - result.append_fmt( "%S : %S", Name, UnderlyingType->to_string() ); - - if ( Parent == nullptr || ( Parent->Type != ECode::Typedef && Parent->Type != ECode::Variable ) ) - { - if ( InlineCmt ) - result.append_fmt( "; %S", InlineCmt->Content ); - else - result.append( ";\n" ); - } - } + case CT_Destructor_Fwd: + destructor_to_strbuilder_fwd(cast(CodeDestructor, self), result ); break; - case Export_Body : - { - result.append_fmt( "export\n{\n" ); - - Code curr = { this }; - s32 left = NumEntries; - while ( left-- ) - { - result.append_fmt( "%S", curr.to_string() ); - ++curr; - } - - result.append_fmt( "};\n" ); - } + case CT_Enum: + enum_to_strbuilder_def(cast(CodeEnum, self), result ); break; - case Extern_Linkage : - result.append_fmt( "extern \"%S\"\n{\n%S\n}\n", Name, Body->to_string() ); - break; - - case Friend : - result.append_fmt( "friend %S", Declaration->to_string() ); - - if ( result[ result.length() - 1 ] != ';' ) - { - result.append( ";" ); - } - - if ( InlineCmt ) - result.append_fmt( " %S", InlineCmt->Content ); - else - result.append( "\n" ); - break; - - case Function : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export" ); - - if ( Attributes ) - result.append_fmt( " %S ", Attributes->to_string() ); - - if ( Specs ) - { - for ( SpecifierT spec : Specs->cast< CodeSpecifiers >() ) - { - if ( ! ESpecifier::is_trailing( spec ) ) - { - StrC spec_str = ESpecifier::to_str( spec ); - result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr ); - } - } - } - - if ( Attributes || Specs ) - result.append( "\n" ); - - if ( ReturnType ) - result.append_fmt( "%S %S(", ReturnType->to_string(), Name ); - - else - result.append_fmt( "%S(", Name ); - - if ( Params ) - result.append_fmt( "%S)", Params->to_string() ); - - else - result.append( ")" ); - - if ( Specs ) - { - for ( SpecifierT spec : Specs->cast< CodeSpecifiers >() ) - { - if ( ESpecifier::is_trailing( spec ) ) - { - StrC spec_str = ESpecifier::to_str( spec ); - result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr ); - } - } - } - - result.append_fmt( "\n{\n%S\n}\n", Body->to_string() ); - } + case CT_Enum_Fwd: + enum_to_strbuilder_fwd(cast(CodeEnum, self), result ); break; - case Function_Fwd : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - if ( Attributes ) - result.append_fmt( "%S ", Attributes->to_string() ); - - if ( Specs ) - { - for ( SpecifierT spec : Specs->cast< CodeSpecifiers >() ) - { - if ( ! ESpecifier::is_trailing( spec ) ) - { - StrC spec_str = ESpecifier::to_str( spec ); - result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr ); - } - } - } - - if ( Attributes || Specs ) - { - result.append( "\n" ); - } - - if ( ReturnType ) - result.append_fmt( "%S %S(", ReturnType->to_string(), Name ); - - else - result.append_fmt( "%S(", Name ); - - if ( Params ) - result.append_fmt( "%S)", Params->to_string() ); - - else - result.append( ")" ); - - if ( Specs ) - { - for ( SpecifierT spec : Specs->cast< CodeSpecifiers >() ) - { - if ( ESpecifier::is_trailing( spec ) ) - { - StrC spec_str = ESpecifier::to_str( spec ); - result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr ); - } - } - } - - if ( InlineCmt ) - result.append_fmt( "; %S", InlineCmt->Content ); - else - result.append( ";\n" ); - } + case CT_Enum_Class: + enum_to_strbuilder_class_def(cast(CodeEnum, self), result ); break; - case Module : - if ( ( ( u32( ModuleFlag::Export ) & u32( ModuleFlags ) ) == u32( ModuleFlag::Export ) ) ) - result.append( "export " ); - - if ( ( ( u32( ModuleFlag::Import ) & u32( ModuleFlags ) ) == u32( ModuleFlag::Import ) ) ) - result.append( "import " ); - - result.append_fmt( "%S;\n", Name ); - break; - - case Namespace : - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - result.append_fmt( "namespace %S\n{\n%S\n}\n", Name, Body->to_string() ); - break; - - case Operator : - case Operator_Member : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - if ( Attributes ) - result.append_fmt( "%S ", Attributes->to_string() ); - - if ( Attributes ) - result.append_fmt( "%S ", Attributes->to_string() ); - - if ( Specs ) - { - for ( SpecifierT spec : Specs->cast< CodeSpecifiers >() ) - { - if ( ! ESpecifier::is_trailing( spec ) ) - { - StrC spec_str = ESpecifier::to_str( spec ); - result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr ); - } - } - } - - if ( Attributes || Specs ) - { - result.append( "\n" ); - } - - if ( ReturnType ) - result.append_fmt( "%S %S (", ReturnType->to_string(), Name ); - - if ( Params ) - result.append_fmt( "%S)", Params->to_string() ); - - else - result.append( ")" ); - - if ( Specs ) - { - for ( SpecifierT spec : Specs->cast< CodeSpecifiers >() ) - { - if ( ESpecifier::is_trailing( spec ) ) - { - StrC spec_str = ESpecifier::to_str( spec ); - result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr ); - } - } - } - - result.append_fmt( "\n{\n%S\n}\n", Body->to_string() ); - } + case CT_Enum_Class_Fwd: + enum_to_strbuilder_class_fwd(cast(CodeEnum, self), result ); break; - case Operator_Fwd : - case Operator_Member_Fwd : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - if ( Attributes ) - result.append_fmt( "%S\n", Attributes->to_string() ); - - if ( Specs ) - { - for ( SpecifierT spec : Specs->cast< CodeSpecifiers >() ) - { - if ( ! ESpecifier::is_trailing( spec ) ) - { - StrC spec_str = ESpecifier::to_str( spec ); - result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr ); - } - } - } - - if ( Attributes || Specs ) - { - result.append( "\n" ); - } - - result.append_fmt( "%S %S (", ReturnType->to_string(), Name ); - - if ( Params ) - result.append_fmt( "%S)", Params->to_string() ); - - else - result.append_fmt( ")" ); - - if ( Specs ) - { - for ( SpecifierT spec : Specs->cast< CodeSpecifiers >() ) - { - if ( ESpecifier::is_trailing( spec ) ) - { - StrC spec_str = ESpecifier::to_str( spec ); - result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr ); - } - } - } - - if ( InlineCmt ) - result.append_fmt( "; %S", InlineCmt->Content ); - else - result.append( ";\n" ); - } + case CT_Export_Body: + body_to_strbuilder_export(cast(CodeBody, self), result ); break; - case Operator_Cast : - { - if ( Specs ) - { - // TODO : Add support for specifies before the operator keyword - - if ( Name && Name.length() ) - result.append_fmt( "%Soperator %S()", Name, ValueType->to_string() ); - else - result.append_fmt( "operator %S()", ValueType->to_string() ); - - for ( SpecifierT spec : Specs->cast< CodeSpecifiers >() ) - { - if ( ESpecifier::is_trailing( spec ) ) - { - StrC spec_str = ESpecifier::to_str( spec ); - result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr ); - } - } - - result.append_fmt( "\n{\n%S\n}\n", Body->to_string() ); - break; - } - - if ( Name && Name.length() ) - result.append_fmt( "%Soperator %S()\n{\n%S\n}\n", Name, ValueType->to_string(), Body->to_string() ); - else - result.append_fmt( "operator %S()\n{\n%S\n}\n", ValueType->to_string(), Body->to_string() ); - } + case CT_Extern_Linkage: + extern_to_strbuilder(cast(CodeExtern, self), result ); break; - case Operator_Cast_Fwd : - if ( Specs ) - { - // TODO : Add support for specifies before the operator keyword - - result.append_fmt( "operator %S()", ValueType->to_string() ); - - for ( SpecifierT spec : Specs->cast< CodeSpecifiers >() ) - { - if ( ESpecifier::is_trailing( spec ) ) - { - StrC spec_str = ESpecifier::to_str( spec ); - result.append_fmt( " %*s", spec_str.Len, spec_str.Ptr ); - } - } - - if ( InlineCmt ) - result.append_fmt( "; %S", InlineCmt->Content ); - else - result.append( ";\n" ); - break; - } - - if ( InlineCmt ) - result.append_fmt( "operator %S(); %S", ValueType->to_string() ); - else - result.append_fmt( "operator %S();\n", ValueType->to_string() ); - break; - - case Parameters : - { - if ( ValueType == nullptr ) - { - result.append_fmt( "%S", Name ); - break; - } - - if ( Name ) - result.append_fmt( "%S %S", ValueType->to_string(), Name ); - - else - result.append_fmt( "%S", ValueType->to_string() ); - - if ( Value ) - result.append_fmt( "= %S", Value->to_string() ); - - if ( NumEntries - 1 > 0 ) - { - for ( CodeParam param : CodeParam { ( AST_Param* )Next } ) - { - result.append_fmt( ", %S", param.to_string() ); - } - } - } - break; - case Preprocess_Define : - result.append_fmt( "#define %S %S\n", Name, Content ); - break; - - case Preprocess_If : - result.append_fmt( "#if %S\n", Content ); - break; - - case Preprocess_IfDef : - result.append_fmt( "#ifdef %S\n", Content ); - break; - - case Preprocess_IfNotDef : - result.append_fmt( "#ifndef %S\n", Content ); - break; - - case Preprocess_Include : - result.append_fmt( "#include %S\n", Content ); - break; - - case Preprocess_ElIf : - result.append_fmt( "#elif %S\n", Content ); - break; - - case Preprocess_Else : - result.append_fmt( "#else\n" ); - break; - - case Preprocess_EndIf : - result.append_fmt( "#endif\n" ); - break; - - case Preprocess_Pragma : - result.append_fmt( "#pragma %S\n", Content ); - break; - - case Specifiers : - { - s32 idx = 0; - s32 left = NumEntries; - while ( left-- ) - { - StrC spec = ESpecifier::to_str( ArrSpecs[ idx ] ); - result.append_fmt( "%.*s ", spec.Len, spec.Ptr ); - idx++; - } - } + case CT_Friend: + friend_to_strbuilder_ref(cast(CodeFriend, self), result ); break; - case Struct : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - result.append( "struct " ); - - if ( Attributes ) - { - result.append_fmt( "%S ", Attributes->to_string() ); - } - - if ( ParentType ) - { - char const* access_level = to_str( ParentAccess ); - - result.append_fmt( "%S : %s %S", Name, access_level, ParentType ); - - CodeType interface = ParentType->Next->cast< CodeType >(); - if ( interface ) - result.append( "\n" ); - - while ( interface ) - { - result.append_fmt( ", %S", interface.to_string() ); - interface = interface->Next ? interface->Next->cast< CodeType >() : Code { nullptr }; - } - } - else if ( Name ) - { - result.append( Name ); - } - - if ( InlineCmt ) - { - result.append_fmt( " // %S", InlineCmt->Content ); - } - - result.append_fmt( "\n{\n%S\n}", Body->to_string() ); - - if ( Parent == nullptr || ( Parent->Type != ECode::Typedef && Parent->Type != ECode::Variable ) ) - result.append( ";\n" ); - } + case CT_Function: + fn_to_strbuilder_def(cast(CodeFn, self), result ); break; - case Struct_Fwd : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - if ( Attributes ) - result.append_fmt( "struct %S %S", Attributes->to_string(), Name ); - - else - result.append_fmt( "struct %S", Name ); - - if ( Parent == nullptr || ( Parent->Type != ECode::Typedef && Parent->Type != ECode::Variable ) ) - { - if ( InlineCmt ) - result.append_fmt( "; %S", InlineCmt->Content ); - else - result.append( ";\n" ); - } - } + case CT_Function_Fwd: + fn_to_strbuilder_fwd(cast(CodeFn, self), result ); break; - case Template : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - if ( Params ) - result.append_fmt( "template< %S >\n%S", Params->to_string(), Declaration->to_string() ); - else - result.append_fmt( "template<>\n%S", Declaration->to_string() ); - } + case CT_Module: + module_to_strbuilder_ref(cast(CodeModule, self), result ); break; - case Typedef : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - result.append( "typedef " ); - - // Determines if the typedef is a function typename - if ( UnderlyingType->ReturnType ) - result.append( UnderlyingType->to_string() ); - else - result.append_fmt( "%S %S", UnderlyingType->to_string(), Name ); - - if ( UnderlyingType->Type == Typename && UnderlyingType->ArrExpr ) - { - result.append_fmt( "[ %S ];", UnderlyingType->ArrExpr->to_string() ); - - AST* next_arr_expr = UnderlyingType->ArrExpr->Next; - while ( next_arr_expr ) - { - result.append_fmt( "[ %S ];", next_arr_expr->to_string() ); - next_arr_expr = next_arr_expr->Next; - } - } - else - { - result.append( ";" ); - } - - if ( InlineCmt ) - result.append_fmt( " %S", InlineCmt->Content ); - else - result.append( "\n" ); - } + case CT_Namespace: + namespace_to_strbuilder_ref(cast(CodeNS, self), result ); break; - case Typename : - { -#if GEN_USE_NEW_TYPENAME_PARSING - if ( ReturnType && Params ) - { - if ( Attributes ) - result.append_fmt( "%S ", Attributes->to_string() ); - else - { - if ( Specs ) - result.append_fmt( "%S ( %S ) ( %S ) %S", ReturnType->to_string(), Name, Params->to_string(), Specs->to_string() ); - else - result.append_fmt( "%S ( %S ) ( %S )", ReturnType->to_string(), Name, Params->to_string() ); - } - - break; - } -#else - if ( ReturnType && Params ) - { - if ( Attributes ) - result.append_fmt( "%S ", Attributes->to_string() ); - else - { - if ( Specs ) - result.append_fmt( "%S %S ( %S ) %S", ReturnType->to_string(), Name, Params->to_string(), Specs->to_string() ); - else - result.append_fmt( "%S %S ( %S )", ReturnType->to_string(), Name, Params->to_string() ); - } - - break; - } -#endif - - if ( Attributes ) - result.append_fmt( "%S ", Attributes->to_string() ); - - if ( Specs ) - result.append_fmt( "%S %S", Name, Specs->to_string() ); - else - result.append_fmt( "%S", Name ); - - if ( IsParamPack ) - result.append( "..." ); - } + case CT_Operator: + case CT_Operator_Member: + code_op_to_strbuilder_def(cast(CodeOperator, self), result ); break; - case Union : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - result.append( "union " ); - - if ( Attributes ) - result.append_fmt( "%S ", Attributes->to_string() ); - - if ( Name ) - { - result.append_fmt( "%S\n{\n%S\n}", Name, Body->to_string() ); - } - else - { - // Anonymous union - result.append_fmt( "\n{\n%S\n}", Body->to_string() ); - } - - if ( Parent == nullptr || ( Parent->Type != ECode::Typedef && Parent->Type != ECode::Variable ) ) - result.append( ";\n" ); - } + case CT_Operator_Fwd: + case CT_Operator_Member_Fwd: + code_op_to_strbuilder_fwd(cast(CodeOperator, self), result ); break; - case Using : - { - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - if ( Attributes ) - result.append_fmt( "%S ", Attributes->to_string() ); - - if ( UnderlyingType ) - { - result.append_fmt( "using %S = %S", Name, UnderlyingType->to_string() ); - - if ( UnderlyingType->ArrExpr ) - { - result.append_fmt( "[ %S ]", UnderlyingType->ArrExpr->to_string() ); - - AST* next_arr_expr = UnderlyingType->ArrExpr->Next; - while ( next_arr_expr ) - { - result.append_fmt( "[ %S ]", next_arr_expr->to_string() ); - next_arr_expr = next_arr_expr->Next; - } - } - - result.append( ";" ); - } - else - result.append_fmt( "using %S;", Name ); - - if ( InlineCmt ) - result.append_fmt( " %S\n", InlineCmt->Content ); - else - result.append( "\n" ); - } + case CT_Operator_Cast: + opcast_to_strbuilder_def(cast(CodeOpCast, self), result ); break; - case Using_Namespace : - if ( InlineCmt ) - result.append_fmt( "using namespace $S; %S", Name, InlineCmt->Content ); - else - result.append_fmt( "using namespace %s;\n", Name ); - break; - - case Variable : - { - if ( Parent && Parent->Type == Variable ) - { - // Its a comma-separated variable ( a NextVar ) - - if ( Specs ) - result.append_fmt( "%S ", Specs->to_string() ); - - result.append( Name ); - - if ( ArrExpr ) - { - result.append_fmt( "[ %S ]", ArrExpr->to_string() ); - - AST* next_arr_expr = ArrExpr->Next; - while ( next_arr_expr ) - { - result.append_fmt( "[ %S ]", next_arr_expr->to_string() ); - next_arr_expr = next_arr_expr->Next; - } - } - - if ( Value ) - result.append_fmt( " = %S", Value->to_string() ); - - // Keep the chain going... - if ( NextVar ) - result.append_fmt( ", %S", NextVar->to_string() ); - } - - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ) ) - result.append( "export " ); - - if ( Attributes || Specs ) - { - if ( Attributes ) - result.append_fmt( "%S ", Specs->to_string() ); - - if ( Specs ) - result.append_fmt( "%S\n", Specs->to_string() ); - - result.append_fmt( "%S %S", ValueType->to_string(), Name ); - - if ( ValueType->ArrExpr ) - { - result.append_fmt( "[ %S ]", ValueType->ArrExpr->to_string() ); - - AST* next_arr_expr = ValueType->ArrExpr->Next; - while ( next_arr_expr ) - { - result.append_fmt( "[ %S ]", next_arr_expr->to_string() ); - next_arr_expr = next_arr_expr->Next; - } - } - - if ( BitfieldSize ) - result.append_fmt( " : %S", BitfieldSize->to_string() ); - - if ( Value ) - result.append_fmt( " = %S", Value->to_string() ); - - if ( NextVar ) - result.append_fmt( ", %S", NextVar->to_string() ); - - if ( InlineCmt ) - result.append_fmt( "; %S", InlineCmt->Content ); - else - result.append( ";\n" ); - - break; - } - - if ( BitfieldSize ) - result.append_fmt( "%S %S : %S", ValueType->to_string(), Name, BitfieldSize->to_string() ); - - else if ( ValueType->ArrExpr ) - { - result.append_fmt( "%S %S[ %S ]", ValueType->to_string(), Name, ValueType->ArrExpr->to_string() ); - - AST* next_arr_expr = ValueType->ArrExpr->Next; - while ( next_arr_expr ) - { - result.append_fmt( "[ %S ]", next_arr_expr->to_string() ); - next_arr_expr = next_arr_expr->Next; - } - } - - else - result.append_fmt( "%S %S", ValueType->to_string(), Name ); - - if ( Value ) - result.append_fmt( " = %S", Value->to_string() ); - - if ( NextVar ) - result.append_fmt( ", %S", NextVar->to_string() ); - - result.append( ";" ); - - if ( InlineCmt ) - result.append_fmt( " %S", InlineCmt->Content ); - else - result.append( "\n" ); - } + case CT_Operator_Cast_Fwd: + opcast_to_strbuilder_fwd(cast(CodeOpCast, self), result ); break; - case Enum_Body : - case Class_Body : - case Extern_Linkage_Body : - case Function_Body : - case Global_Body : - case Namespace_Body : - case Struct_Body : - case Union_Body : - { - Code curr = Front->cast< Code >(); - s32 left = NumEntries; - while ( left-- ) - { - result.append_fmt( "%S", curr.to_string() ); - ++curr; - } - } + case CT_Parameters: + params_to_strbuilder_ref(cast(CodeParams, self), result ); + break; + + case CT_Preprocess_Define: + define_to_strbuilder_ref(cast(CodeDefine, self), result ); + break; + + case CT_Preprocess_If: + preprocess_to_strbuilder_if(cast(CodePreprocessCond, self), result ); + break; + + case CT_Preprocess_IfDef: + preprocess_to_strbuilder_ifdef(cast(CodePreprocessCond, self), result ); + break; + + case CT_Preprocess_IfNotDef: + preprocess_to_strbuilder_ifndef(cast(CodePreprocessCond, self), result ); + break; + + case CT_Preprocess_Include: + include_to_strbuilder_ref(cast(CodeInclude, self), result ); + break; + + case CT_Preprocess_ElIf: + preprocess_to_strbuilder_elif(cast(CodePreprocessCond, self), result ); + break; + + case CT_Preprocess_Else: + preprocess_to_strbuilder_else(cast(CodePreprocessCond, self), result ); + break; + + case CT_Preprocess_EndIf: + preprocess_to_strbuilder_endif(cast(CodePreprocessCond, self), result ); + break; + + case CT_Preprocess_Pragma: + pragma_to_strbuilder_ref(cast(CodePragma, self), result ); + break; + + case CT_Specifiers: + specifiers_to_strbuilder_ref(cast(CodeSpecifiers, self), result ); + break; + + case CT_Struct: + struct_to_strbuilder_def(cast(CodeStruct, self), result ); + break; + + case CT_Struct_Fwd: + struct_to_strbuilder_fwd(cast(CodeStruct, self), result ); + break; + + case CT_Template: + template_to_strbuilder_ref(cast(CodeTemplate, self), result ); + break; + + case CT_Typedef: + typedef_to_strbuilder_ref(cast(CodeTypedef, self), result ); + break; + + case CT_Typename: + typename_to_strbuilder_ref(cast(CodeTypename, self), result ); + break; + + case CT_Union: + union_to_strbuilder_def( cast(CodeUnion, self), result ); + break; + + case CT_Union_Fwd: + union_to_strbuilder_fwd( cast(CodeUnion, self), result ); + break; + + case CT_Using: + using_to_strbuilder_ref(cast(CodeUsing, self), result ); + break; + + case CT_Using_Namespace: + using_to_strbuilder_ns(cast(CodeUsing, self), result ); + break; + + case CT_Variable: + var_to_strbuilder_ref(cast(CodeVar, self), result ); + break; + + case CT_Enum_Body: + case CT_Class_Body: + case CT_Extern_Linkage_Body: + case CT_Function_Body: + case CT_Global_Body: + case CT_Namespace_Body: + case CT_Struct_Body: + case CT_Union_Body: + body_to_strbuilder_ref( cast(CodeBody, self), result ); break; } - - return result; } -bool AST::is_equal( AST* other ) +bool code_is_equal( Code self, Code other ) { - /* - AST values are either some u32 value, a cached string, or a pointer to another AST. +/* + AST values are either some u32 value, a cached string, or a pointer to another AST. - u32 values are compared by value. - Cached strings are compared by pointer. - AST nodes are compared with AST::is_equal. - */ + u32 values are compared by value. + Cached strings are compared by pointer. + AST nodes are compared with AST::is_equal. +*/ if ( other == nullptr ) { - log_fmt( "AST::is_equal: other is null\nAST: %S", debug_str() ); + log_fmt( "AST::is_equal: other is null\nAST: %S", code_debug_str(self) ); return false; } - if ( Type != other->Type ) + if ( self->Type != other->Type ) { - log_fmt( "AST::is_equal: Type check failure with other\nAST: %S\nOther: %S", debug_str(), other->debug_str() ); + log_fmt("AST::is_equal: Type check failure with other\nAST: %S\nOther: %S" + , code_debug_str(self) + , code_debug_str(other) + ); return false; } - switch ( Type ) + switch ( self->Type ) { - using namespace ECode; - -#define check_member_val( val ) \ - if ( val != other->val ) \ - { \ - log_fmt( \ - "\nAST::is_equal: Member - " #val \ - " failed\n" \ - "AST : %S\n" \ - "Other: %S\n", \ - debug_str(), \ - other->debug_str() \ - ); \ - \ - return false; \ + #define check_member_val( val ) \ + if ( self->val != other->val ) \ + { \ + log_fmt("\nAST::is_equal: Member - " #val " failed\n" \ + "AST : %S\n" \ + "Other: %S\n" \ + , code_debug_str(self) \ + ,code_debug_str(other) \ + ); \ + \ + return false; \ } -#define check_member_str( str ) \ - if ( str != other->str ) \ - { \ - log_fmt( \ - "\nAST::is_equal: Member string - " #str \ - " failed\n" \ - "AST : %S\n" \ - "Other: %S\n", \ - debug_str(), \ - other->debug_str() \ - ); \ - \ - return false; \ + #define check_member_str( str ) \ + if ( ! str_are_equal( self->str, other->str ) ) \ + { \ + log_fmt("\nAST::is_equal: Member string - "#str " failed\n" \ + "AST : %S\n" \ + "Other: %S\n" \ + , code_debug_str(self) \ + ,code_debug_str(other) \ + ); \ + \ + return false; \ } -#define check_member_content( content ) \ - if ( content != other->content ) \ - { \ - log_fmt( \ - "\nAST::is_equal: Member content - " #content \ - " failed\n" \ - "AST : %S\n" \ - "Other: %S\n", \ - debug_str(), \ - other->debug_str() \ - ); \ - \ - log_fmt( \ - "Content cannot be trusted to be unique with this check " \ - "so it must be verified by eye for now\n" \ - "AST Content:\n%S\n" \ - "Other Content:\n%S\n", \ - content.visualize_whitespace(), \ - other->content.visualize_whitespace() \ - ); \ + #define check_member_content( content ) \ + if ( ! str_are_equal( self->content, other->content )) \ + { \ + log_fmt("\nAST::is_equal: Member content - "#content " failed\n" \ + "AST : %S\n" \ + "Other: %S\n" \ + , code_debug_str(self) \ + , code_debug_str(other) \ + ); \ + \ + log_fmt("Content cannot be trusted to be unique with this check " \ + "so it must be verified by eye for now\n" \ + "AST Content:\n%S\n" \ + "Other Content:\n%S\n" \ + , str_visualize_whitespace(self->content, _ctx->Allocator_Temp) \ + , str_visualize_whitespace(other->content, _ctx->Allocator_Temp) \ + ); \ } -#define check_member_ast( ast ) \ - if ( ast ) \ - { \ - if ( other->ast == nullptr ) \ - { \ - log_fmt( \ - "\nAST::is_equal: Failed for member " #ast \ - " other equivalent param is null\n" \ - "AST : %s\n" \ - "Other: %s\n" \ - "For ast member: %s\n", \ - debug_str(), \ - other->debug_str(), \ - ast->debug_str() \ - ); \ - \ - return false; \ - } \ - \ - if ( ! ast->is_equal( other->ast ) ) \ - { \ - log_fmt( \ - "\nAST::is_equal: Failed for " #ast \ - "\n" \ - "AST : %S\n" \ - "Other: %S\n" \ - "For ast member: %S\n" \ - "other's ast member: %S\n", \ - debug_str(), \ - other->debug_str(), \ - ast->debug_str(), \ - other->ast->debug_str() \ - ); \ - \ - return false; \ - } \ + #define check_member_ast( ast ) \ + if ( self->ast ) \ + { \ + if ( other->ast == nullptr ) \ + { \ + log_fmt("\nAST::is_equal: Failed for member " #ast " other equivalent param is null\n" \ + "AST : %S\n" \ + "Other: %S\n" \ + "For ast member: %S\n" \ + , code_debug_str(self) \ + , code_debug_str(other) \ + , code_debug_str(self->ast) \ + ); \ + \ + return false; \ + } \ + \ + if ( ! code_is_equal(self->ast, other->ast ) ) \ + { \ + log_fmt( "\nAST::is_equal: Failed for " #ast"\n" \ + "AST : %S\n" \ + "Other: %S\n" \ + "For ast member: %S\n" \ + "other's ast member: %S\n" \ + , code_debug_str(self) \ + , code_debug_str(other) \ + , code_debug_str(self->ast) \ + , code_debug_str(other->ast) \ + ); \ + \ + return false; \ + } \ } - case NewLine : - case Access_Public : - case Access_Protected : - case Access_Private : - case Preprocess_Else : - case Preprocess_EndIf : + case CT_NewLine: + case CT_Access_Public: + case CT_Access_Protected: + case CT_Access_Private: + case CT_Preprocess_Else: + case CT_Preprocess_EndIf: return true; // Comments are not validated. - case Comment : + case CT_Comment: return true; - case Execution : - case PlatformAttributes : - case Untyped : + case CT_Execution: + case CT_PlatformAttributes: + case CT_Untyped: { check_member_content( Content ); - return true; } - case Class_Fwd : - case Struct_Fwd : + case CT_Class_Fwd: + case CT_Struct_Fwd: { check_member_str( Name ); check_member_ast( ParentType ); @@ -14007,8 +14107,8 @@ bool AST::is_equal( AST* other ) return true; } - case Class : - case Struct : + case CT_Class: + case CT_Struct: { check_member_val( ModuleFlags ); check_member_str( Name ); @@ -14020,7 +14120,7 @@ bool AST::is_equal( AST* other ) return true; } - case Constructor : + case CT_Constructor: { check_member_ast( InitializerList ); check_member_ast( Params ); @@ -14029,7 +14129,7 @@ bool AST::is_equal( AST* other ) return true; } - case Constructor_Fwd : + case CT_Constructor_Fwd: { check_member_ast( InitializerList ); check_member_ast( Params ); @@ -14037,7 +14137,7 @@ bool AST::is_equal( AST* other ) return true; } - case Destructor : + case CT_Destructor: { check_member_ast( Specs ); check_member_ast( Body ); @@ -14045,37 +14145,39 @@ bool AST::is_equal( AST* other ) return true; } - case Destructor_Fwd : + case CT_Destructor_Fwd: { check_member_ast( Specs ); return true; } - case Enum : - case Enum_Class : + case CT_Enum: + case CT_Enum_Class: { check_member_val( ModuleFlags ); check_member_str( Name ); check_member_ast( Attributes ); check_member_ast( UnderlyingType ); check_member_ast( Body ); + check_member_ast( UnderlyingTypeMacro ); return true; } - case Enum_Fwd : - case Enum_Class_Fwd : + case CT_Enum_Fwd: + case CT_Enum_Class_Fwd: { check_member_val( ModuleFlags ); check_member_str( Name ); check_member_ast( Attributes ); check_member_ast( UnderlyingType ); + check_member_ast( UnderlyingTypeMacro ); return true; } - case Extern_Linkage : + case CT_Extern_Linkage: { check_member_str( Name ); check_member_ast( Body ); @@ -14083,7 +14185,7 @@ bool AST::is_equal( AST* other ) return true; } - case Friend : + case CT_Friend: { check_member_str( Name ); check_member_ast( Declaration ); @@ -14091,7 +14193,7 @@ bool AST::is_equal( AST* other ) return true; } - case Function : + case CT_Function: { check_member_val( ModuleFlags ); check_member_str( Name ); @@ -14104,7 +14206,7 @@ bool AST::is_equal( AST* other ) return true; } - case Function_Fwd : + case CT_Function_Fwd: { check_member_val( ModuleFlags ); check_member_str( Name ); @@ -14116,7 +14218,7 @@ bool AST::is_equal( AST* other ) return true; } - case Module : + case CT_Module: { check_member_val( ModuleFlags ); check_member_str( Name ); @@ -14124,7 +14226,7 @@ bool AST::is_equal( AST* other ) return true; } - case Namespace : + case CT_Namespace: { check_member_val( ModuleFlags ); check_member_str( Name ); @@ -14133,8 +14235,8 @@ bool AST::is_equal( AST* other ) return true; } - case Operator : - case Operator_Member : + case CT_Operator: + case CT_Operator_Member: { check_member_val( ModuleFlags ); check_member_str( Name ); @@ -14147,8 +14249,8 @@ bool AST::is_equal( AST* other ) return true; } - case Operator_Fwd : - case Operator_Member_Fwd : + case CT_Operator_Fwd: + case CT_Operator_Member_Fwd: { check_member_val( ModuleFlags ); check_member_str( Name ); @@ -14160,7 +14262,7 @@ bool AST::is_equal( AST* other ) return true; } - case Operator_Cast : + case CT_Operator_Cast: { check_member_str( Name ); check_member_ast( Specs ); @@ -14170,7 +14272,7 @@ bool AST::is_equal( AST* other ) return true; } - case Operator_Cast_Fwd : + case CT_Operator_Cast_Fwd: { check_member_str( Name ); check_member_ast( Specs ); @@ -14179,73 +14281,69 @@ bool AST::is_equal( AST* other ) return true; } - case Parameters : + case CT_Parameters: { - if ( NumEntries > 1 ) + if ( self->NumEntries > 1 ) { - AST* curr = this; - AST* curr_other = other; - while ( curr != nullptr ) + Code curr = self; + Code curr_other = other; + while ( curr != nullptr ) { if ( curr ) { if ( curr_other == nullptr ) { - log_fmt( - "\nAST::is_equal: Failed for parameter, other equivalent param is null\n" - "AST : %S\n" - "Other: %S\n" - "For ast member: %S\n", - curr->debug_str() + log_fmt("\nAST::is_equal: Failed for parameter, other equivalent param is null\n" + "AST : %S\n" + "Other: %S\n" + "For ast member: %S\n" + , code_debug_str(curr) ); return false; } - if ( curr->Name != curr_other->Name ) + if ( str_are_equal(curr->Name, curr_other->Name) ) { - log_fmt( - "\nAST::is_equal: Failed for parameter name check\n" - "AST : %S\n" - "Other: %S\n" - "For ast member: %S\n" - "other's ast member: %S\n", - debug_str(), - other->debug_str(), - curr->debug_str(), - curr_other->debug_str() + log_fmt( "\nAST::is_equal: Failed for parameter name check\n" + "AST : %S\n" + "Other: %S\n" + "For ast member: %S\n" + "other's ast member: %S\n" + , code_debug_str(self) + , code_debug_str(other) + , code_debug_str(curr) + , code_debug_str(curr_other) ); return false; } - if ( curr->ValueType && ! curr->ValueType->is_equal( curr_other->ValueType ) ) + if ( curr->ValueType && ! code_is_equal(curr->ValueType, curr_other->ValueType) ) { - log_fmt( - "\nAST::is_equal: Failed for parameter value type check\n" - "AST : %S\n" - "Other: %S\n" - "For ast member: %S\n" - "other's ast member: %S\n", - debug_str(), - other->debug_str(), - curr->debug_str(), - curr_other->debug_str() + log_fmt( "\nAST::is_equal: Failed for parameter value type check\n" + "AST : %S\n" + "Other: %S\n" + "For ast member: %S\n" + "other's ast member: %S\n" + , code_debug_str(self) + , code_debug_str(other) + , code_debug_str(curr) + , code_debug_str(curr_other) ); return false; } - if ( curr->Value && ! curr->Value->is_equal( curr_other->Value ) ) + if ( curr->Value && ! code_is_equal(curr->Value, curr_other->Value) ) { - log_fmt( - "\nAST::is_equal: Failed for parameter value check\n" - "AST : %S\n" - "Other: %S\n" - "For ast member: %S\n" - "other's ast member: %S\n", - debug_str(), - other->debug_str(), - curr->debug_str(), - curr_other->debug_str() + log_fmt( "\nAST::is_equal: Failed for parameter value check\n" + "AST : %S\n" + "Other: %S\n" + "For ast member: %S\n" + "other's ast member: %S\n" + , code_debug_str(self) + , code_debug_str(other) + , code_debug_str(curr) + , code_debug_str(curr_other) ); return false; } @@ -14268,7 +14366,7 @@ bool AST::is_equal( AST* other ) return true; } - case Preprocess_Define : + case CT_Preprocess_Define: { check_member_str( Name ); check_member_content( Content ); @@ -14276,36 +14374,36 @@ bool AST::is_equal( AST* other ) return true; } - case Preprocess_If : - case Preprocess_IfDef : - case Preprocess_IfNotDef : - case Preprocess_ElIf : + case CT_Preprocess_If: + case CT_Preprocess_IfDef: + case CT_Preprocess_IfNotDef: + case CT_Preprocess_ElIf: { check_member_content( Content ); return true; } - case Preprocess_Include : - case Preprocess_Pragma : + case CT_Preprocess_Include: + case CT_Preprocess_Pragma: { check_member_content( Content ); return true; } - case Specifiers : + case CT_Specifiers: { check_member_val( NumEntries ); check_member_str( Name ); - for ( s32 idx = 0; idx < NumEntries; ++idx ) + for ( s32 idx = 0; idx < self->NumEntries; ++idx ) { check_member_val( ArrSpecs[ idx ] ); } return true; } - case Template : + case CT_Template: { check_member_val( ModuleFlags ); check_member_str( Name ); @@ -14315,7 +14413,7 @@ bool AST::is_equal( AST* other ) return true; } - case Typedef : + case CT_Typedef: { check_member_val( IsFunction ); check_member_val( ModuleFlags ); @@ -14325,7 +14423,7 @@ bool AST::is_equal( AST* other ) return true; } - case Typename : + case CT_Typename: { check_member_val( IsParamPack ); check_member_str( Name ); @@ -14335,7 +14433,7 @@ bool AST::is_equal( AST* other ) return true; } - case Union : + case CT_Union: { check_member_val( ModuleFlags ); check_member_str( Name ); @@ -14345,8 +14443,15 @@ bool AST::is_equal( AST* other ) return true; } - case Using : - case Using_Namespace : + case CT_Union_Fwd: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( Attributes ); + } + + case CT_Using: + case CT_Using_Namespace: { check_member_val( ModuleFlags ); check_member_str( Name ); @@ -14356,7 +14461,7 @@ bool AST::is_equal( AST* other ) return true; } - case Variable : + case CT_Variable: { check_member_val( ModuleFlags ); check_member_str( Name ); @@ -14370,46 +14475,44 @@ bool AST::is_equal( AST* other ) return true; } - case Class_Body : - case Enum_Body : - case Export_Body : - case Global_Body : - case Namespace_Body : - case Struct_Body : - case Union_Body : + case CT_Class_Body: + case CT_Enum_Body: + case CT_Export_Body: + case CT_Global_Body: + case CT_Namespace_Body: + case CT_Struct_Body: + case CT_Union_Body: { check_member_ast( Front ); check_member_ast( Back ); - AST* curr = Front; - AST* curr_other = other->Front; + Code curr = self->Front; + Code curr_other = other->Front; while ( curr != nullptr ) { if ( curr_other == nullptr ) { - log_fmt( - "\nAST::is_equal: Failed for body, other equivalent param is null\n" - "AST : %S\n" - "Other: %S\n" - "For ast member: %S\n", - curr->debug_str() + log_fmt("\nAST::is_equal: Failed for body, other equivalent param is null\n" + "AST : %S\n" + "Other: %S\n" + , code_debug_str(curr) + , code_debug_str(other) ); return false; } - if ( ! curr->is_equal( curr_other ) ) + if ( ! code_is_equal( curr, curr_other ) ) { - log_fmt( - "\nAST::is_equal: Failed for body\n" - "AST : %S\n" - "Other: %S\n" - "For ast member: %S\n" - "other's ast member: %S\n", - debug_str(), - other->debug_str(), - curr->debug_str(), - curr_other->debug_str() + log_fmt( "\nAST::is_equal: Failed for body\n" + "AST : %S\n" + "Other: %S\n" + "For ast member: %S\n" + "other's ast member: %S\n" + , code_debug_str(self) + , code_debug_str(other) + , code_debug_str(curr) + , code_debug_str(curr_other) ); return false; @@ -14424,162 +14527,1684 @@ bool AST::is_equal( AST* other ) return true; } -#undef check_member_val -#undef check_member_str -#undef check_member_ast + #undef check_member_val + #undef check_member_str + #undef check_member_ast } return true; } -bool AST::validate_body() +bool code_validate_body(Code self) { - using namespace ECode; - -#define CheckEntries( Unallowed_Types ) \ - do \ - { \ - for ( Code entry : cast< CodeBody >() ) \ - { \ - switch ( entry->Type ) \ - { \ - Unallowed_Types log_failure( "AST::validate_body: Invalid entry in body %s", entry.debug_str() ); \ - return false; \ - } \ - } \ - } while ( 0 ); - - switch ( Type ) + switch ( self->Type ) { - case Class_Body : - CheckEntries( GEN_AST_BODY_CLASS_UNALLOWED_TYPES ); - break; - case Enum_Body : - for ( Code entry : cast< CodeBody >() ) + case CT_Class_Body: + { + CodeBody body = cast(CodeBody, self); + for (Code code_entry = begin_CodeBody(body); code_entry != end_CodeBody(body); next_CodeBody(body, code_entry)) switch (code_entry->Type) { - if ( entry->Type != Untyped ) - { - log_failure( "AST::validate_body: Invalid entry in enum body (needs to be untyped or comment) %s", entry.debug_str() ); - return false; - } - } - break; - case Export_Body : - CheckEntries( GEN_AST_BODY_CLASS_UNALLOWED_TYPES ); - break; - case Extern_Linkage : - CheckEntries( GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES ); - break; - case Function_Body : - CheckEntries( GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES ); - break; - case Global_Body : - for ( Code entry : cast< CodeBody >() ) - { - switch ( entry->Type ) - { - case Access_Public : - case Access_Protected : - case Access_Private : - case PlatformAttributes : - case Class_Body : - case Enum_Body : - case Execution : - case Friend : - case Function_Body : - case Global_Body : - case Namespace_Body : - case Operator_Member : - case Operator_Member_Fwd : - case Parameters : - case Specifiers : - case Struct_Body : - case Typename : - log_failure( "AST::validate_body: Invalid entry in body %s", entry.debug_str() ); - return false; - } - } - break; - case Namespace_Body : - CheckEntries( GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES ); - break; - case Struct_Body : - CheckEntries( GEN_AST_BODY_STRUCT_UNALLOWED_TYPES ); - break; - case Union_Body : - for ( Code entry : Body->cast< CodeBody >() ) - { - if ( entry->Type != Untyped ) - { - log_failure( "AST::validate_body: Invalid entry in union body (needs to be untyped or comment) %s", entry.debug_str() ); - return false; - } - } - break; + GEN_AST_BODY_CLASS_UNALLOWED_TYPES: + log_failure("AST::validate_body: Invalid entry in body %S", code_debug_str(code_entry)); + return false; - default : - log_failure( "AST::validate_body: Invalid this AST does not have a body %s", debug_str() ); + default: + continue; + } + } + break; + case CT_Enum_Body: + { + CodeBody body = cast(CodeBody, self); + for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); next_CodeBody(body, entry) ) + { + if ( entry->Type != CT_Untyped ) + { + log_failure( "AST::validate_body: Invalid entry in enum body (needs to be untyped or comment) %S", code_debug_str(entry) ); + return false; + } + } + } + break; + case CT_Export_Body: + { + CodeBody body = cast(CodeBody, self); + for (Code code_entry = begin_CodeBody(body); code_entry != end_CodeBody(body); next_CodeBody(body, code_entry)) switch (code_entry->Type) + { + GEN_AST_BODY_EXPORT_UNALLOWED_TYPES: + log_failure("AST::validate_body: Invalid entry in body %S", code_debug_str(code_entry)); + return false; + + default: + continue; + } + } + break; + case CT_Extern_Linkage: + { + CodeBody body = cast(CodeBody, self); + for (Code code_entry = begin_CodeBody(body); code_entry != end_CodeBody(body); next_CodeBody(body, code_entry)) switch (code_entry->Type) + { + GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES: + log_failure("AST::validate_body: Invalid entry in body %S", code_debug_str(code_entry)); + return false; + + default: + continue; + } + } + break; + case CT_Function_Body: + { + CodeBody body = cast(CodeBody, self); + for (Code code_entry = begin_CodeBody(body); code_entry != end_CodeBody(body); next_CodeBody(body, code_entry)) switch (code_entry->Type) + { + GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES: + log_failure("AST::validate_body: Invalid entry in body %S", code_debug_str(code_entry)); + return false; + + default: + continue; + } + } + break; + case CT_Global_Body: + { + CodeBody body = cast(CodeBody, self); + for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); next_CodeBody(body, entry) )switch (entry->Type) + { + GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES: + log_failure("AST::validate_body: Invalid entry in body %S", code_debug_str(entry)); + return false; + } + } + break; + case CT_Namespace_Body: + { + CodeBody body = cast(CodeBody, self); + for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); next_CodeBody(body, entry) ) switch (entry->Type) + { + GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES: + log_failure("AST::validate_body: Invalid entry in body %S", code_debug_str(entry)); + return false; + } + } + break; + case CT_Struct_Body: + { + CodeBody body = cast(CodeBody, self); + for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); next_CodeBody(body, entry) ) switch (entry->Type) + { + GEN_AST_BODY_STRUCT_UNALLOWED_TYPES: + log_failure("AST::validate_body: Invalid entry in body %S", code_debug_str(entry)); + return false; + } + } + break; + case CT_Union_Body: + { + CodeBody body = cast(CodeBody, self); + for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); next_CodeBody(body, entry) ) + { + if ( entry->Type != CT_Untyped ) + { + log_failure( "AST::validate_body: Invalid entry in union body (needs to be untyped or comment) %S", code_debug_str(entry) ); + return false; + } + } + } + break; + + default: + log_failure( "AST::validate_body: Invalid this AST does not have a body %S", code_debug_str(self) ); return false; } - return false; - -#undef CheckEntries } +inline +StrBuilder attributes_to_strbuilder(CodeAttributes attributes) { + GEN_ASSERT(attributes); + char* raw = ccast(char*, str_duplicate( attributes->Content, _ctx->Allocator_Temp ).Ptr); + StrBuilder result = { raw }; + return result; +} + +inline +void attributes_to_strbuilder_ref(CodeAttributes attributes, StrBuilder* result) { + GEN_ASSERT(attributes); + GEN_ASSERT(result); + strbuilder_append_str(result, attributes->Content); +} + +StrBuilder body_to_strbuilder(CodeBody body) +{ + GEN_ASSERT(body); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 ); + switch ( body->Type ) + { + case CT_Untyped: + case CT_Execution: + strbuilder_append_str( & result, cast(Code, body)->Content ); + break; + + case CT_Enum_Body: + case CT_Class_Body: + case CT_Extern_Linkage_Body: + case CT_Function_Body: + case CT_Global_Body: + case CT_Namespace_Body: + case CT_Struct_Body: + case CT_Union_Body: + body_to_strbuilder_ref( body, & result ); + break; + + case CT_Export_Body: + body_to_strbuilder_export( body, & result ); + break; + } + return result; +} + +void body_to_strbuilder_ref( CodeBody body, StrBuilder* result ) +{ + GEN_ASSERT(body != nullptr); + GEN_ASSERT(result != nullptr); + Code curr = body->Front; + s32 left = body->NumEntries; + while ( left -- ) + { + code_to_strbuilder_ptr(curr, result); + // strbuilder_append_fmt( result, "%SB", code_to_strbuilder(curr) ); + ++curr; + } +} + +void body_to_strbuilder_export( CodeBody body, StrBuilder* result ) +{ + GEN_ASSERT(body != nullptr); + GEN_ASSERT(result != nullptr); + strbuilder_append_fmt( result, "export\n{\n" ); + + Code curr = cast(Code, body); + s32 left = body->NumEntries; + while ( left-- ) + { + code_to_strbuilder_ptr(curr, result); + // strbuilder_append_fmt( result, "%SB", code_to_strbuilder(curr) ); + ++curr; + } + + strbuilder_append_fmt( result, "};\n" ); +} + +inline +StrBuilder comment_to_strbuilder(CodeComment comment) { + GEN_ASSERT(comment); + char* raw = ccast(char*, str_duplicate( comment->Content, _ctx->Allocator_Temp ).Ptr); + StrBuilder result = { raw }; + return result; +} + +inline +void comment_to_strbuilder_ref(CodeComment comment, StrBuilder* result) { + GEN_ASSERT(comment); + GEN_ASSERT(result); + strbuilder_append_str(result, comment->Content); +} + +StrBuilder constructor_to_strbuilder(CodeConstructor self) +{ + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 ); + switch (self->Type) + { + case CT_Constructor: + constructor_to_strbuilder_def( self, & result ); + break; + case CT_Constructor_Fwd: + constructor_to_strbuilder_fwd( self, & result ); + break; + } + return result; +} + +void constructor_to_strbuilder_def(CodeConstructor self, StrBuilder* result ) +{ + Code ClassStructParent = self->Parent->Parent; + if (ClassStructParent) { + strbuilder_append_str( result, ClassStructParent->Name ); + } + else { + strbuilder_append_str( result, self->Name ); + } + + if ( self->Params ) + strbuilder_append_fmt( result, "( %SB )", params_to_strbuilder(self->Params) ); + else + strbuilder_append_str( result, txt("()") ); + + if ( self->InitializerList ) + strbuilder_append_fmt( result, " : %SB", code_to_strbuilder(self->InitializerList) ); + + if ( self->InlineCmt ) + strbuilder_append_fmt( result, " // %S", self->InlineCmt->Content ); + + strbuilder_append_fmt( result, "\n{\n%SB\n}\n", code_to_strbuilder(self->Body) ); +} + +void constructor_to_strbuilder_fwd(CodeConstructor self, StrBuilder* result ) +{ + Code ClassStructParent = self->Parent->Parent; + if (ClassStructParent) { + strbuilder_append_str( result, ClassStructParent->Name ); + } + else { + strbuilder_append_str( result, self->Name ); + } + + if ( self->Params ) + strbuilder_append_fmt( result, "( %SB )", params_to_strbuilder(self->Params) ); + else + strbuilder_append_fmt( result, "()"); + + if (self->Body) + strbuilder_append_fmt( result, " = %SB", code_to_strbuilder(self->Body) ); + + if ( self->InlineCmt ) + strbuilder_append_fmt( result, "; // %S\n", self->InlineCmt->Content ); + else + strbuilder_append_str( result, txt(";\n") ); +} + +StrBuilder class_to_strbuilder( CodeClass self ) +{ + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 512 ); + switch ( self->Type ) + { + case CT_Class: + class_to_strbuilder_def(self, & result ); + break; + case CT_Class_Fwd: + class_to_strbuilder_fwd(self, & result ); + break; + } + return result; +} + +void class_to_strbuilder_def( CodeClass self, StrBuilder* result ) +{ + GEN_ASSERT(self); + + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + strbuilder_append_str( result, txt("class ") ); + + if ( self->Attributes ) + { + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + } + + if ( self->ParentType ) + { + Str access_level = access_spec_to_str( self->ParentAccess ); + strbuilder_append_fmt( result, "%S : %S %SB", self->Name, access_level, typename_to_strbuilder(self->ParentType) ); + + CodeTypename interface = cast(CodeTypename, self->ParentType->Next); + if ( interface ) + strbuilder_append_str( result, txt("\n") ); + + while ( interface ) + { + strbuilder_append_fmt( result, ", public %SB", typename_to_strbuilder(interface) ); + interface = interface->Next ? cast(CodeTypename, interface->Next) : NullCode; + } + } + else if ( self->Name.Len ) + { + strbuilder_append_str( result, self->Name ); + } + + if ( self->InlineCmt ) + { + strbuilder_append_fmt( result, " // %S", self->InlineCmt->Content ); + } + + strbuilder_append_fmt( result, "\n{\n%SB\n}", body_to_strbuilder(self->Body) ); + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + strbuilder_append_str( result, txt(";\n") ); +} + +void class_to_strbuilder_fwd( CodeClass self, StrBuilder* result ) +{ + GEN_ASSERT(self); + + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + if ( self->Attributes ) + strbuilder_append_fmt( result, "class %SB %S", attributes_to_strbuilder(self->Attributes), self->Name ); + + else strbuilder_append_fmt( result, "class %S", self->Name ); + + // Check if it can have an end-statement + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + { + if ( self->InlineCmt ) + strbuilder_append_fmt( result, "; // %S\n", self->InlineCmt->Content ); + else + strbuilder_append_str( result, txt(";\n") ); + } +} + +StrBuilder define_to_strbuilder(CodeDefine define) +{ + return strbuilder_fmt_buf( _ctx->Allocator_Temp, "#define %S %S", define->Name, define->Content ); +} + +void define_to_strbuilder_ref(CodeDefine define, StrBuilder* result ) +{ + strbuilder_append_fmt( result, "#define %S %S", define->Name, define->Content ); +} + +StrBuilder destructor_to_strbuilder(CodeDestructor self) +{ + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 ); + switch ( self->Type ) + { + case CT_Destructor: + destructor_to_strbuilder_def( self, & result ); + break; + case CT_Destructor_Fwd: + destructor_to_strbuilder_fwd( self, & result ); + break; + } + return result; +} + +void destructor_to_strbuilder_def(CodeDestructor self, StrBuilder* result ) +{ + if ( self->Name.Len ) + { + strbuilder_append_fmt( result, "%S()", self->Name ); + } + else if ( self->Specs ) + { + if ( specifiers_has(self->Specs, Spec_Virtual ) ) + strbuilder_append_fmt( result, "virtual ~%S()", self->Parent->Name ); + else + strbuilder_append_fmt( result, "~%S()", self->Parent->Name ); + } + else + strbuilder_append_fmt( result, "~%S()", self->Parent->Name ); + + strbuilder_append_fmt( result, "\n{\n%SB\n}\n", code_to_strbuilder(self->Body) ); +} + +void destructor_to_strbuilder_fwd(CodeDestructor self, StrBuilder* result ) +{ + if ( self->Specs ) + { + if ( specifiers_has(self->Specs, Spec_Virtual ) ) + strbuilder_append_fmt( result, "virtual ~%S();\n", self->Parent->Name ); + else + strbuilder_append_fmt( result, "~%S()", self->Parent->Name ); + + if ( specifiers_has(self->Specs, Spec_Pure ) ) + strbuilder_append_str( result, txt(" = 0;") ); + else if (self->Body) + strbuilder_append_fmt( result, " = %SB;", code_to_strbuilder(self->Body) ); + } + else + strbuilder_append_fmt( result, "~%S();", self->Parent->Name ); + + if ( self->InlineCmt ) + strbuilder_append_fmt( result, " %S", self->InlineCmt->Content ); + else + strbuilder_append_str( result, txt("\n")); +} + +StrBuilder enum_to_strbuilder(CodeEnum self) +{ + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 512 ); + switch ( self->Type ) + { + case CT_Enum: + enum_to_strbuilder_def(self, & result ); + break; + case CT_Enum_Fwd: + enum_to_strbuilder_fwd(self, & result ); + break; + case CT_Enum_Class: + enum_to_strbuilder_class_def(self, & result ); + break; + case CT_Enum_Class_Fwd: + enum_to_strbuilder_class_fwd(self, & result ); + break; + } + return result; +} + +void enum_to_strbuilder_def(CodeEnum self, StrBuilder* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + if ( self->Attributes || self->UnderlyingType || self->UnderlyingTypeMacro ) + { + strbuilder_append_str( result, txt("enum ") ); + + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + + if ( self->UnderlyingType ) + strbuilder_append_fmt( result, "%S : %SB\n{\n%SB\n}" + , self->Name + , typename_to_strbuilder(self->UnderlyingType) + , body_to_strbuilder(self->Body) + ); + else if ( self->UnderlyingTypeMacro ) + strbuilder_append_fmt( result, "%S %SB\n{\n%SB\n}" + , self->Name + , code_to_strbuilder(self->UnderlyingTypeMacro) + , body_to_strbuilder(self->Body) + ); + + else strbuilder_append_fmt( result, "%S\n{\n%SB\n}", self->Name, body_to_strbuilder(self->Body) ); + } + else strbuilder_append_fmt( result, "enum %S\n{\n%SB\n}", self->Name, body_to_strbuilder(self->Body) ); + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + strbuilder_append_str( result, txt(";\n")); +} + +void enum_to_strbuilder_fwd(CodeEnum self, StrBuilder* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + + if ( self->UnderlyingType ) + strbuilder_append_fmt( result, "enum %S : %SB", self->Name, typename_to_strbuilder(self->UnderlyingType) ); + else if (self->UnderlyingTypeMacro) + { + log_fmt("IDENTIFIED A UNDERLYING ENUM MACRO"); + strbuilder_append_fmt( result, "enum %S %SB", self->Name, code_to_strbuilder(self->UnderlyingTypeMacro) ); + } + else + strbuilder_append_fmt( result, "enum %S", self->Name ); + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + { + if ( self->InlineCmt ) + strbuilder_append_fmt( result, "; %S", self->InlineCmt->Content ); + else + strbuilder_append_str( result, txt(";\n")); + } +} + +void enum_to_strbuilder_class_def(CodeEnum self, StrBuilder* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + if ( self->Attributes || self->UnderlyingType ) + { + strbuilder_append_str( result, txt("enum class ") ); + + if ( self->Attributes ) + { + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + } + + if ( self->UnderlyingType ) + { + strbuilder_append_fmt( result, "%S : %SB\n{\n%SB\n}", self->Name, typename_to_strbuilder(self->UnderlyingType), body_to_strbuilder(self->Body) ); + } + else + { + strbuilder_append_fmt( result, "%S\n{\n%SB\n}", self->Name, body_to_strbuilder(self->Body) ); + } + } + else + { + strbuilder_append_fmt( result, "enum %S\n{\n%SB\n}", self->Name, body_to_strbuilder(self->Body) ); + } + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + strbuilder_append_str( result, txt(";\n")); +} + +void enum_to_strbuilder_class_fwd(CodeEnum self, StrBuilder* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + strbuilder_append_str( result, txt("enum class ") ); + + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + + strbuilder_append_fmt( result, "%S : %SB", self->Name, typename_to_strbuilder(self->UnderlyingType) ); + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + { + if ( self->InlineCmt ) + strbuilder_append_fmt( result, "; %S", self->InlineCmt->Content ); + else + strbuilder_append_str( result, txt(";\n")); + } +} + +StrBuilder exec_to_strbuilder(CodeExec exec) +{ + GEN_ASSERT(exec); + char* raw = ccast(char*, str_duplicate( exec->Content, _ctx->Allocator_Temp ).Ptr); + StrBuilder result = { raw }; + return result; +} + +void extern_to_strbuilder(CodeExtern self, StrBuilder* result ) +{ + if ( self->Body ) + strbuilder_append_fmt( result, "extern \"%S\"\n{\n%SB\n}\n", self->Name, body_to_strbuilder(self->Body) ); + else + strbuilder_append_fmt( result, "extern \"%S\"\n{}\n", self->Name ); +} + +StrBuilder include_to_strbuilder(CodeInclude include) +{ + return strbuilder_fmt_buf( _ctx->Allocator_Temp, "#include %S\n", include->Content ); +} + +void include_to_strbuilder_ref( CodeInclude include, StrBuilder* result ) +{ + strbuilder_append_fmt( result, "#include %S\n", include->Content ); +} + +StrBuilder friend_to_strbuilder(CodeFriend self) +{ + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 256 ); + friend_to_strbuilder_ref( self, & result ); + return result; +} + +void friend_to_strbuilder_ref(CodeFriend self, StrBuilder* result ) +{ + strbuilder_append_fmt( result, "friend %SB", code_to_strbuilder(self->Declaration) ); + + if ( self->Declaration->Type != CT_Function && self->Declaration->Type != CT_Operator && (* result)[ strbuilder_length(* result) - 1 ] != ';' ) + { + strbuilder_append_str( result, txt(";") ); + } + + if ( self->InlineCmt ) + strbuilder_append_fmt( result, " %S", self->InlineCmt->Content ); + else + strbuilder_append_str( result, txt("\n")); +} + +StrBuilder fn_to_strbuilder(CodeFn self) +{ + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 512 ); + switch ( self->Type ) + { + case CT_Function: + fn_to_strbuilder_def(self, & result ); + break; + case CT_Function_Fwd: + fn_to_strbuilder_fwd(self, & result ); + break; + } + return result; +} + +void fn_to_strbuilder_def(CodeFn self, StrBuilder* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export") ); + + if ( self->Attributes ) + strbuilder_append_fmt( result, " %SB ", attributes_to_strbuilder(self->Attributes) ); + + bool prefix_specs = false; + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( ! spec_is_trailing( * spec ) ) + { + Str spec_str = spec_to_str( * spec ); + strbuilder_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + + prefix_specs = true; + } + } + } + + if ( self->Attributes || prefix_specs ) + strbuilder_append_str( result, txt("\n") ); + + if ( self->ReturnType ) + strbuilder_append_fmt( result, "%SB %S(", typename_to_strbuilder(self->ReturnType), self->Name ); + + else + strbuilder_append_fmt( result, "%S(", self->Name ); + + if ( self->Params ) + strbuilder_append_fmt( result, "%SB)", params_to_strbuilder(self->Params) ); + + else + strbuilder_append_str( result, txt(")") ); + + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( spec_is_trailing( * spec ) ) + { + Str spec_str = spec_to_str( * spec ); + strbuilder_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + } + } + } + + strbuilder_append_fmt( result, "\n{\n%SB\n}\n", body_to_strbuilder(self->Body) ); +} + +void fn_to_strbuilder_fwd(CodeFn self, StrBuilder* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + + b32 prefix_specs = false; + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( ! spec_is_trailing( * spec ) || ! ( * spec != Spec_Pure) ) + { + Str spec_str = spec_to_str( * spec ); + strbuilder_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + + prefix_specs = true; + } + } + } + + if ( self->Attributes || prefix_specs ) + { + strbuilder_append_str( result, txt("\n") ); + } + + if ( self->ReturnType ) + strbuilder_append_fmt( result, "%SB %S(", typename_to_strbuilder(self->ReturnType), self->Name ); + + else + strbuilder_append_fmt( result, "%S(", self->Name ); + + if ( self->Params ) + strbuilder_append_fmt( result, "%SB)", params_to_strbuilder(self->Params) ); + + else + strbuilder_append_str( result, txt(")") ); + + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( spec_is_trailing( * spec ) ) + { + Str spec_str = spec_to_str( * spec ); + strbuilder_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + } + } + } + + if ( self->Specs && specifiers_has(self->Specs, Spec_Pure ) >= 0 ) + strbuilder_append_str( result, txt(" = 0;") ); + else if (self->Body) + strbuilder_append_fmt( result, " = %SB;", body_to_strbuilder(self->Body) ); + + if ( self->InlineCmt ) + strbuilder_append_fmt( result, "; %S", self->InlineCmt->Content ); + else + strbuilder_append_str( result, txt(";\n") ); +} + +StrBuilder module_to_strbuilder(CodeModule self) +{ + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 64 ); + module_to_strbuilder_ref( self, & result ); + return result; +} + +void module_to_strbuilder_ref(CodeModule self, StrBuilder* result ) +{ + if (((scast(u32, ModuleFlag_Export) & scast(u32, self->ModuleFlags)) == scast(u32, ModuleFlag_Export))) + strbuilder_append_str( result, txt("export ")); + + if (((scast(u32, ModuleFlag_Import) & scast(u32, self->ModuleFlags)) == scast(u32, ModuleFlag_Import))) + strbuilder_append_str( result, txt("import ")); + + strbuilder_append_fmt( result, "%S;\n", self->Name ); +} + +StrBuilder namespace_to_strbuilder(CodeNS self) +{ + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 512 ); + namespace_to_strbuilder_ref( self, & result ); + return result; +} + +void namespace_to_strbuilder_ref(CodeNS self, StrBuilder* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + strbuilder_append_fmt( result, "namespace %S\n{\n%SB\n}\n", self->Name, body_to_strbuilder(self->Body) ); +} + +StrBuilder code_op_to_strbuilder(CodeOperator self) +{ + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 512 ); + switch ( self->Type ) + { + case CT_Operator: + case CT_Operator_Member: + code_op_to_strbuilder_def( self, & result ); + break; + case CT_Operator_Fwd: + case CT_Operator_Member_Fwd: + code_op_to_strbuilder_fwd( self, & result ); + break; + } + return result; +} + +void code_op_to_strbuilder_def(CodeOperator self, StrBuilder* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( ! spec_is_trailing( * spec ) ) + { + Str spec_str = spec_to_str( * spec ); + strbuilder_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + } + } + } + + if ( self->Attributes || self->Specs ) + { + strbuilder_append_str( result, txt("\n") ); + } + + if ( self->ReturnType ) + strbuilder_append_fmt( result, "%SB %S (", typename_to_strbuilder(self->ReturnType), self->Name ); + + if ( self->Params ) + strbuilder_append_fmt( result, "%SB)", params_to_strbuilder(self->Params) ); + + else + strbuilder_append_str( result, txt(")") ); + + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( spec_is_trailing( * spec ) ) + { + Str spec_str = spec_to_str( * spec ); + strbuilder_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + } + } + } + + strbuilder_append_fmt( result, "\n{\n%SB\n}\n" + , body_to_strbuilder(self->Body) + ); +} + +void code_op_to_strbuilder_fwd(CodeOperator self, StrBuilder* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB\n", attributes_to_strbuilder(self->Attributes) ); + + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( ! spec_is_trailing( * spec ) ) + { + Str spec_str = spec_to_str( * spec ); + strbuilder_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + } + } + } + + if ( self->Attributes || self->Specs ) + { + strbuilder_append_str( result, txt("\n") ); + } + + strbuilder_append_fmt( result, "%SB %S (", typename_to_strbuilder(self->ReturnType), self->Name ); + + if ( self->Params ) + strbuilder_append_fmt( result, "%SB)", params_to_strbuilder(self->Params) ); + + else + strbuilder_append_fmt( result, ")" ); + + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( spec_is_trailing( * spec ) ) + { + Str spec_str = spec_to_str( * spec ); + strbuilder_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + } + } + } + + if ( self->InlineCmt ) + strbuilder_append_fmt( result, "; %S", self->InlineCmt->Content ); + else + strbuilder_append_str( result, txt(";\n") ); +} + +StrBuilder opcast_to_strbuilder(CodeOpCast self) +{ + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 ); + switch ( self->Type ) + { + case CT_Operator_Cast: + opcast_to_strbuilder_def(self, & result ); + break; + case CT_Operator_Cast_Fwd: + opcast_to_strbuilder_fwd(self, & result ); + break; + } + return result; +} + +void opcast_to_strbuilder_def(CodeOpCast self, StrBuilder* result ) +{ + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( ! spec_is_trailing( * spec ) ) + { + Str spec_str = spec_to_str( * spec ); + strbuilder_append_fmt( result, "%*s ", spec_str.Len, spec_str.Ptr ); + } + } + + if ( self->Name.Ptr && self->Name.Len ) + strbuilder_append_fmt( result, "%S operator %SB()", self->Name, typename_to_strbuilder(self->ValueType) ); + else + strbuilder_append_fmt( result, "operator %SB()", typename_to_strbuilder(self->ValueType) ); + + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( spec_is_trailing( * spec ) ) + { + Str spec_str = spec_to_str( * spec ); + strbuilder_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + } + } + + strbuilder_append_fmt( result, "\n{\n%SB\n}\n", body_to_strbuilder(self->Body) ); + return; + } + + if ( self->Name.Ptr && self->Name.Len ) + strbuilder_append_fmt( result, "%S operator %SB()\n{\n%SB\n}\n", self->Name, typename_to_strbuilder(self->ValueType), body_to_strbuilder(self->Body) ); + else + strbuilder_append_fmt( result, "operator %SB()\n{\n%SB\n}\n", typename_to_strbuilder(self->ValueType), body_to_strbuilder(self->Body) ); +} + +void opcast_to_strbuilder_fwd(CodeOpCast self, StrBuilder* result ) +{ + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( ! spec_is_trailing( * spec ) ) + { + Str spec_str = spec_to_str( * spec ); + strbuilder_append_fmt( result, "%*s ", spec_str.Len, spec_str.Ptr ); + } + } + + strbuilder_append_fmt( result, "operator %SB()", typename_to_strbuilder(self->ValueType) ); + + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( spec_is_trailing( * spec ) ) + { + Str spec_str = spec_to_str( * spec ); + strbuilder_append_fmt( result, " %*s", spec_str.Len, spec_str.Ptr ); + } + } + + if ( self->InlineCmt ) + strbuilder_append_fmt( result, "; %S", self->InlineCmt->Content ); + else + strbuilder_append_str( result, txt(";\n") ); + return; + } + + if ( self->InlineCmt ) + strbuilder_append_fmt( result, "operator %SB(); %SB", typename_to_strbuilder(self->ValueType) ); + else + strbuilder_append_fmt( result, "operator %SB();\n", typename_to_strbuilder(self->ValueType) ); +} + +StrBuilder params_to_strbuilder(CodeParams self) +{ + GEN_ASSERT(self); + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 ); + params_to_strbuilder_ref( self, & result ); + return result; +} + +void params_to_strbuilder_ref( CodeParams self, StrBuilder* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( self->Macro ) + { + // Related to parsing: ( , ... ) + strbuilder_append_str( result, self->Macro->Content ); + // Could also be: ( , ... ) + } + + if ( self->Name.Ptr && self->Name.Len ) + { + if ( self->ValueType == nullptr ) + strbuilder_append_fmt( result, " %S", self->Name ); + else + strbuilder_append_fmt( result, " %SB %S", typename_to_strbuilder(self->ValueType), self->Name ); + + } + else if ( self->ValueType ) + strbuilder_append_fmt( result, " %SB", typename_to_strbuilder(self->ValueType) ); + + if ( self->PostNameMacro ) + { + strbuilder_append_fmt( result, " %SB", code_to_strbuilder(self->PostNameMacro) ); + } + + if ( self->Value ) + strbuilder_append_fmt( result, " = %SB", code_to_strbuilder(self->Value) ); + + if ( self->NumEntries - 1 > 0 ) + { + for ( CodeParams param = begin_CodeParams(self->Next); param != end_CodeParams(self->Next); param = next_CodeParams(self->Next, param) ) + { + strbuilder_append_fmt( result, ", %SB", params_to_strbuilder(param) ); + } + } +} + +StrBuilder preprocess_to_strbuilder(CodePreprocessCond self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 256 ); + switch ( self->Type ) + { + case CT_Preprocess_If: + preprocess_to_strbuilder_if( self, & result ); + break; + case CT_Preprocess_IfDef: + preprocess_to_strbuilder_ifdef( self, & result ); + break; + case CT_Preprocess_IfNotDef: + preprocess_to_strbuilder_ifndef( self, & result ); + break; + case CT_Preprocess_ElIf: + preprocess_to_strbuilder_elif( self, & result ); + break; + case CT_Preprocess_Else: + preprocess_to_strbuilder_else( self, & result ); + break; + case CT_Preprocess_EndIf: + preprocess_to_strbuilder_endif( self, & result ); + break; + } + return result; +} + +void preprocess_to_strbuilder_if(CodePreprocessCond cond, StrBuilder* result ) +{ + GEN_ASSERT(cond); + strbuilder_append_fmt( result, "#if %S", cond->Content ); +} + +void preprocess_to_strbuilder_ifdef(CodePreprocessCond cond, StrBuilder* result ) +{ + GEN_ASSERT(cond); + strbuilder_append_fmt( result, "#ifdef %S\n", cond->Content ); +} + +void preprocess_to_strbuilder_ifndef(CodePreprocessCond cond, StrBuilder* result ) +{ + GEN_ASSERT(cond); + strbuilder_append_fmt( result, "#ifndef %S", cond->Content ); +} + +void preprocess_to_strbuilder_elif(CodePreprocessCond cond, StrBuilder* result ) +{ + GEN_ASSERT(cond); + strbuilder_append_fmt( result, "#elif %S\n", cond->Content ); +} + +void preprocess_to_strbuilder_else(CodePreprocessCond cond, StrBuilder* result ) +{ + GEN_ASSERT(cond); + strbuilder_append_str( result, txt("#else\n") ); +} + +void preprocess_to_strbuilder_endif(CodePreprocessCond cond, StrBuilder* result ) +{ + GEN_ASSERT(cond); + strbuilder_append_str( result, txt("#endif\n") ); +} + +StrBuilder pragma_to_strbuilder(CodePragma self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 256 ); + pragma_to_strbuilder_ref( self, & result ); + return result; +} + +void pragma_to_strbuilder_ref(CodePragma self, StrBuilder* result ) +{ + strbuilder_append_fmt( result, "#pragma %S\n", self->Content ); +} + +StrBuilder specifiers_to_strbuilder(CodeSpecifiers self) +{ + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 64 ); + specifiers_to_strbuilder_ref( self, & result ); + return result; +} + +void specifiers_to_strbuilder_ref( CodeSpecifiers self, StrBuilder* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + s32 idx = 0; + s32 left = self->NumEntries; + while ( left-- ) + { + Str spec = spec_to_str( self->ArrSpecs[idx] ); + strbuilder_append_fmt( result, "%.*s ", spec.Len, spec.Ptr ); + idx++; + } +} + +StrBuilder struct_to_strbuilder(CodeStruct self) +{ + GEN_ASSERT(self); + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 512 ); + switch ( self->Type ) + { + case CT_Struct: + struct_to_strbuilder_def( self, & result ); + break; + case CT_Struct_Fwd: + struct_to_strbuilder_fwd( self, & result ); + break; + } + return result; +} + +void struct_to_strbuilder_def( CodeStruct self, StrBuilder* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + strbuilder_append_str( result, txt("struct ") ); + + if ( self->Attributes ) + { + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + } + + if ( self->ParentType ) + { + Str access_level = access_spec_to_str( self->ParentAccess ); + + strbuilder_append_fmt( result, "%S : %S %SB", self->Name, access_level, typename_to_strbuilder(self->ParentType) ); + + CodeTypename interface = cast(CodeTypename, self->ParentType->Next); + if ( interface ) + strbuilder_append_str( result, txt("\n") ); + + while ( interface ) + { + strbuilder_append_fmt( result, ", %SB", typename_to_strbuilder(interface) ); + interface = interface->Next ? cast( CodeTypename, interface->Next) : NullCode; + } + } + else if ( self->Name.Len ) + { + strbuilder_append_str( result, self->Name ); + } + + if ( self->InlineCmt ) + { + strbuilder_append_fmt( result, " // %S", self->InlineCmt->Content ); + } + + strbuilder_append_fmt( result, "\n{\n%SB\n}", body_to_strbuilder(self->Body) ); + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + strbuilder_append_str( result, txt(";\n")); +} + +void struct_to_strbuilder_fwd( CodeStruct self, StrBuilder* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + if ( self->Attributes ) + strbuilder_append_fmt( result, "struct %SB %S", attributes_to_strbuilder(self->Attributes), self->Name ); + + else strbuilder_append_fmt( result, "struct %S", self->Name ); + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + { + if ( self->InlineCmt ) + strbuilder_append_fmt( result, "; %S", self->InlineCmt->Content ); + else + strbuilder_append_str( result, txt( ";\n") ); + } +} + +StrBuilder template_to_strbuilder(CodeTemplate self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 1024 ); + template_to_strbuilder_ref( self, & result ); + return result; +} + +void template_to_strbuilder_ref(CodeTemplate self, StrBuilder* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + if ( self->Params ) + strbuilder_append_fmt( result, "template< %SB >\n%SB", params_to_strbuilder(self->Params), code_to_strbuilder(self->Declaration) ); + else + strbuilder_append_fmt( result, "template<>\n%SB", code_to_strbuilder(self->Declaration) ); +} + +StrBuilder typedef_to_strbuilder(CodeTypedef self) +{ + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 ); + typedef_to_strbuilder_ref( self, & result ); + return result; +} + +void typedef_to_strbuilder_ref(CodeTypedef self, StrBuilder* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + strbuilder_append_str( result, txt("typedef ")); + + // Determines if the typedef is a function typename + if ( self->UnderlyingType->ReturnType ) + strbuilder_append_string( result, code_to_strbuilder(self->UnderlyingType) ); + else + strbuilder_append_fmt( result, "%SB %S", code_to_strbuilder(self->UnderlyingType), self->Name ); + + if ( self->UnderlyingType->Type == CT_Typename && self->UnderlyingType->ArrExpr ) + { + strbuilder_append_fmt( result, "[ %SB ];", code_to_strbuilder(self->UnderlyingType->ArrExpr) ); + + Code next_arr_expr = self->UnderlyingType->ArrExpr->Next; + while ( next_arr_expr ) + { + strbuilder_append_fmt( result, "[ %SB ];", code_to_strbuilder(next_arr_expr) ); + next_arr_expr = next_arr_expr->Next; + } + } + else + { + strbuilder_append_str( result, txt(";") ); + } + + if ( self->InlineCmt ) + strbuilder_append_fmt( result, " %S", self->InlineCmt->Content); + else + strbuilder_append_str( result, txt("\n")); +} + +StrBuilder typename_to_strbuilder(CodeTypename self) +{ + StrBuilder result = strbuilder_make_str( _ctx->Allocator_Temp, txt("") ); + typename_to_strbuilder_ref( self, & result ); + return result; +} + +void typename_to_strbuilder_ref(CodeTypename self, StrBuilder* result ) +{ + #if defined(GEN_USE_NEW_TYPENAME_PARSING) + if ( self->ReturnType && self->Params ) + { + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + else + { + if ( self->Specs ) + strbuilder_append_fmt( result, "%SB ( %S ) ( %SB ) %SB", typename_to_strbuilder(self->ReturnType), self->Name, params_to_strbuilder(self->Params), specifiers_to_strbuilder(self->Specs) ); + else + strbuilder_append_fmt( result, "%SB ( %S ) ( %SB )", typename_to_strbuilder(self->ReturnType), self->Name, params_to_strbuilder(self->Params) ); + } + + break; + } + #else + if ( self->ReturnType && self->Params ) + { + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + else + { + if ( self->Specs ) + strbuilder_append_fmt( result, "%SB %S ( %SB ) %SB", typename_to_strbuilder(self->ReturnType), self->Name, params_to_strbuilder(self->Params), specifiers_to_strbuilder(self->Specs) ); + else + strbuilder_append_fmt( result, "%SB %S ( %SB )", typename_to_strbuilder(self->ReturnType), self->Name, params_to_strbuilder(self->Params) ); + } + + return; + } + #endif + + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + + switch ( self->TypeTag ) + { + case Tag_Class : strbuilder_append_str( result, txt("class ")); break; + case Tag_Enum : strbuilder_append_str( result, txt("enum ")); break; + case Tag_Struct : strbuilder_append_str( result, txt("struct ")); break; + case Tag_Union : strbuilder_append_str( result, txt("union ")); break; + default: + break; + } + + if ( self->Specs ) + strbuilder_append_fmt( result, "%S %SB", self->Name, specifiers_to_strbuilder(self->Specs) ); + else + strbuilder_append_fmt( result, "%S", self->Name ); + + if ( self->IsParamPack ) + strbuilder_append_str( result, txt("...")); +} + +StrBuilder union_to_strbuilder(CodeUnion self) +{ + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 512 ); + switch ( self->Type ) + { + case CT_Union: + union_to_strbuilder_def( self, & result ); + break; + case CT_Union_Fwd: + union_to_strbuilder_fwd( self, & result ); + break; + } + return result; +} + +void union_to_strbuilder_def(CodeUnion self, StrBuilder* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + strbuilder_append_str( result, txt("union ") ); + + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + + if ( self->Name.Len ) + { + strbuilder_append_fmt( result, "%S\n{\n%SB\n}" + , self->Name + , body_to_strbuilder(self->Body) + ); + } + else + { + // Anonymous union + strbuilder_append_fmt( result, "\n{\n%SB\n}" + , body_to_strbuilder(self->Body) + ); + } + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + strbuilder_append_str( result, txt(";\n")); +} + +void union_to_strbuilder_fwd(CodeUnion self, StrBuilder* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + strbuilder_append_str( result, txt("union ") ); + + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + + if ( self->Name.Len ) + { + strbuilder_append_fmt( result, "%S", self->Name); + } + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + strbuilder_append_str( result, txt(";\n")); +} + +StrBuilder using_to_strbuilder(CodeUsing self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 ); + switch ( self->Type ) + { + case CT_Using: + using_to_strbuilder_ref( self, & result ); + break; + case CT_Using_Namespace: + using_to_strbuilder_ns( self, & result ); + break; + } + return result; +} + +void using_to_strbuilder_ref(CodeUsing self, StrBuilder* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + + if ( self->UnderlyingType ) + { + strbuilder_append_fmt( result, "using %S = %SB", self->Name, typename_to_strbuilder(self->UnderlyingType) ); + + if ( self->UnderlyingType->ArrExpr ) + { + strbuilder_append_fmt( result, "[ %SB ]", code_to_strbuilder(self->UnderlyingType->ArrExpr) ); + + Code next_arr_expr = self->UnderlyingType->ArrExpr->Next; + while ( next_arr_expr ) + { + strbuilder_append_fmt( result, "[ %SB ]", code_to_strbuilder(next_arr_expr) ); + next_arr_expr = next_arr_expr->Next; + } + } + + strbuilder_append_str( result, txt(";") ); + } + else + strbuilder_append_fmt( result, "using %S;", self->Name ); + + if ( self->InlineCmt ) + strbuilder_append_fmt( result, " %S\n", self->InlineCmt->Content ); + else + strbuilder_append_str( result, txt("\n")); +} + +inline +void using_to_strbuilder_ns(CodeUsing self, StrBuilder* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( self->InlineCmt ) + strbuilder_append_fmt( result, "using namespace $SC; %S", self->Name, self->InlineCmt->Content ); + else + strbuilder_append_fmt( result, "using namespace %S;\n", self->Name ); +} + +inline +StrBuilder var_to_strbuilder(CodeVar self) +{ + GEN_ASSERT(self); + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 256 ); + var_to_strbuilder_ref( self, & result ); + return result; +} + +neverinline +void var_to_strbuilder_ref(CodeVar self, StrBuilder* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( self->Parent && self->Parent->Type == CT_Variable ) + { + // Its a comma-separated variable ( a NextVar ) + + if ( self->Specs ) + strbuilder_append_fmt( result, "%SB ", specifiers_to_strbuilder(self->Specs) ); + + strbuilder_append_str( result, self->Name ); + + if ( self->ValueType && self->ValueType->ArrExpr ) + { + strbuilder_append_fmt( result, "[ %SB ]", code_to_strbuilder(self->ValueType->ArrExpr) ); + + Code next_arr_expr = self->ValueType->ArrExpr->Next; + while ( next_arr_expr ) + { + strbuilder_append_fmt( result, "[ %SB ]", code_to_strbuilder(next_arr_expr) ); + next_arr_expr = next_arr_expr->Next; + } + } + + if ( self->Value ) + { + if ( self->VarParenthesizedInit ) + strbuilder_append_fmt( result, "( %SB ", code_to_strbuilder(self->Value) ); + else + strbuilder_append_fmt( result, " = %SB", code_to_strbuilder(self->Value) ); + } + + // Keep the chain going... + if ( self->NextVar ) + strbuilder_append_fmt( result, ", %SB", var_to_strbuilder(self->NextVar) ); + + if ( self->VarParenthesizedInit ) + strbuilder_append_str( result, txt(" )")); + + return; + } + + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + strbuilder_append_str( result, txt("export ") ); + + if ( self->Attributes || self->Specs ) + { + if ( self->Attributes ) + strbuilder_append_fmt( result, "%SB ", attributes_to_strbuilder(self->Attributes) ); + + if ( self->Specs ) + strbuilder_append_fmt( result, "%SB\n", specifiers_to_strbuilder(self->Specs) ); + + strbuilder_append_fmt( result, "%SB %S", typename_to_strbuilder(self->ValueType), self->Name ); + + if ( self->ValueType && self->ValueType->ArrExpr ) + { + strbuilder_append_fmt( result, "[ %SB ]", code_to_strbuilder(self->ValueType->ArrExpr) ); + + Code next_arr_expr = self->ValueType->ArrExpr->Next; + while ( next_arr_expr ) + { + strbuilder_append_fmt( result, "[ %SB ]", code_to_strbuilder(next_arr_expr) ); + next_arr_expr = next_arr_expr->Next; + } + } + + if ( self->BitfieldSize ) + strbuilder_append_fmt( result, " : %SB", code_to_strbuilder(self->BitfieldSize) ); + + if ( self->Value ) + { + if ( self->VarParenthesizedInit ) + strbuilder_append_fmt( result, "( %SB ", code_to_strbuilder(self->Value) ); + else + strbuilder_append_fmt( result, " = %SB", code_to_strbuilder(self->Value) ); + } + + if ( self->NextVar ) + strbuilder_append_fmt( result, ", %SB", var_to_strbuilder(self->NextVar) ); + + if ( self->VarParenthesizedInit ) + strbuilder_append_str( result, txt(" )")); + + if ( self->InlineCmt ) + strbuilder_append_fmt( result, "; %S", self->InlineCmt->Content); + else + strbuilder_append_str( result, txt(";\n") ); + + return; + } + + if ( self->BitfieldSize ) + strbuilder_append_fmt( result, "%SB %S : %SB", typename_to_strbuilder(self->ValueType), self->Name, code_to_strbuilder(self->BitfieldSize) ); + + else if ( self->ValueType && self->ValueType->ArrExpr ) + { + strbuilder_append_fmt( result, "%SB %S[ %SB ]", typename_to_strbuilder(self->ValueType), self->Name, code_to_strbuilder(self->ValueType->ArrExpr) ); + + Code next_arr_expr = self->ValueType->ArrExpr->Next; + while ( next_arr_expr ) + { + strbuilder_append_fmt( result, "[ %SB ]", code_to_strbuilder(next_arr_expr) ); + next_arr_expr = next_arr_expr->Next; + } + } + + else + strbuilder_append_fmt( result, "%SB %S", typename_to_strbuilder(self->ValueType), self->Name ); + + if ( self->Value ) + { + if ( self->VarParenthesizedInit ) + strbuilder_append_fmt( result, "( %SB ", code_to_strbuilder(self->Value) ); + else + strbuilder_append_fmt( result, " = %SB", code_to_strbuilder(self->Value) ); + } + + if ( self->NextVar ) + strbuilder_append_fmt( result, ", %SB", var_to_strbuilder( self->NextVar) ); + + if ( self->VarParenthesizedInit ) + strbuilder_append_str( result, txt(" )")); + + strbuilder_append_str( result, txt(";") ); + + if ( self->InlineCmt ) + strbuilder_append_fmt( result, " %S", self->InlineCmt->Content); + else + strbuilder_append_str( result, txt("\n")); +} #pragma endregion AST #pragma region Interface -internal void init_parser(); -internal void deinit_parser(); +internal void parser_init(); +internal void parser_deinit(); -internal void* Global_Allocator_Proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ) +internal +void* fallback_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) { - Arena* last = &Global_AllocatorBuckets.back(); + GEN_ASSERT(_ctx); + GEN_ASSERT(_ctx->Fallback_AllocatorBuckets); + Arena* last = array_back(_ctx->Fallback_AllocatorBuckets); switch ( type ) { - case EAllocation_ALLOC : + case EAllocation_ALLOC: { if ( ( last->TotalUsed + size ) > last->TotalSize ) { - Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); + Arena bucket = arena_init_from_allocator( heap(), _ctx->InitSize_Fallback_Allocator_Bucket_Size ); if ( bucket.PhysicalStart == nullptr ) - GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets" ); + GEN_FATAL( "Failed to create bucket for Fallback_AllocatorBuckets"); - if ( ! Global_AllocatorBuckets.append( bucket ) ) - GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets" ); + if ( ! array_append( _ctx->Fallback_AllocatorBuckets, bucket ) ) + GEN_FATAL( "Failed to append bucket to Fallback_AllocatorBuckets"); - last = &Global_AllocatorBuckets.back(); + last = array_back(_ctx->Fallback_AllocatorBuckets); } - return alloc_align( *last, size, alignment ); + return alloc_align( arena_allocator_info(last), size, alignment ); } - case EAllocation_FREE : + case EAllocation_FREE: { // Doesn't recycle. } break; - case EAllocation_FREE_ALL : + case EAllocation_FREE_ALL: { // Memory::cleanup instead. } break; - case EAllocation_RESIZE : + case EAllocation_RESIZE: { if ( last->TotalUsed + size > last->TotalSize ) { - Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); + Arena bucket = arena_init_from_allocator( heap(), _ctx->InitSize_Fallback_Allocator_Bucket_Size ); if ( bucket.PhysicalStart == nullptr ) - GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets" ); + GEN_FATAL( "Failed to create bucket for Fallback_AllocatorBuckets"); - if ( ! Global_AllocatorBuckets.append( bucket ) ) - GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets" ); + if ( ! array_append( _ctx->Fallback_AllocatorBuckets, bucket ) ) + GEN_FATAL( "Failed to append bucket to Fallback_AllocatorBuckets"); - last = &Global_AllocatorBuckets.back(); + last = array_back( _ctx->Fallback_AllocatorBuckets); } void* result = alloc_align( last->Backing, size, alignment ); @@ -14596,477 +16221,493 @@ internal void* Global_Allocator_Proc( void* allocator_data, AllocType type, sw s return nullptr; } -internal void define_constants() +internal +void define_constants() { - Code::Global = make_code(); - Code::Global->Name = get_cached_string( txt( "Global Code" ) ); - Code::Global->Content = Code::Global->Name; + // We only initalize these if there is no base context. + if ( context_counter > 0 ) + return; - Code::Invalid = make_code(); - Code::Invalid.set_global(); + Code_Global = make_code(); + Code_Global->Name = cache_str( txt("Global Code") ); + Code_Global->Content = Code_Global->Name; - t_empty = ( CodeType )make_code(); - t_empty->Type = ECode::Typename; - t_empty->Name = get_cached_string( txt( "" ) ); - t_empty.set_global(); + Code_Invalid = make_code(); + code_set_global(Code_Invalid); + + t_empty = (CodeTypename) make_code(); + t_empty->Type = CT_Typename; + t_empty->Name = cache_str( txt("") ); + code_set_global(cast(Code, t_empty)); access_private = make_code(); - access_private->Type = ECode::Access_Private; - access_private->Name = get_cached_string( txt( "private:" ) ); - access_private.set_global(); + access_private->Type = CT_Access_Private; + access_private->Name = cache_str( txt("private:\n") ); + code_set_global(cast(Code, access_private)); access_protected = make_code(); - access_protected->Type = ECode::Access_Protected; - access_protected->Name = get_cached_string( txt( "protected:" ) ); - access_protected.set_global(); + access_protected->Type = CT_Access_Protected; + access_protected->Name = cache_str( txt("protected:\n") ); + code_set_global(access_protected); access_public = make_code(); - access_public->Type = ECode::Access_Public; - access_public->Name = get_cached_string( txt( "public:" ) ); - access_public.set_global(); + access_public->Type = CT_Access_Public; + access_public->Name = cache_str( txt("public:\n") ); + code_set_global(access_public); - attrib_api_export = def_attributes( code( GEN_API_Export_Code ) ); - attrib_api_export.set_global(); + Str api_export_str = code(GEN_API_Export_Code); + attrib_api_export = def_attributes( api_export_str ); + code_set_global(cast(Code, attrib_api_export)); - attrib_api_import = def_attributes( code( GEN_API_Import_Code ) ); - attrib_api_import.set_global(); + Str api_import_str = code(GEN_API_Import_Code); + attrib_api_import = def_attributes( api_import_str ); + code_set_global(cast(Code, 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->Type = CT_Untyped; + module_global_fragment->Name = cache_str( txt("module;") ); module_global_fragment->Content = module_global_fragment->Name; - module_global_fragment.set_global(); + code_set_global(cast(Code, 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->Type = CT_Untyped; + module_private_fragment->Name = cache_str( txt("module : private;") ); module_private_fragment->Content = module_private_fragment->Name; - module_private_fragment.set_global(); + code_set_global(cast(Code, module_private_fragment)); - fmt_newline = make_code(); - fmt_newline->Type = ECode::NewLine; - fmt_newline.set_global(); + fmt_newline = make_code(); + fmt_newline->Type = CT_NewLine; + code_set_global((Code)fmt_newline); - pragma_once = ( CodePragma )make_code(); - pragma_once->Type = ECode::Preprocess_Pragma; - pragma_once->Name = get_cached_string( txt( "once" ) ); + pragma_once = (CodePragma) make_code(); + pragma_once->Type = CT_Preprocess_Pragma; + pragma_once->Name = cache_str( txt("once") ); pragma_once->Content = pragma_once->Name; - pragma_once.set_global(); + code_set_global((Code)pragma_once); - param_varadic = ( CodeType )make_code(); - param_varadic->Type = ECode::Parameters; - param_varadic->Name = get_cached_string( txt( "..." ) ); + param_varadic = (CodeParams) make_code(); + param_varadic->Type = CT_Parameters; + param_varadic->Name = cache_str( txt("...") ); param_varadic->ValueType = t_empty; - param_varadic.set_global(); + code_set_global((Code)param_varadic); - preprocess_else = ( CodePreprocessCond )make_code(); - preprocess_else->Type = ECode::Preprocess_Else; - preprocess_else.set_global(); + preprocess_else = (CodePreprocessCond) make_code(); + preprocess_else->Type = CT_Preprocess_Else; + code_set_global((Code)preprocess_else); - preprocess_endif = ( CodePreprocessCond )make_code(); - preprocess_endif->Type = ECode::Preprocess_EndIf; - preprocess_endif.set_global(); + preprocess_endif = (CodePreprocessCond) make_code(); + preprocess_endif->Type = CT_Preprocess_EndIf; + code_set_global((Code)preprocess_endif); -#define def_constant_code_type( Type_ ) \ - t_##Type_ = def_type( name( Type_ ) ); \ - t_##Type_.set_global(); - - def_constant_code_type( auto ); - def_constant_code_type( void ); - def_constant_code_type( int ); - def_constant_code_type( bool ); - def_constant_code_type( char ); - def_constant_code_type( wchar_t ); - def_constant_code_type( class ); - def_constant_code_type( typename ); + Str auto_str = txt("auto"); t_auto = def_type( auto_str ); code_set_global( t_auto ); + Str void_str = txt("void"); t_void = def_type( void_str ); code_set_global( t_void ); + Str int_str = txt("int"); t_int = def_type( int_str ); code_set_global( t_int ); + Str bool_str = txt("bool"); t_bool = def_type( bool_str ); code_set_global( t_bool ); + Str char_str = txt("char"); t_char = def_type( char_str ); code_set_global( t_char ); + Str wchar_str = txt("wchar_t"); t_wchar_t = def_type( wchar_str ); code_set_global( t_wchar_t ); + Str class_str = txt("class"); t_class = def_type( class_str ); code_set_global( t_class ); + Str typename_str = txt("typename"); t_typename = def_type( typename_str ); code_set_global( t_typename ); #ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS - t_b32 = def_type( name( b32 ) ); + t_b32 = def_type( name(b32) ); code_set_global( t_b32 ); - def_constant_code_type( s8 ); - def_constant_code_type( s16 ); - def_constant_code_type( s32 ); - def_constant_code_type( s64 ); + Str s8_str = txt("s8"); t_s8 = def_type( s8_str ); code_set_global( t_s8 ); + Str s16_str = txt("s16"); t_s16 = def_type( s16_str ); code_set_global( t_s16 ); + Str s32_str = txt("s32"); t_s32 = def_type( s32_str ); code_set_global( t_s32 ); + Str s64_str = txt("s64"); t_s64 = def_type( s64_str ); code_set_global( t_s64 ); - def_constant_code_type( u8 ); - def_constant_code_type( u16 ); - def_constant_code_type( u32 ); - def_constant_code_type( u64 ); + Str u8_str = txt("u8"); t_u8 = def_type( u8_str ); code_set_global( t_u8 ); + Str u16_str = txt("u16"); t_u16 = def_type( u16_str ); code_set_global( t_u16 ); + Str u32_str = txt("u32"); t_u32 = def_type( u32_str ); code_set_global( t_u32 ); + Str u64_str = txt("u64"); t_u64 = def_type( u64_str ); code_set_global( t_u64 ); - def_constant_code_type( sw ); - def_constant_code_type( uw ); + Str ssize_str = txt("ssize"); t_ssize = def_type( ssize_str ); code_set_global( t_ssize ); + Str usize_str = txt("usize"); t_usize = def_type( usize_str ); code_set_global( t_usize ); - def_constant_code_type( f32 ); - def_constant_code_type( f64 ); + Str f32_str = txt("f32"); t_f32 = def_type( f32_str ); code_set_global( t_f32 ); + Str f64_str = txt("f64"); t_f64 = def_type( f64_str ); code_set_global( t_f64 ); #endif -#undef def_constant_code_type + spec_const = def_specifier( Spec_Const); code_set_global( cast(Code, spec_const )); + spec_consteval = def_specifier( Spec_Consteval); code_set_global( cast(Code, spec_consteval ));; + spec_constexpr = def_specifier( Spec_Constexpr); code_set_global( cast(Code, spec_constexpr ));; + spec_constinit = def_specifier( Spec_Constinit); code_set_global( cast(Code, spec_constinit ));; + spec_extern_linkage = def_specifier( Spec_External_Linkage); code_set_global( cast(Code, spec_extern_linkage ));; + spec_final = def_specifier( Spec_Final); code_set_global( cast(Code, spec_final ));; + spec_forceinline = def_specifier( Spec_ForceInline); code_set_global( cast(Code, spec_forceinline ));; + spec_global = def_specifier( Spec_Global); code_set_global( cast(Code, spec_global ));; + spec_inline = def_specifier( Spec_Inline); code_set_global( cast(Code, spec_inline ));; + spec_internal_linkage = def_specifier( Spec_Internal_Linkage); code_set_global( cast(Code, spec_internal_linkage ));; + spec_local_persist = def_specifier( Spec_Local_Persist); code_set_global( cast(Code, spec_local_persist ));; + spec_mutable = def_specifier( Spec_Mutable); code_set_global( cast(Code, spec_mutable ));; + spec_neverinline = def_specifier( Spec_NeverInline); code_set_global( cast(Code, spec_neverinline ));; + spec_noexcept = def_specifier( Spec_NoExceptions); code_set_global( cast(Code, spec_noexcept ));; + spec_override = def_specifier( Spec_Override); code_set_global( cast(Code, spec_override ));; + spec_ptr = def_specifier( Spec_Ptr); code_set_global( cast(Code, spec_ptr ));; + spec_pure = def_specifier( Spec_Pure); code_set_global( cast(Code, spec_pure )); + spec_ref = def_specifier( Spec_Ref); code_set_global( cast(Code, spec_ref ));; + spec_register = def_specifier( Spec_Register); code_set_global( cast(Code, spec_register ));; + spec_rvalue = def_specifier( Spec_RValue); code_set_global( cast(Code, spec_rvalue ));; + spec_static_member = def_specifier( Spec_Static); code_set_global( cast(Code, spec_static_member ));; + spec_thread_local = def_specifier( Spec_Thread_Local); code_set_global( cast(Code, spec_thread_local ));; + spec_virtual = def_specifier( Spec_Virtual); code_set_global( cast(Code, spec_virtual ));; + spec_volatile = def_specifier( Spec_Volatile); code_set_global( cast(Code, spec_volatile )); -#define def_constant_spec( Type_, ... ) \ - spec_##Type_ = def_specifiers( num_args( __VA_ARGS__ ), __VA_ARGS__ ); \ - spec_##Type_.set_global(); + spec_local_persist = def_specifiers( 1, Spec_Local_Persist ); + code_set_global(cast(Code, spec_local_persist)); -#pragma push_macro( "forceinline" ) -#pragma push_macro( "global" ) -#pragma push_macro( "internal" ) -#pragma push_macro( "local_persist" ) -#pragma push_macro( "neverinline" ) -#undef forceinline -#undef global -#undef internal -#undef local_persist -#undef neverinline - def_constant_spec( const, ESpecifier::Const ); - def_constant_spec( consteval, ESpecifier::Consteval ); - def_constant_spec( constexpr, ESpecifier::Constexpr ); - def_constant_spec( constinit, ESpecifier::Constinit ); - def_constant_spec( extern_linkage, ESpecifier::External_Linkage ); - def_constant_spec( final, ESpecifier::Final ); - def_constant_spec( forceinline, ESpecifier::ForceInline ); - def_constant_spec( global, ESpecifier::Global ); - def_constant_spec( inline, ESpecifier::Inline ); - def_constant_spec( internal_linkage, ESpecifier::Internal_Linkage ); - def_constant_spec( local_persist, ESpecifier::Local_Persist ); - def_constant_spec( mutable, ESpecifier::Mutable ); - def_constant_spec( neverinline, ESpecifier::NeverInline ); - def_constant_spec( noexcept, ESpecifier::NoExceptions ); - def_constant_spec( override, ESpecifier::Override ); - def_constant_spec( ptr, ESpecifier::Ptr ); - def_constant_spec( pure, ESpecifier::Pure ) def_constant_spec( ref, ESpecifier::Ref ); - def_constant_spec( register, ESpecifier::Register ); - def_constant_spec( rvalue, ESpecifier::RValue ); - def_constant_spec( static_member, ESpecifier::Static ); - def_constant_spec( thread_local, ESpecifier::Thread_Local ); - def_constant_spec( virtual, ESpecifier::Virtual ); - def_constant_spec( volatile, ESpecifier::Volatile ) - - spec_local_persist = def_specifiers( 1, ESpecifier::Local_Persist ); - spec_local_persist.set_global(); - -#pragma pop_macro( "forceinline" ) -#pragma pop_macro( "global" ) -#pragma pop_macro( "internal" ) -#pragma pop_macro( "local_persist" ) -#pragma pop_macro( "neverinline" ) - -#undef def_constant_spec + if (enum_underlying_sig.Len == 0) { + enum_underlying_sig = txt("enum_underlying("); + } + array_append( _ctx->PreprocessorDefines, enum_underlying_sig); } -void init() +void init(Context* ctx) { - // Setup global allocator - { - GlobalAllocator = AllocatorInfo { &Global_Allocator_Proc, nullptr }; - - Global_AllocatorBuckets = Array< Arena >::init_reserve( heap(), 128 ); - - if ( Global_AllocatorBuckets == nullptr ) - GEN_FATAL( "Failed to reserve memory for Global_AllocatorBuckets" ); - - 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 ); + do_once() { + context_counter = 0; } + AllocatorInfo fallback_allocator = { & fallback_allocator_proc, nullptr }; + + b32 using_fallback_allocator = false; + if (ctx->Allocator_DyanmicContainers.Proc == nullptr) { + ctx->Allocator_DyanmicContainers = fallback_allocator; + using_fallback_allocator = true; + } + if (ctx->Allocator_Pool.Proc == nullptr ) { + ctx->Allocator_Pool = fallback_allocator; + using_fallback_allocator = true; + } + if (ctx->Allocator_StrCache.Proc == nullptr) { + ctx->Allocator_StrCache = fallback_allocator; + using_fallback_allocator = true; + } + if (ctx->Allocator_Temp.Proc == nullptr) { + ctx->Allocator_Temp = fallback_allocator; + using_fallback_allocator = true; + } + // Setup fallback allocator + if (using_fallback_allocator) + { + ctx->Fallback_AllocatorBuckets = array_init_reserve(Arena, heap(), 128 ); + if ( ctx->Fallback_AllocatorBuckets == nullptr ) + GEN_FATAL( "Failed to reserve memory for Fallback_AllocatorBuckets"); + + Arena bucket = arena_init_from_allocator( heap(), ctx->InitSize_Fallback_Allocator_Bucket_Size ); + if ( bucket.PhysicalStart == nullptr ) + GEN_FATAL( "Failed to create first bucket for Fallback_AllocatorBuckets"); + + array_append( ctx->Fallback_AllocatorBuckets, bucket ); + } + + if (ctx->Max_CommentLineLength == 0) { + ctx->Max_CommentLineLength = 1024; + } + if (ctx->Max_StrCacheLength == 0) { + ctx->Max_StrCacheLength = kilobytes(512); + } + + if (ctx->InitSize_BuilderBuffer == 0) { + ctx->InitSize_BuilderBuffer = megabytes(2); + } + if (ctx->InitSize_CodePoolsArray == 0) { + ctx->InitSize_CodePoolsArray = 16; + } + if (ctx->InitSize_StringArenasArray == 0) { + ctx->InitSize_StringArenasArray = 16; + } + if (ctx->CodePool_NumBlocks == 0) { + ctx->CodePool_NumBlocks = kilobytes(16); + } + + if (ctx->InitSize_LexArena == 0 ) { + ctx->InitSize_LexArena = megabytes(4); + } + if (ctx->SizePer_StringArena == 0) { + ctx->SizePer_StringArena = megabytes(1); + } + + if (ctx->InitSize_Fallback_Allocator_Bucket_Size == 0) { + ctx->InitSize_Fallback_Allocator_Bucket_Size = megabytes(8); + } + + // Override the current context (user has to put it back if unwanted). + _ctx = ctx; // Setup the arrays { - CodePools = Array< Pool >::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); - - if ( CodePools == nullptr ) + ctx->CodePools = array_init_reserve(Pool, ctx->Allocator_DyanmicContainers, ctx->InitSize_CodePoolsArray ); + if ( ctx->CodePools == nullptr ) GEN_FATAL( "gen::init: Failed to initialize the CodePools array" ); - StringArenas = Array< Arena >::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); - - if ( StringArenas == nullptr ) + ctx->StringArenas = array_init_reserve(Arena, ctx->Allocator_DyanmicContainers, ctx->InitSize_StringArenasArray ); + if ( ctx->StringArenas == nullptr ) GEN_FATAL( "gen::init: Failed to initialize the StringArenas array" ); } - // Setup the code pool and code entries arena. { - Pool code_pool = Pool::init( Allocator_CodePool, CodePool_NumBlocks, sizeof( AST ) ); - + Pool code_pool = pool_init( ctx->Allocator_Pool, ctx->CodePool_NumBlocks, sizeof(AST) ); if ( code_pool.PhysicalStart == nullptr ) GEN_FATAL( "gen::init: Failed to initialize the code pool" ); + array_append( ctx->CodePools, code_pool ); - CodePools.append( code_pool ); + // TODO(Ed): This is going to be phased out most likely. + ctx->LexArena = arena_init_from_allocator( ctx->Allocator_DyanmicContainers, ctx->InitSize_LexArena ); - LexArena = Arena::init_from_allocator( Allocator_Lexer, LexAllocator_Size ); - - Arena string_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena ); - - if ( string_arena.PhysicalStart == nullptr ) + // TODO(Ed): Eventually the string arenas needs to be phased out for a dedicated string slab allocator + Arena strbuilder_arena = arena_init_from_allocator( ctx->Allocator_StrCache, ctx->SizePer_StringArena ); + if ( strbuilder_arena.PhysicalStart == nullptr ) GEN_FATAL( "gen::init: Failed to initialize the string arena" ); - - StringArenas.append( string_arena ); + array_append( ctx->StringArenas, strbuilder_arena ); } - // Setup the hash tables { - StringCache = StringTable::init( Allocator_StringTable ); - - if ( StringCache.Entries == nullptr ) - GEN_FATAL( "gen::init: Failed to initialize the StringCache" ); + ctx->StrCache = hashtable_init(StrCached, ctx->Allocator_DyanmicContainers); + if ( ctx->StrCache.Entries == nullptr ) + GEN_FATAL( "gen::init: Failed to initialize the StringCache"); } + // Preprocessor Defines + ctx->PreprocessorDefines = array_init_reserve(StrCached, ctx->Allocator_DyanmicContainers, kilobytes(1) ); define_constants(); - init_parser(); + parser_init(); + + ++ context_counter; } -void deinit() +void deinit(Context* ctx) { - uw index = 0; - uw left = CodePools.num(); + GEN_ASSERT(context_counter); + GEN_ASSERT_MSG(context_counter > 0, "Attempted to deinit a context that for some reason wan't accounted for!"); + usize index = 0; + usize left = array_num(ctx->CodePools); do { - Pool* code_pool = &CodePools[ index ]; - code_pool->free(); + Pool* code_pool = & ctx->CodePools[index]; + pool_free(code_pool); index++; - } while ( left--, left ); + } + while ( left--, left ); index = 0; - left = StringArenas.num(); + left = array_num(ctx->StringArenas); do { - Arena* string_arena = &StringArenas[ index ]; - string_arena->free(); + Arena* strbuilder_arena = & ctx->StringArenas[index]; + arena_free(strbuilder_arena); index++; - } while ( left--, left ); + } + while ( left--, left ); - StringCache.destroy(); + hashtable_destroy(ctx->StrCache); - CodePools.free(); - StringArenas.free(); + array_free( ctx->CodePools); + array_free( ctx->StringArenas); - LexArena.free(); + arena_free(& ctx->LexArena); - index = 0; - left = Global_AllocatorBuckets.num(); - do + array_free(ctx->PreprocessorDefines); + + left = array_num( ctx->Fallback_AllocatorBuckets); + if (left) { - Arena* bucket = &Global_AllocatorBuckets[ index ]; - bucket->free(); - index++; - } while ( left--, left ); + index = 0; + do + { + Arena* bucket = & ctx->Fallback_AllocatorBuckets[ index ]; + arena_free(bucket); + index++; + } + while ( left--, left ); + array_free( ctx->Fallback_AllocatorBuckets); + } + parser_deinit(); - Global_AllocatorBuckets.free(); - deinit_parser(); + if (_ctx == ctx) + _ctx = nullptr; + -- context_counter; } -void reset() +void reset(Context* ctx) { s32 index = 0; - s32 left = CodePools.num(); + s32 left = array_num(ctx->CodePools); do { - Pool* code_pool = &CodePools[ index ]; - code_pool->clear(); + Pool* code_pool = & ctx->CodePools[index]; + pool_clear(code_pool); index++; - } while ( left--, left ); + } + while ( left--, left ); index = 0; - left = StringArenas.num(); + left = array_num(ctx->StringArenas); do { - Arena* string_arena = &StringArenas[ index ]; - string_arena->TotalUsed = 0; - ; + Arena* strbuilder_arena = & ctx->StringArenas[index]; + strbuilder_arena->TotalUsed = 0;; index++; - } while ( left--, left ); - - StringCache.clear(); + } + while ( left--, left ); + hashtable_clear(ctx->StrCache); define_constants(); } -AllocatorInfo get_string_allocator( s32 str_length ) +void set_context(Context* new_ctx) { + GEN_ASSERT(new_ctx); + _ctx = new_ctx; +} + +AllocatorInfo get_cached_str_allocator( s32 str_length ) { - Arena* last = &StringArenas.back(); - - uw size_req = str_length + sizeof( String::Header ) + sizeof( char* ); - - if ( last->TotalUsed + size_req > last->TotalSize ) + Arena* last = array_back(_ctx->StringArenas); + usize size_req = str_length + sizeof(StrBuilderHeader) + sizeof(char*); + if ( last->TotalUsed + scast(ssize, size_req) > last->TotalSize ) { - Arena new_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena ); + Arena new_arena = arena_init_from_allocator( _ctx->Allocator_StrCache, _ctx->SizePer_StringArena ); + if ( ! array_append( _ctx->StringArenas, new_arena ) ) + GEN_FATAL( "gen::get_cached_str_allocator: Failed to allocate a new string arena" ); - if ( ! StringArenas.append( new_arena ) ) - GEN_FATAL( "gen::get_string_allocator: Failed to allocate a new string arena" ); - - last = &StringArenas.back(); + last = array_back( _ctx->StringArenas); } - - return *last; + return arena_allocator_info(last); } // Will either make or retrive a code string. -StringCached get_cached_string( StrC str ) +StrCached cache_str( Str str ) { - s32 hash_length = str.Len > kilobytes( 1 ) ? kilobytes( 1 ) : str.Len; - u64 key = crc32( str.Ptr, hash_length ); - { - StringCached* result = StringCache.get( key ); - - if ( result ) - return *result; + if (str.Len > _ctx->Max_StrCacheLength) { + // Do not cache the string, just shove into the arena and and return it. + Str result = strbuilder_to_str( strbuilder_make_str( get_cached_str_allocator( str.Len ), str )); + return result; } - - String result = String::make( get_string_allocator( str.Len ), str ); - StringCache.set( key, result ); - + u64 key = crc32( str.Ptr, str.Len ); { + StrCached* result = hashtable_get( _ctx->StrCache, key ); + if ( result ) + return * result; + } + Str result = strbuilder_to_str( strbuilder_make_str( get_cached_str_allocator( str.Len ), str )); + hashtable_set( _ctx->StrCache, key, result ); return result; } // Used internally to retireve a Code object form the CodePool. Code make_code() { - Pool* allocator = &CodePools.back(); + Pool* allocator = array_back( _ctx->CodePools); if ( allocator->FreeList == nullptr ) { - Pool code_pool = Pool::init( Allocator_CodePool, CodePool_NumBlocks, sizeof( AST ) ); + Pool code_pool = pool_init( _ctx->Allocator_Pool, _ctx->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 ( ! array_append( _ctx->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 = array_back( _ctx->CodePools); } - - Code result { rcast( AST*, alloc( *allocator, sizeof( AST ) ) ) }; - // mem_set( result.ast, 0, sizeof(AST) ); - result->Type = ECode::Invalid; - - result->Content = { nullptr }; - result->Prev = { nullptr }; - result->Next = { nullptr }; - result->Token = nullptr; - result->Parent = { nullptr }; - result->Name = { nullptr }; - result->Type = ECode::Invalid; - result->ModuleFlags = ModuleFlag::Invalid; - result->NumEntries = 0; - + Code result = { rcast( AST*, alloc( pool_allocator_info(allocator), sizeof(AST) )) }; + mem_set( rcast(void*, cast(AST*, result)), 0, sizeof(AST) ); return result; } -void set_allocator_data_arrays( AllocatorInfo allocator ) -{ - Allocator_DataArrays = allocator; -} - -void set_allocator_code_pool( AllocatorInfo allocator ) -{ - Allocator_CodePool = allocator; -} - -void set_allocator_lexer( AllocatorInfo allocator ) -{ - Allocator_Lexer = allocator; -} - -void set_allocator_string_arena( AllocatorInfo allocator ) -{ - Allocator_StringArena = allocator; -} - -void set_allocator_string_table( AllocatorInfo allocator ) -{ - Allocator_StringArena = allocator; +void set_preprocess_define( Str id, b32 is_functional ) { + StrBuilder builder = strbuilder_make_str( _ctx->Allocator_Temp, id ); + if (is_functional) { + strbuilder_append_char( & builder, '(' ); + } + array_append( _ctx->PreprocessorDefines, cache_str( strbuilder_to_str(builder)) ); } #pragma region Upfront -enum class OpValidateResult : u32 +enum OpValidateResult : u32 { - Fail, - Global, - Member + OpValResult_Fail, + OpValResult_Global, + OpValResult_Member }; -OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeType ret_type, CodeSpecifiers specifier ) +internal neverinline +OpValidateResult operator__validate( Operator op, CodeParams params_code, CodeTypename ret_type, CodeSpecifiers specifier ) { - using namespace EOperator; - - if ( op == EOperator::Invalid ) + if ( op == Op_Invalid ) { - log_failure( "gen::def_operator: op cannot be invalid" ); - return OpValidateResult::Fail; + log_failure("gen::def_operator: op cannot be invalid"); + return OpValResult_Fail; } #pragma region Helper Macros -#define check_params() \ - if ( ! params_code ) \ - { \ - log_failure( "gen::def_operator: params is null and operator%s requires it", to_str( op ) ); \ - return OpValidateResult::Fail; \ - } \ - if ( params_code->Type != ECode::Parameters ) \ - { \ - log_failure( "gen::def_operator: params is not of Parameters type - %s", params_code.debug_str() ); \ - return OpValidateResult::Fail; \ +# define check_params() \ + if ( ! params_code ) \ + { \ + log_failure("gen::def_operator: params is null and operator%S requires it", operator_to_str(op)); \ + return OpValResult_Fail; \ + } \ + if ( params_code->Type != CT_Parameters ) \ + { \ + log_failure("gen::def_operator: params is not of Parameters type - %S", code_debug_str( cast(Code, params_code))); \ + return OpValResult_Fail; \ } -#define check_param_eq_ret() \ - if ( ! is_member_symbol && ! params_code->ValueType.is_equal( ret_type ) ) \ - { \ - log_failure( \ - "gen::def_operator: operator%s requires first parameter to equal return type\n" \ - "param types: %s\n" \ - "return type: %s", \ - to_str( op ).Ptr, \ - params_code.debug_str(), \ - ret_type.debug_str() \ - ); \ - return OpValidateResult::Fail; \ +# define check_param_eq_ret() \ + if ( ! is_member_symbol && ! code_is_equal(cast(Code, params_code->ValueType), cast(Code, ret_type)) ) \ + { \ + log_failure("gen::def_operator: operator%S requires first parameter to equal return type\n" \ + "param types: %S\n" \ + "return type: %S", \ + operator_to_str(op).Ptr, \ + code_debug_str(cast(Code, params_code)), \ + code_debug_str(cast(Code, ret_type)) \ + ); \ + return OpValResult_Fail; \ } #pragma endregion Helper Macros if ( ! ret_type ) { - log_failure( "gen::def_operator: ret_type is null but is required by operator%s", to_str( op ) ); + log_failure("gen::def_operator: ret_type is null but is required by operator%S", operator_to_str(op)); } - if ( ret_type->Type != ECode::Typename ) + if ( ret_type->Type != CT_Typename ) { - log_failure( "gen::def_operator: ret_type is not of typename type - %s", ret_type.debug_str() ); - return OpValidateResult::Fail; + log_failure("gen::def_operator: ret_type is not of typename type - %S", code_debug_str(cast(Code, ret_type))); + return OpValResult_Fail; } bool is_member_symbol = false; switch ( op ) { -#define specs( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__ - case Assign : +# define specs( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__ + case Op_Assign: check_params(); if ( params_code->NumEntries > 1 ) { - log_failure( - "gen::def_operator: " - "operator%s does not support non-member definition (more than one parameter provided) - %s", - to_str( op ), - params_code.debug_str() + log_failure("gen::def_operator: " + "operator%S does not support non-member definition (more than one parameter provided) - %S", + operator_to_str(op), + code_debug_str(cast(Code, params_code)) ); - return OpValidateResult::Fail; + return OpValResult_Fail; } is_member_symbol = true; break; - case Assign_Add : - case Assign_Subtract : - case Assign_Multiply : - case Assign_Divide : - case Assign_Modulo : - case Assign_BAnd : - case Assign_BOr : - case Assign_BXOr : - case Assign_LShift : - case Assign_RShift : + case Op_Assign_Add: + case Op_Assign_Subtract: + case Op_Assign_Multiply: + case Op_Assign_Divide: + case Op_Assign_Modulo: + case Op_Assign_BAnd: + case Op_Assign_BOr: + case Op_Assign_BXOr: + case Op_Assign_LShift: + case Op_Assign_RShift: check_params(); if ( params_code->NumEntries == 1 ) @@ -15075,220 +16716,249 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy else check_param_eq_ret(); - if ( params_code->NumEntries > 2 ) + if (params_code->NumEntries > 2 ) { - log_failure( - "gen::def_operator: operator%s may not be defined with more than two parametes - param count; %d\n%s", - to_str( op ), - params_code->NumEntries, - params_code.debug_str() + log_failure("gen::def_operator: operator%S may not be defined with more than two parametes - param count; %d\n%S" + , operator_to_str(op) + , params_code->NumEntries + , code_debug_str(cast(Code, params_code)) ); - return OpValidateResult::Fail; + return OpValResult_Fail; } break; - case Increment : - case Decrement : + case Op_Increment: + case Op_Decrement: // If its not set, it just means its a prefix member op. if ( params_code ) { - if ( params_code->Type != ECode::Parameters ) + if ( params_code->Type != CT_Parameters ) { - log_failure( "gen::def_operator: operator%s params code provided is not of Parameters type - %s", to_str( op ), params_code.debug_str() ); - return OpValidateResult::Fail; + log_failure("gen::def_operator: operator%S params code provided is not of Parameters type - %S" + , operator_to_str(op) + , code_debug_str(cast(Code, params_code)) + ); + return OpValResult_Fail; } switch ( params_code->NumEntries ) { - case 1 : - if ( params_code->ValueType.is_equal( t_int ) ) + case 1: + if ( code_is_equal((Code)params_code->ValueType, (Code)t_int ) ) is_member_symbol = true; else check_param_eq_ret(); break; - case 2 : + case 2: check_param_eq_ret(); - if ( ! params_code.get( 1 ).is_equal( t_int ) ) + if ( ! code_is_equal((Code)params_get(params_code, 1), (Code)t_int ) ) { - log_failure( - "gen::def_operator: " - "operator%s requires second parameter of non-member definition to be int for post-decrement", - to_str( op ) + log_failure("gen::def_operator: " + "operator%S requires second parameter of non-member definition to be int for post-decrement", + operator_to_str(op) ); - return OpValidateResult::Fail; + return OpValResult_Fail; } break; - default : - log_failure( - "gen::def_operator: operator%s recieved unexpected number of parameters recived %d instead of 0-2", - to_str( op ), - params_code->NumEntries + default: + log_failure("gen::def_operator: operator%S recieved unexpected number of parameters recived %d instead of 0-2" + , operator_to_str(op) + , params_code->NumEntries ); - return OpValidateResult::Fail; + return OpValResult_Fail; } } break; - case Unary_Plus : - case Unary_Minus : - case BNot : + case Op_Unary_Plus: + case Op_Unary_Minus: if ( ! params_code ) is_member_symbol = true; else { - if ( params_code->Type != ECode::Parameters ) + if ( params_code->Type != CT_Parameters ) { - log_failure( "gen::def_operator: params is not of Parameters type - %s", params_code.debug_str() ); - return OpValidateResult::Fail; + log_failure("gen::def_operator: params is not of Parameters type - %S", code_debug_str((Code)params_code)); + return OpValResult_Fail; } - if ( params_code->ValueType.is_equal( ret_type ) ) + if ( code_is_equal((Code)params_code->ValueType, (Code)ret_type ) ) { - log_failure( - "gen::def_operator: " - "operator%s is non-member symbol yet first paramter does not equal return type\n" - "param type: %s\n" - "return type: %s\n", - params_code.debug_str(), - ret_type.debug_str() + log_failure("gen::def_operator: " + "operator%S is non-member symbol yet first paramter does not equal return type\n" + "param type: %S\n" + "return type: %S\n" + , operator_to_str(op) + , code_debug_str((Code)params_code) + , code_debug_str((Code)ret_type) ); - return OpValidateResult::Fail; + return OpValResult_Fail; + } + + if ( params_code->NumEntries > 1 ) + { + log_failure("gen::def_operator: operator%S may not have more than one parameter - param count: %d" + , operator_to_str(op) + , params_code->NumEntries + ); + return OpValResult_Fail; + } + } + break; + + case Op_BNot: + { + // Some compilers let you do this... + #if 0 + if ( ! ret_type.is_equal( t_bool) ) + { + log_failure( "gen::def_operator: return type is not a boolean - %S", code_debug_str(params_code) ); + return OpValidateResult::Fail; + } + #endif + + if ( ! params_code ) + is_member_symbol = true; + + else + { + if ( params_code->Type != CT_Parameters ) + { + log_failure( "gen::def_operator: params is not of Parameters type - %S", code_debug_str((Code)params_code) ); + return OpValResult_Fail; } if ( params_code->NumEntries > 1 ) { log_failure( - "gen::def_operator: operator%s may not have more than one parameter - param count: %d", - to_str( op ), - params_code->NumEntries + "gen::def_operator: operator%S may not have more than one parameter - param count: %d", + operator_to_str( op ), + params_code->NumEntries ); - return OpValidateResult::Fail; + return OpValResult_Fail; } } break; + } - case Add : - case Subtract : - case Multiply : - case Divide : - case Modulo : - case BAnd : - case BOr : - case BXOr : - case LShift : - case RShift : + case Op_Add: + case Op_Subtract: + case Op_Multiply: + case Op_Divide: + case Op_Modulo: + case Op_BAnd: + case Op_BOr: + case Op_BXOr: + case Op_LShift: + case Op_RShift: check_params(); switch ( params_code->NumEntries ) { - case 1 : + case 1: is_member_symbol = true; break; - case 2 : - break; - // Its not required by c++ to have this constraint so I'm omitting it. -#if 0 - if ( ! params_code->ValueType.is_equal( ret_type ) && ! params_code->Next.is_equal( ret_type ) ) - { - log_failure( - "gen::def_operator: " - "operator%s is non-member symbol yet first paramter does not equal return type\n" - "param type: %s\n" - "return type: %s\n", - params_code.debug_str(), - ret_type.debug_str() - ); - return OpValidateResult::Fail; - } + case 2: + // This is allowed. + // if ( ! code_is_equal((Code)params_code->ValueType, (Code)ret_type ) ) + // { + // log_failure("gen::def_operator: " + // "operator%S is non-member symbol yet first paramter does not equal return type\n" + // "param type: %S\n" + // "return type: %S\n" + // , operator_to_str(op) + // , code_debug_str((Code)params_code) + // , code_debug_str((Code)ret_type) + // ); + // return OpValResult_Fail; + // } break; -#endif - default : - log_failure( - "gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 0-2", - to_str( op ), - params_code->NumEntries + default: + log_failure("gen::def_operator: operator%S recieved unexpected number of paramters recived %d instead of 0-2" + , operator_to_str(op) + , params_code->NumEntries ); - return OpValidateResult::Fail; + return OpValResult_Fail; } break; - case UnaryNot : + case Op_UnaryNot: if ( ! params_code ) is_member_symbol = true; else { - if ( params_code->Type != ECode::Parameters ) + if ( params_code->Type != CT_Parameters ) { - log_failure( "gen::def_operator: params is not of Parameters type - %s", params_code.debug_str() ); - return OpValidateResult::Fail; + log_failure("gen::def_operator: params is not of Parameters type - %S", code_debug_str((Code)params_code)); + return OpValResult_Fail; } if ( params_code->NumEntries != 1 ) { - log_failure( - "gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 0-1", - to_str( op ), - params_code->NumEntries + log_failure("gen::def_operator: operator%S recieved unexpected number of paramters recived %d instead of 0-1" + , operator_to_str(op) + , params_code->NumEntries ); - return OpValidateResult::Fail; + return OpValResult_Fail; } } - if ( ! ret_type.is_equal( t_bool ) ) + if ( ! code_is_equal((Code)ret_type, (Code)t_bool )) { - log_failure( "gen::def_operator: operator%s return type must be of type bool - %s", to_str( op ), ret_type.debug_str() ); - return OpValidateResult::Fail; + log_failure("gen::def_operator: operator%S return type must be of type bool - %S" + , operator_to_str(op) + , code_debug_str((Code)ret_type) + ); + return OpValResult_Fail; } break; - case LAnd : - case LOr : - case LEqual : - case LNot : - case Lesser : - case Greater : - case LesserEqual : - case GreaterEqual : + case Op_LAnd: + case Op_LOr: + case Op_LEqual: + case Op_LNot: + case Op_Lesser: + case Op_Greater: + case Op_LesserEqual: + case Op_GreaterEqual: check_params(); switch ( params_code->NumEntries ) { - case 1 : + case 1: is_member_symbol = true; break; - case 2 : + case 2: break; - default : - log_failure( - "gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 1-2", - to_str( op ), - params_code->NumEntries + default: + log_failure("gen::def_operator: operator%S recieved unexpected number of paramters recived %d instead of 1-2" + , operator_to_str(op) + , params_code->NumEntries ); - return OpValidateResult::Fail; + return OpValResult_Fail; } break; - case Indirection : - case AddressOf : - case MemberOfPointer : - if ( params_code && params_code->NumEntries > 1 ) + case Op_Indirection: + case Op_AddressOf: + case Op_MemberOfPointer: + if ( params_code && params_code->NumEntries > 1) { - log_failure( - "gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 0-1", - to_str( op ), - params_code->NumEntries + log_failure("gen::def_operator: operator%S recieved unexpected number of paramters recived %d instead of 0-1" + , operator_to_str(op) + , params_code->NumEntries ); - return OpValidateResult::Fail; + return OpValResult_Fail; } else { @@ -15296,71 +16966,57 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy } break; - case PtrToMemOfPtr : + case Op_PtrToMemOfPtr: if ( params_code ) { - log_failure( "gen::def_operator: operator%s expects no paramters - %s", to_str( op ), params_code.debug_str() ); - return OpValidateResult::Fail; + log_failure("gen::def_operator: operator%S expects no paramters - %S", operator_to_str(op), code_debug_str((Code)params_code)); + return OpValResult_Fail; } break; - case Subscript : - case FunctionCall : - case Comma : + case Op_Subscript: + case Op_FunctionCall: + case Op_Comma: check_params(); break; -#undef specs + + case Op_New: + case Op_Delete: + // This library doesn't support validating new and delete yet. + break; +# undef specs } - return is_member_symbol ? OpValidateResult::Member : OpValidateResult::Global; -#undef check_params -#undef check_ret_type -#undef check_param_eq_ret + return is_member_symbol ? OpValResult_Member : OpValResult_Global; +# undef check_params +# undef check_ret_type +# undef check_param_eq_ret } -#pragma region Helper Marcos -// This snippet is used in nearly all the functions. -#define name_check( Context_, Name_ ) \ - { \ - if ( Name_.Len <= 0 ) \ - { \ - log_failure( "gen::" stringize( Context_ ) ": Invalid name length provided - %d", Name_.Len ); \ - return CodeInvalid; \ - } \ - \ - if ( Name_.Ptr == nullptr ) \ - { \ - log_failure( "gen::" stringize( Context_ ) ": name is null" ); \ - return CodeInvalid; \ - } \ +forceinline +bool name__check( char const* context, Str name ) +{ + if ( name.Len <= 0 ) { + log_failure( "gen::%s: Invalid name length provided - %d", name.Len ); + return false; } - -#define null_check( Context_, Code_ ) \ - if ( ! Code_ ) \ - { \ - log_failure( "gen::" stringize( Context_ ) ": " stringize( Code_ ) " provided is null" ); \ - return CodeInvalid; \ + if ( name.Ptr == nullptr ) { + log_failure( "gen::%s: name is null" ); + return false; } + return true; +} +#define name_check( context, name ) name__check( #context, name ) -#define null_or_invalid_check( Context_, Code_ ) \ - { \ - if ( ! Code_ ) \ - { \ - log_failure( "gen::" stringize( Context_ ) ": " stringize( Code_ ) " provided is null" ); \ - return CodeInvalid; \ - } \ - \ - if ( Code_->is_invalid() ) \ - { \ - log_failure( "gen::" stringize( Context_ ) ": " stringize( Code_ ) " provided is invalid" ); \ - return CodeInvalid; \ - } \ +forceinline +bool null__check( char const* context, char const* code_id, Code code ) { + if ( code == nullptr ) { + log_failure( "gen::%s: %s provided is null", context, code_id ); + return false; } - -#define not_implemented( Context_ ) \ - log_failure( "gen::%s: This function is not implemented" ); \ - return CodeInvalid; -#pragma endregion Helper Marcos + return true; +} +#define null_check( context, code ) null__check( #context, #code, cast(Code, code) ) /* The implementaiton of the upfront constructors involves doing three things: @@ -15374,33 +17030,31 @@ identify the issue without having to debug too much (at least they can debug tho The largest of the functions is related to operator overload definitions. The library validates a good protion of their form and thus the argument processing for is quite a bit. */ -CodeAttributes def_attributes( StrC content ) +CodeAttributes def_attributes( Str content ) { - if ( content.Len <= 0 || content.Ptr == nullptr ) - { + if ( content.Len <= 0 || content.Ptr == nullptr ) { log_failure( "gen::def_attributes: Invalid attributes provided" ); - return CodeInvalid; + GEN_DEBUG_TRAP(); + return InvalidCode; } - - Code result = make_code(); - result->Type = ECode::PlatformAttributes; - result->Name = get_cached_string( content ); + Code + result = make_code(); + result->Type = CT_PlatformAttributes; + result->Name = cache_str( content ); result->Content = result->Name; - - return ( CodeAttributes )result; + return (CodeAttributes) result; } -CodeComment def_comment( StrC content ) +CodeComment def_comment( Str content ) { if ( content.Len <= 0 || content.Ptr == nullptr ) { log_failure( "gen::def_comment: Invalid comment provided:" ); - return CodeInvalid; + GEN_DEBUG_TRAP(); + return InvalidCode; } - static char line[ MaxCommentLineLength ]; - - String cmt_formatted = String::make_reserve( GlobalAllocator, kilobytes( 1 ) ); + StrBuilder cmt_formatted = strbuilder_make_reserve( _ctx->Allocator_Temp, kilobytes(1) ); char const* end = content.Ptr + content.Len; char const* scanner = content.Ptr; s32 curr = 0; @@ -15415,1071 +17069,929 @@ CodeComment def_comment( StrC content ) } length++; - str_copy( line, scanner, length ); - cmt_formatted.append_fmt( "//%.*s", length, line ); - mem_set( line, 0, MaxCommentLineLength ); - + strbuilder_append_fmt(& cmt_formatted, "//%.*s", length, scanner ); scanner += length; - } while ( scanner <= end ); + } + while ( scanner <= end ); - if ( cmt_formatted.back() != '\n' ) - cmt_formatted.append( "\n" ); + if ( * strbuilder_back(cmt_formatted) != '\n' ) + strbuilder_append_str( & cmt_formatted, txt("\n") ); - Code result = make_code(); - result->Type = ECode::Comment; - result->Name = get_cached_string( cmt_formatted ); + Str name = strbuilder_to_str(cmt_formatted); + + Code + result = make_code(); + result->Type = CT_Comment; + result->Name = cache_str( name ); result->Content = result->Name; - cmt_formatted.free(); + strbuilder_free(& cmt_formatted); - return ( CodeComment )result; + return (CodeComment) result; } -CodeConstructor def_constructor( CodeParam params, Code initializer_list, Code body ) +CodeConstructor def_constructor( Opts_def_constructor p ) { - using namespace ECode; - - if ( params && params->Type != Parameters ) - { - log_failure( "gen::def_constructor: params must be of Parameters type - %s", params.debug_str() ); - return CodeInvalid; + if ( p.params && p.params->Type != CT_Parameters ) { + log_failure("gen::def_constructor: params must be of Parameters type - %s", code_debug_str((Code)p.params)); + GEN_DEBUG_TRAP(); + return InvalidCode; } - CodeConstructor result = ( CodeConstructor )make_code(); - - if ( params ) - { - result->Params = params; + CodeConstructor result = (CodeConstructor) make_code(); + if ( p.params ) { + result->Params = p.params; } - - if ( initializer_list ) - { - result->InitializerList = initializer_list; + if ( p.initializer_list ) { + result->InitializerList = p.initializer_list; } - - if ( body ) + if ( p.body ) { - switch ( body->Type ) - { - case Function_Body : - case Untyped : - break; + switch ( p.body->Type ) { + case CT_Function_Body: + case CT_Untyped: + break; - default : - log_failure( "gen::def_constructor: body must be either of Function_Body or Untyped type - %s", body.debug_str() ); - return CodeInvalid; + default: + log_failure("gen::def_constructor: body must be either of Function_Body or Untyped type - %s", code_debug_str(p.body)); + return InvalidCode; } - result->Type = Constructor; - result->Body = body; + result->Type = CT_Constructor; + result->Body = p.body; } else { - result->Type = Constructor_Fwd; + result->Type = CT_Constructor_Fwd; } - return result; } -CodeClass def_class( - StrC name, - Code body, - CodeType parent, - AccessSpec parent_access, - CodeAttributes attributes, - ModuleFlag mflags, - CodeType* interfaces, - s32 num_interfaces -) +CodeClass def_class( Str name, Opts_def_struct p ) { - using namespace ECode; - - name_check( def_class, name ); - - if ( attributes && attributes->Type != PlatformAttributes ) - { - log_failure( "gen::def_class: attributes was not a 'PlatformAttributes' type: %s", attributes.debug_str() ); - return CodeInvalid; + if ( ! name_check( def_class, name ) ) { + GEN_DEBUG_TRAP(); + return InvalidCode; } - if ( parent && ( parent->Type != Class || parent->Type != Struct || parent->Type != Typename || parent->Type != Untyped ) ) - { - log_failure( "gen::def_class: parent provided is not type 'Class', 'Struct', 'Typeanme', or 'Untyped': %s", parent.debug_str() ); - return CodeInvalid; + if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { + log_failure( "gen::def_class: attributes was not a 'PlatformAttributes' type: %s", code_debug_str(p.attributes) ); + GEN_DEBUG_TRAP(); + return InvalidCode; + } + if ( p.parent && ( p.parent->Type != CT_Class && p.parent->Type != CT_Struct && p.parent->Type != CT_Typename && p.parent->Type != CT_Untyped ) ) { + log_failure( "gen::def_class: parent provided is not type 'Class', 'Struct', 'Typeanme', or 'Untyped': %s", code_debug_str(p.parent) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } - CodeClass result = ( CodeClass )make_code(); - result->Name = get_cached_string( name ); - result->ModuleFlags = mflags; - - if ( body ) + CodeClass + result = (CodeClass) make_code(); + result->Name = cache_str( name ); + result->ModuleFlags = p.mflags; + if ( p.body ) { - switch ( body->Type ) + switch ( p.body->Type ) { - case Class_Body : - case Untyped : - break; + case CT_Class_Body: + case CT_Untyped: + break; - default : - log_failure( "gen::def_class: body must be either of Class_Body or Untyped type - %s", body.debug_str() ); - return CodeInvalid; + default: + log_failure("gen::def_class: body must be either of Class_Body or Untyped type - %s", code_debug_str(p.body)); + return InvalidCode; } - result->Type = Class; - result->Body = body; + result->Type = CT_Class; + result->Body = p.body; + result->Body->Parent = cast(Code, result); } - else - { - result->Type = Class_Fwd; + else { + result->Type = CT_Class_Fwd; } - if ( attributes ) - result->Attributes = attributes; + result->Attributes = p.attributes; + result->ParentAccess = p.parent_access; + result->ParentType = p.parent; - if ( parent ) - { - result->ParentAccess = parent_access; - result->ParentType = parent; + for (s32 idx = 0; idx < p.num_interfaces; idx++ ) { + class_add_interface(result, p.interfaces[idx] ); } - - if ( interfaces ) - { - for ( s32 idx = 0; idx < num_interfaces; idx++ ) - { - result.add_interface( interfaces[ idx ] ); - } - } - return result; } -CodeDefine def_define( StrC name, StrC content ) +CodeDefine def_define( Str name, Str content, Opts_def_define p ) { - using namespace ECode; + if ( ! name_check( def_define, name ) ) { + GEN_DEBUG_TRAP(); + return InvalidCode; + } - name_check( def_define, name ); + CodeDefine + result = (CodeDefine) make_code(); + result->Type = CT_Preprocess_Define; + result->Name = cache_str( name ); if ( content.Len <= 0 || content.Ptr == nullptr ) - { - log_failure( "gen::def_define: Invalid value provided" ); - return CodeInvalid; + result->Content = cache_str( txt("") ); + else + result->Content = cache_str( strbuilder_to_str(strbuilder_fmt_buf(_ctx->Allocator_Temp, "%S\n", content)) ); + + b32 append_preprocess_defines = ! p.dont_append_preprocess_defines; + if ( append_preprocess_defines ) { + // Add the define to PreprocessorDefines for usage in parsing + s32 lex_id_len = 0; + for (; lex_id_len < result->Name.Len; ++ lex_id_len ) { + if ( result->Name.Ptr[lex_id_len] == '(' ) + break; + } + Str lex_id = { result->Name.Ptr, lex_id_len }; + array_append(_ctx->PreprocessorDefines, cache_str(lex_id) ); } - - CodeDefine result = ( CodeDefine )make_code(); - result->Type = Preprocess_Define; - result->Name = get_cached_string( name ); - result->Content = get_cached_string( content ); - return result; } -CodeDestructor def_destructor( Code body, CodeSpecifiers specifiers ) +CodeDestructor def_destructor( Opts_def_destructor p ) { - using namespace ECode; - - if ( specifiers && specifiers->Type != Specifiers ) - { - log_failure( "gen::def_destructor: specifiers was not a 'Specifiers' type: %s", specifiers.debug_str() ); - return CodeInvalid; + if ( p.specifiers && p.specifiers->Type != CT_Specifiers ) { + log_failure( "gen::def_destructor: specifiers was not a 'Specifiers' type: %s", code_debug_str(p.specifiers) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } - CodeDestructor result = ( CodeDestructor )make_code(); - - if ( specifiers ) - result->Specs = specifiers; - - if ( body ) + CodeDestructor + result = (CodeDestructor) make_code(); + result->Specs = p.specifiers; + if ( p.body ) { - switch ( body->Type ) + switch ( p.body->Type ) { - case Function_Body : - case Untyped : - break; + case CT_Function_Body: + case CT_Untyped: + break; - default : - log_failure( "gen::def_destructor: body must be either of Function_Body or Untyped type - %s", body.debug_str() ); - return CodeInvalid; + default: + log_failure("gen::def_destructor: body must be either of Function_Body or Untyped type - %s", code_debug_str(p.body)); + return InvalidCode; } - result->Type = Destructor; - result->Body = body; + result->Type = CT_Destructor; + result->Body = p.body; } else { - result->Type = Destructor_Fwd; + result->Type = CT_Destructor_Fwd; } - return result; } -CodeEnum def_enum( StrC name, Code body, CodeType type, EnumT specifier, CodeAttributes attributes, ModuleFlag mflags ) +CodeEnum def_enum( Str name, Opts_def_enum p ) { - using namespace ECode; - - name_check( def_enum, name ); - - if ( type && type->Type != Typename ) - { - log_failure( "gen::def_enum: enum underlying type provided was not of type Typename: %s", type.debug_str() ); - return CodeInvalid; + if ( ! name_check( def_enum, name ) ) { + GEN_DEBUG_TRAP(); + return InvalidCode; + } + if ( p.type && p.type->Type != CT_Typename ) { + log_failure( "gen::def_enum: enum underlying type provided was not of type Typename: %s", code_debug_str(p.type) ); + GEN_DEBUG_TRAP(); + return InvalidCode; + } + if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { + log_failure( "gen::def_enum: attributes was not a 'PlatformAttributes' type: %s", code_debug_str(p.attributes) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } - if ( attributes && attributes->Type != PlatformAttributes ) + CodeEnum + result = (CodeEnum) make_code(); + result->Name = cache_str( name ); + result->ModuleFlags = p.mflags; + if ( p.body ) { - log_failure( "gen::def_enum: attributes was not a 'PlatformAttributes' type: %s", attributes.debug_str() ); - return CodeInvalid; - } - - CodeEnum result = ( CodeEnum )make_code(); - result->Name = get_cached_string( name ); - result->ModuleFlags = mflags; - - if ( body ) - { - switch ( body->Type ) + switch ( p.body->Type ) { - case Enum_Body : - case Untyped : - break; + case CT_Enum_Body: + case CT_Untyped: + break; - default : - log_failure( "gen::def_enum: body must be of Enum_Body or Untyped type %s", body.debug_str() ); - return CodeInvalid; + default: + log_failure( "gen::def_enum: body must be of Enum_Body or Untyped type %s", code_debug_str(p.body)); + return InvalidCode; } - result->Type = specifier == EnumClass ? Enum_Class : Enum; + result->Type = p.specifier == EnumDecl_Class ? + CT_Enum_Class : CT_Enum; - result->Body = body; + result->Body = p.body; } else { - result->Type = specifier == EnumClass ? Enum_Class_Fwd : Enum_Fwd; + result->Type = p.specifier == EnumDecl_Class ? + CT_Enum_Class_Fwd : CT_Enum_Fwd; } + result->Attributes = p.attributes; - if ( attributes ) - result->Attributes = attributes; - - if ( type ) - { - result->UnderlyingType = type; + if ( p.type ) { + result->UnderlyingType = p.type; } - else if ( result->Type != Enum_Class_Fwd && result->Type != Enum_Fwd ) + else if ( p.type_macro ) { + result->UnderlyingTypeMacro = p.type_macro; + } + else if ( result->Type != CT_Enum_Class_Fwd && result->Type != CT_Enum_Fwd ) { log_failure( "gen::def_enum: enum forward declaration must have an underlying type" ); - return CodeInvalid; + GEN_DEBUG_TRAP(); + return InvalidCode; } - return result; } -CodeExec def_execution( StrC content ) +CodeExec def_execution( Str content ) { - if ( content.Len <= 0 || content.Ptr == nullptr ) - { + if ( content.Len <= 0 || content.Ptr == nullptr ) { log_failure( "gen::def_execution: Invalid execution provided" ); - return CodeInvalid; + GEN_DEBUG_TRAP(); + return InvalidCode; } - - Code result = make_code(); - result->Type = ECode::Execution; - result->Name = get_cached_string( content ); - result->Content = result->Name; - - return ( CodeExec )result; + CodeExec + result = (CodeExec) make_code(); + result->Type = CT_Execution; + result->Content = cache_str( content ); + return result; } -CodeExtern def_extern_link( StrC name, Code body ) +CodeExtern def_extern_link( Str name, CodeBody body ) { - using namespace ECode; - - name_check( def_extern_linkage, name ); - null_check( def_extern_linkage, body ); - - if ( body->Type != Extern_Linkage_Body && body->Type != Untyped ) - { - log_failure( "gen::def_extern_linkage: body is not of extern_linkage or untyped type %s", body->debug_str() ); - return CodeInvalid; + if ( ! name_check(def_extern_link, name) || ! null_check(def_extern_link, body) ) { + GEN_DEBUG_TRAP(); + return InvalidCode; } - - CodeExtern result = ( CodeExtern )make_code(); - result->Type = Extern_Linkage; - result->Name = get_cached_string( name ); - result->Body = body; - - return ( CodeExtern )result; + if ( body->Type != CT_Extern_Linkage_Body && body->Type != CT_Untyped ) { + log_failure("gen::def_extern_linkage: body is not of extern_linkage or untyped type %s", code_debug_str(body)); + GEN_DEBUG_TRAP(); + return InvalidCode; + } + CodeExtern + result = (CodeExtern)make_code(); + result->Type = CT_Extern_Linkage; + result->Name = cache_str( name ); + result->Body = body; + return result; } CodeFriend def_friend( Code declaration ) { - using namespace ECode; - - null_check( def_friend, declaration ); - + if ( ! null_check( def_friend, declaration ) ) { + GEN_DEBUG_TRAP(); + return InvalidCode; + } switch ( declaration->Type ) { - case Class_Fwd : - case Function_Fwd : - case Operator_Fwd : - case Struct_Fwd : - case Class : - case Function : - case Operator : - case Struct : - break; + case CT_Class_Fwd: + case CT_Function_Fwd: + case CT_Operator_Fwd: + case CT_Struct_Fwd: + case CT_Class: + case CT_Function: + case CT_Operator: + case CT_Struct: + break; - default : - log_failure( "gen::def_friend: requires declartion to have class, function, operator, or struct - %s", declaration->debug_str() ); - return CodeInvalid; + default: + log_failure("gen::def_friend: requires declartion to have class, function, operator, or struct - %s", code_debug_str(declaration)); + return InvalidCode; } - - CodeFriend result = ( CodeFriend )make_code(); - result->Type = Friend; - + CodeFriend + result = (CodeFriend) make_code(); + result->Type = CT_Friend; result->Declaration = declaration; - return result; } -CodeFn def_function( StrC name, CodeParam params, CodeType ret_type, Code body, CodeSpecifiers specifiers, CodeAttributes attributes, ModuleFlag mflags ) +CodeFn def_function( Str name, Opts_def_function p ) { - using namespace ECode; - - name_check( def_function, name ); - - if ( params && params->Type != Parameters ) - { - log_failure( "gen::def_function: params was not a `Parameters` type: %s", params.debug_str() ); - return CodeInvalid; + if ( ! name_check( def_function, name )) { + GEN_DEBUG_TRAP(); + return InvalidCode; + } + if ( p.params && p.params->Type != CT_Parameters ) { + log_failure( "gen::def_function: params was not a `Parameters` type: %s", code_debug_str(p.params) ); + GEN_DEBUG_TRAP(); + return InvalidCode; + } + if ( p.ret_type && p.ret_type->Type != CT_Typename ) { + log_failure( "gen::def_function: ret_type was not a Typename: %s", code_debug_str(p.ret_type) ); + GEN_DEBUG_TRAP(); + return InvalidCode; + } + if ( p.specs && p.specs-> Type != CT_Specifiers ) { + log_failure( "gen::def_function: specifiers was not a `Specifiers` type: %s", code_debug_str(p.specs) ); + GEN_DEBUG_TRAP(); + return InvalidCode; + } + if ( p.attrs && p.attrs->Type != CT_PlatformAttributes ) { + log_failure( "gen::def_function: attributes was not a `PlatformAttributes` type: %s", code_debug_str(p.attrs) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } - if ( ret_type && ret_type->Type != Typename ) + CodeFn + result = (CodeFn) make_code(); + result->Name = cache_str( name ); + result->ModuleFlags = p.mflags; + if ( p.body ) { - log_failure( "gen::def_function: ret_type was not a Typename: %s", ret_type.debug_str() ); - return CodeInvalid; - } - - if ( specifiers && specifiers->Type != Specifiers ) - { - log_failure( "gen::def_function: specifiers was not a `Specifiers` type: %s", specifiers.debug_str() ); - return CodeInvalid; - } - - if ( attributes && attributes->Type != PlatformAttributes ) - { - log_failure( "gen::def_function: attributes was not a `PlatformAttributes` type: %s", attributes.debug_str() ); - return CodeInvalid; - } - - CodeFn result = ( CodeFn )make_code(); - result->Name = get_cached_string( name ); - result->ModuleFlags = mflags; - - if ( body ) - { - switch ( body->Type ) + switch ( p.body->Type ) { - case Function_Body : - case Execution : - case Untyped : + case CT_Function_Body: + case CT_Execution: + case CT_Untyped: break; - default : + default: { - log_failure( "gen::def_function: body must be either of Function_Body, Execution, or Untyped type. %s", body->debug_str() ); - return CodeInvalid; + log_failure("gen::def_function: body must be either of Function_Body, Execution, or Untyped type. %s", code_debug_str(p.body)); + return InvalidCode; } } - - result->Type = Function; - result->Body = body; + result->Type = CT_Function; + result->Body = p.body; } else { - result->Type = Function_Fwd; + result->Type = CT_Function_Fwd; } - - if ( attributes ) - result->Attributes = attributes; - - if ( specifiers ) - result->Specs = specifiers; - - if ( ret_type ) - { - result->ReturnType = ret_type; - } - else - { - result->ReturnType = t_void; - } - - if ( params ) - result->Params = params; - + result->Attributes = p.attrs; + result->Specs = p.specs; + result->Params = p.params; + result->ReturnType = p.ret_type ? p.ret_type : t_void; return result; } -CodeInclude def_include( StrC path, bool foreign ) +CodeInclude def_include( Str path, Opts_def_include p ) { - if ( path.Len <= 0 || path.Ptr == nullptr ) - { + if ( path.Len <= 0 || path.Ptr == nullptr ) { log_failure( "gen::def_include: Invalid path provided - %d" ); - return CodeInvalid; + GEN_DEBUG_TRAP(); + return InvalidCode; } + StrBuilder content = p.foreign ? + strbuilder_fmt_buf( _ctx->Allocator_Temp, "<%.*s>", path.Len, path.Ptr ) + : strbuilder_fmt_buf( _ctx->Allocator_Temp, "\"%.*s\"", path.Len, path.Ptr ); - StrC content = foreign ? to_str( str_fmt_buf( "<%.*s>", path.Len, path.Ptr ) ) : to_str( str_fmt_buf( "\"%.*s\"", path.Len, path.Ptr ) ); - - Code result = make_code(); - result->Type = ECode::Preprocess_Include; - result->Name = get_cached_string( content ); + CodeInclude + result = (CodeInclude) make_code(); + result->Type = CT_Preprocess_Include; + result->Name = cache_str( strbuilder_to_str(content) ); result->Content = result->Name; - - return ( CodeInclude )result; -} - -CodeModule def_module( StrC name, ModuleFlag mflags ) -{ - name_check( def_module, name ); - - Code result = make_code(); - result->Type = ECode::Module; - result->Name = get_cached_string( name ); - result->Content = result->Name; - result->ModuleFlags = mflags; - - return ( CodeModule )result; -} - -CodeNS def_namespace( StrC name, Code body, ModuleFlag mflags ) -{ - using namespace ECode; - - name_check( def_namespace, name ); - null_check( def_namespace, body ); - - if ( body->Type != Namespace_Body && body->Type != Untyped ) - { - log_failure( "gen::def_namespace: body is not of namespace or untyped type %s", body.debug_str() ); - return CodeInvalid; - } - - CodeNS result = ( CodeNS )make_code(); - result->Type = Namespace; - result->Name = get_cached_string( name ); - result->ModuleFlags = mflags; - result->Body = body; - return result; } -CodeOperator def_operator( - OperatorT op, - StrC nspace, - CodeParam params_code, - CodeType ret_type, - Code body, - CodeSpecifiers specifiers, - CodeAttributes attributes, - ModuleFlag mflags -) +CodeModule def_module( Str name, Opts_def_module p ) { - using namespace ECode; + if ( ! name_check( def_module, name )) { + GEN_DEBUG_TRAP(); + return InvalidCode; + } + CodeModule + result = (CodeModule) make_code(); + result->Type = CT_Module; + result->Name = cache_str( name ); + result->ModuleFlags = p.mflags; + return result; +} - if ( attributes && attributes->Type != PlatformAttributes ) - { - log_failure( "gen::def_operator: PlatformAttributes was provided but its not of attributes type: %s", attributes.debug_str() ); - return CodeInvalid; +CodeNS def_namespace( Str name, CodeBody body, Opts_def_namespace p ) +{ + if ( ! name_check( def_namespace, name )) { + GEN_DEBUG_TRAP(); + return InvalidCode; + } + if ( ! null_check( def_namespace, body)) { + GEN_DEBUG_TRAP(); + return InvalidCode; + } + if ( body && body->Type != CT_Namespace_Body && body->Type != CT_Untyped ) { + log_failure("gen::def_namespace: body is not of namespace or untyped type %s", code_debug_str(body)); + GEN_DEBUG_TRAP(); + return InvalidCode; + } + CodeNS + result = (CodeNS) make_code(); + result->Type = CT_Namespace; + result->Name = cache_str( name ); + result->ModuleFlags = p.mflags; + result->Body = body; + return result; +} + +CodeOperator def_operator( Operator op, Str nspace, Opts_def_operator p ) +{ + if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { + log_failure( "gen::def_operator: PlatformAttributes was provided but its not of attributes type: %s", code_debug_str(p.attributes) ); + GEN_DEBUG_TRAP(); + return InvalidCode; + } + if ( p.specifiers && p.specifiers->Type != CT_Specifiers ) { + log_failure( "gen::def_operator: Specifiers was provided but its not of specifiers type: %s", code_debug_str(p.specifiers) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } - if ( specifiers && specifiers->Type != Specifiers ) - { - log_failure( "gen::def_operator: Specifiers was provided but its not of specifiers type: %s", specifiers.debug_str() ); - return CodeInvalid; - } - - OpValidateResult check_result = operator__validate( op, params_code, ret_type, specifiers ); - - if ( check_result == OpValidateResult::Fail ) - { - return CodeInvalid; + OpValidateResult check_result = operator__validate( op, p.params, p.ret_type, p.specifiers ); + if ( check_result == OpValResult_Fail ) { + return InvalidCode; } char const* name = nullptr; - StrC op_str = to_str( op ); + Str op_str = operator_to_str( op ); if ( nspace.Len > 0 ) - name = str_fmt_buf( "%.*soperator %.*s", nspace.Len, nspace.Ptr, op_str.Len, op_str.Ptr ); + name = c_str_fmt_buf( "%.*soperator %.*s", nspace.Len, nspace.Ptr, op_str.Len, op_str.Ptr ); else - name = str_fmt_buf( "operator %.*s", op_str.Len, op_str.Ptr ); - CodeOperator result = ( CodeOperator )make_code(); - result->Name = get_cached_string( { str_len( name ), name } ); - result->ModuleFlags = mflags; - result->Op = op; + name = c_str_fmt_buf( "operator %.*s", op_str.Len, op_str.Ptr ); - if ( body ) + Str name_resolved = { name, c_str_len(name) }; + + CodeOperator + result = (CodeOperator) make_code(); + result->Name = cache_str( name_resolved ); + result->ModuleFlags = p.mflags; + result->Op = op; + if ( p.body ) { - switch ( body->Type ) + switch ( p.body->Type ) { - case Function_Body : - case Execution : - case Untyped : + case CT_Function_Body: + case CT_Execution: + case CT_Untyped: break; - default : + default: { - log_failure( "gen::def_operator: body must be either of Function_Body, Execution, or Untyped type. %s", body->debug_str() ); - return CodeInvalid; + log_failure("gen::def_operator: body must be either of Function_Body, Execution, or Untyped type. %s", code_debug_str(p.body)); + GEN_DEBUG_TRAP(); + return InvalidCode; } } - result->Type = check_result == OpValidateResult::Global ? Operator : Operator_Member; + result->Type = check_result == OpValResult_Global ? + CT_Operator : CT_Operator_Member; - result->Body = body; + result->Body = p.body; } else { - result->Type = check_result == OpValidateResult::Global ? Operator_Fwd : Operator_Member_Fwd; + result->Type = check_result == OpValResult_Global ? + CT_Operator_Fwd : CT_Operator_Member_Fwd; } - - if ( attributes ) - result->Attributes = attributes; - - if ( specifiers ) - result->Specs = specifiers; - - result->ReturnType = ret_type; - - if ( params_code ) - result->Params = params_code; - + result->Attributes = p.attributes; + result->Specs = p.specifiers; + result->ReturnType = p.ret_type; + result->Params = p.params; return result; } -CodeOpCast def_operator_cast( CodeType type, Code body, CodeSpecifiers const_spec ) +CodeOpCast def_operator_cast( CodeTypename type, Opts_def_operator_cast p ) { - using namespace ECode; - null_check( def_operator_cast, type ); - - if ( type->Type != Typename ) - { - log_failure( "gen::def_operator_cast: type is not a typename - %s", type.debug_str() ); - return CodeInvalid; + if ( ! null_check( def_operator_cast, type )) { + GEN_DEBUG_TRAP(); + return InvalidCode; + } + if ( type->Type != CT_Typename ) { + log_failure( "gen::def_operator_cast: type is not a typename - %s", code_debug_str(type) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } - CodeOpCast result = ( CodeOpCast )make_code(); - - if ( body ) + CodeOpCast result = (CodeOpCast) make_code(); + if (p.body) { - result->Type = Operator_Cast; + result->Type = CT_Operator_Cast; - if ( body->Type != Function_Body && body->Type != Execution ) - { - log_failure( "gen::def_operator_cast: body is not of function body or execution type - %s", body.debug_str() ); - return CodeInvalid; + if ( p.body->Type != CT_Function_Body && p.body->Type != CT_Execution ) { + log_failure( "gen::def_operator_cast: body is not of function body or execution type - %s", code_debug_str(p.body) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } - - result->Body = body; + result->Body = p.body; } else { - result->Type = Operator_Cast_Fwd; + result->Type = CT_Operator_Cast_Fwd; } - - if ( const_spec ) - { - result->Specs = const_spec; - } - + result->Specs = p.specs; result->ValueType = type; return result; } -CodeParam def_param( CodeType type, StrC name, Code value ) +CodeParams def_param( CodeTypename type, Str name, Opts_def_param p ) { - using namespace ECode; - - name_check( def_param, name ); - null_check( def_param, type ); - - if ( type->Type != Typename ) - { - log_failure( "gen::def_param: type is not a typename - %s", type.debug_str() ); - return CodeInvalid; + if ( ! name_check( def_param, name ) || ! null_check( def_param, type ) ) { + GEN_DEBUG_TRAP(); + return InvalidCode; } - - if ( value && value->Type != Untyped ) - { - log_failure( "gen::def_param: value is not untyped - %s", value.debug_str() ); - return CodeInvalid; + if ( type->Type != CT_Typename ) { + log_failure( "gen::def_param: type is not a typename - %s", code_debug_str(type) ); + return InvalidCode; } - - CodeParam result = ( CodeParam )make_code(); - result->Type = Parameters; - result->Name = get_cached_string( name ); - + if ( p.value && p.value->Type != CT_Untyped ) { + log_failure( "gen::def_param: value is not untyped - %s", code_debug_str(p.value) ); + return InvalidCode; + } + CodeParams + result = (CodeParams) make_code(); + result->Type = CT_Parameters; + result->Name = cache_str( name ); result->ValueType = type; - - if ( value ) - result->Value = value; - + result->Value = p.value; result->NumEntries++; - return result; } -CodePragma def_pragma( StrC directive ) +CodePragma def_pragma( Str directive ) { - using namespace ECode; - - if ( directive.Len <= 0 || directive.Ptr == nullptr ) - { + if ( directive.Len <= 0 || directive.Ptr == nullptr ) { log_failure( "gen::def_comment: Invalid comment provided:" ); - return CodeInvalid; + GEN_DEBUG_TRAP(); + return InvalidCode; } - - CodePragma result = ( CodePragma )make_code(); - result->Type = Preprocess_Pragma; - result->Content = get_cached_string( directive ); - + CodePragma + result = (CodePragma) make_code(); + result->Type = CT_Preprocess_Pragma; + result->Content = cache_str( directive ); return result; } -CodePreprocessCond def_preprocess_cond( EPreprocessCond type, StrC expr ) +CodePreprocessCond def_preprocess_cond( EPreprocessCond type, Str expr ) { - using namespace ECode; - - if ( expr.Len <= 0 || expr.Ptr == nullptr ) - { + if ( expr.Len <= 0 || expr.Ptr == nullptr ) { log_failure( "gen::def_comment: Invalid comment provided:" ); - return CodeInvalid; + GEN_DEBUG_TRAP(); + return InvalidCode; } - - CodePreprocessCond result = ( CodePreprocessCond )make_code(); - result->Content = get_cached_string( expr ); - - switch ( type ) + CodePreprocessCond + result = (CodePreprocessCond) make_code(); + result->Content = cache_str( expr ); + switch (type) { - case EPreprocessCond::If : - result->Type = Preprocess_If; - break; - case EPreprocessCond::IfDef : - result->Type = Preprocess_IfDef; - break; - case EPreprocessCond::IfNotDef : - result->Type = Preprocess_IfNotDef; - break; - case EPreprocessCond::ElIf : - result->Type = Preprocess_ElIf; - break; + case PreprocessCond_If: + result->Type = CT_Preprocess_If; + break; + case PreprocessCond_IfDef: + result->Type = CT_Preprocess_IfDef; + break; + case PreprocessCond_IfNotDef: + result->Type = CT_Preprocess_IfNotDef; + break; + case PreprocessCond_ElIf: + result->Type = CT_Preprocess_ElIf; + break; } - return result; } -CodeSpecifiers def_specifier( SpecifierT spec ) +CodeSpecifiers def_specifier( Specifier spec ) { - CodeSpecifiers result = ( CodeSpecifiers )make_code(); - result->Type = ECode::Specifiers; - result.append( spec ); - + CodeSpecifiers + result = (CodeSpecifiers) make_code(); + result->Type = CT_Specifiers; + specifiers_append(result, spec ); return result; } -CodeStruct def_struct( - StrC name, - Code body, - CodeType parent, - AccessSpec parent_access, - CodeAttributes attributes, - ModuleFlag mflags, - CodeType* interfaces, - s32 num_interfaces -) +CodeStruct def_struct( Str name, Opts_def_struct p ) { - using namespace ECode; - - if ( attributes && attributes->Type != PlatformAttributes ) - { - log_failure( "gen::def_struct: attributes was not a `PlatformAttributes` type - %s", attributes.debug_str() ); - return CodeInvalid; + if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { + log_failure( "gen::def_struct: attributes was not a `PlatformAttributes` type - %s", code_debug_str(cast(Code, p.attributes)) ); + GEN_DEBUG_TRAP(); + return InvalidCode; + } + if ( p.parent && p.parent->Type != CT_Typename ) { + log_failure( "gen::def_struct: parent was not a `Struct` type - %s", code_debug_str(p.parent) ); + GEN_DEBUG_TRAP(); + return InvalidCode; + } + if ( p.body && p.body->Type != CT_Struct_Body ) { + log_failure( "gen::def_struct: body was not a Struct_Body type - %s", code_debug_str(p.body) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } - if ( parent && parent->Type != Typename ) - { - log_failure( "gen::def_struct: parent was not a `Struct` type - %s", parent.debug_str() ); - return CodeInvalid; + CodeStruct + result = (CodeStruct) make_code(); + result->ModuleFlags = p.mflags; + if ( name.Len ) + result->Name = cache_str( name ); + + if ( p.body ) { + result->Type = CT_Struct; + result->Body = p.body; } - - if ( body && body->Type != Struct_Body ) - { - log_failure( "gen::def_struct: body was not a Struct_Body type - %s", body.debug_str() ); - return CodeInvalid; + else { + result->Type = CT_Struct_Fwd; } + result->Attributes = p.attributes; + result->ParentAccess = p.parent_access; + result->ParentType = p.parent; - CodeStruct result = ( CodeStruct )make_code(); - result->ModuleFlags = mflags; - - if ( name ) - result->Name = get_cached_string( name ); - - if ( body ) - { - result->Type = Struct; - result->Body = body; + for (s32 idx = 0; idx < p.num_interfaces; idx++ ) { + struct_add_interface(result, p.interfaces[idx] ); } - else - { - result->Type = Struct_Fwd; - } - - if ( attributes ) - result->Attributes = attributes; - - if ( parent ) - { - result->ParentAccess = parent_access; - result->ParentType = parent; - } - - if ( interfaces ) - { - for ( s32 idx = 0; idx < num_interfaces; idx++ ) - { - result.add_interface( interfaces[ idx ] ); - } - } - return result; } -CodeTemplate def_template( CodeParam params, Code declaration, ModuleFlag mflags ) +CodeTemplate def_template( CodeParams params, Code declaration, Opts_def_template p ) { - null_check( def_template, declaration ); - - if ( params && params->Type != ECode::Parameters ) - { - log_failure( "gen::def_template: params is not of parameters type - %s", params.debug_str() ); - return CodeInvalid; + if ( ! null_check( def_template, declaration ) ) { + GEN_DEBUG_TRAP(); + return InvalidCode; } - - switch ( declaration->Type ) - { - case ECode::Class : - case ECode::Function : - case ECode::Struct : - case ECode::Variable : - case ECode::Using : - break; - - default : - log_failure( "gen::def_template: declaration is not of class, function, struct, variable, or using type - %s", declaration.debug_str() ); + if ( params && params->Type != CT_Parameters ){ + log_failure( "gen::def_template: params is not of parameters type - %s", code_debug_str(params) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } + switch (declaration->Type ) + { + case CT_Class: + case CT_Function: + case CT_Struct: + case CT_Variable: + case CT_Using: + break; - CodeTemplate result = ( CodeTemplate )make_code(); - result->Type = ECode::Template; - result->ModuleFlags = mflags; + default: + log_failure( "gen::def_template: declaration is not of class, function, struct, variable, or using type - %s", code_debug_str(declaration) ); + } + CodeTemplate + result = (CodeTemplate) make_code(); + result->Type = CT_Template; + result->ModuleFlags = p.mflags; result->Params = params; result->Declaration = declaration; - return result; } -CodeType def_type( StrC name, Code arrayexpr, CodeSpecifiers specifiers, CodeAttributes attributes ) +CodeTypename def_type( Str name, Opts_def_type p ) { - name_check( def_type, name ); - - if ( attributes && attributes->Type != ECode::PlatformAttributes ) - { - log_failure( "gen::def_type: attributes is not of attributes type - %s", attributes.debug_str() ); - return CodeInvalid; + if ( ! name_check( def_type, name )) { + GEN_DEBUG_TRAP(); + return InvalidCode; } - - if ( specifiers && specifiers->Type != ECode::Specifiers ) - { - log_failure( "gen::def_type: specifiers is not of specifiers type - %s", specifiers.debug_str() ); - return CodeInvalid; + Code arrayexpr = p.arrayexpr; + CodeSpecifiers specifiers = p.specifiers; + CodeAttributes attributes = p.attributes; + if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { + log_failure( "gen::def_type: attributes is not of attributes type - %s", code_debug_str((Code)p.attributes) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } - - if ( arrayexpr && arrayexpr->Type != ECode::Untyped ) - { - log_failure( "gen::def_type: arrayexpr is not of untyped type - %s", arrayexpr->debug_str() ); - return CodeInvalid; + if ( p.specifiers && p.specifiers->Type != CT_Specifiers ) { + log_failure( "gen::def_type: specifiers is not of specifiers type - %s", code_debug_str((Code)p.specifiers) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } - - CodeType result = ( CodeType )make_code(); - result->Name = get_cached_string( name ); - result->Type = ECode::Typename; - - if ( attributes ) - result->Attributes = attributes; - - if ( specifiers ) - result->Specs = specifiers; - - if ( arrayexpr ) - result->ArrExpr = arrayexpr; - + if ( p.arrayexpr && p.arrayexpr->Type != CT_Untyped ) { + log_failure( "gen::def_type: arrayexpr is not of untyped type - %s", code_debug_str((Code)p.arrayexpr) ); + GEN_DEBUG_TRAP(); + return InvalidCode; + } + CodeTypename + result = (CodeTypename) make_code(); + result->Name = cache_str( name ); + result->Type = CT_Typename; + result->Attributes = p.attributes; + result->Specs = p.specifiers; + result->ArrExpr = p.arrayexpr; + result->TypeTag = p.type_tag; return result; } -CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes, ModuleFlag mflags ) +CodeTypedef def_typedef( Str name, Code type, Opts_def_typedef p ) { - using namespace ECode; - - null_check( def_typedef, type ); - + if ( ! null_check( def_typedef, type ) ) { + GEN_DEBUG_TRAP(); + return InvalidCode; + } switch ( type->Type ) { - case Class : - case Class_Fwd : - case Enum : - case Enum_Fwd : - case Enum_Class : - case Enum_Class_Fwd : - case Function_Fwd : - case Struct : - case Struct_Fwd : - case Union : - case Typename : + case CT_Class: + case CT_Class_Fwd: + case CT_Enum: + case CT_Enum_Fwd: + case CT_Enum_Class: + case CT_Enum_Class_Fwd: + case CT_Function_Fwd: + case CT_Struct: + case CT_Struct_Fwd: + case CT_Union: + case CT_Typename: break; - default : - log_failure( "gen::def_typedef: type was not a Class, Enum, Function Forward, Struct, Typename, or Union - %s", type.debug_str() ); - return CodeInvalid; + default: + log_failure( "gen::def_typedef: type was not a Class, Enum, Function Forward, Struct, Typename, or Union - %s", code_debug_str((Code)type) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } - - if ( attributes && attributes->Type != ECode::PlatformAttributes ) - { - log_failure( "gen::def_typedef: attributes was not a PlatformAttributes - %s", attributes.debug_str() ); - return CodeInvalid; + if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { + log_failure( "gen::def_typedef: attributes was not a PlatformAttributes - %s", code_debug_str((Code)p.attributes) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } // Registering the type. - Code registered_type = def_type( name ); - - if ( ! registered_type ) - { + CodeTypename registered_type = def_type( name ); + if ( ! registered_type ) { log_failure( "gen::def_typedef: failed to register type" ); - return CodeInvalid; + GEN_DEBUG_TRAP(); + return InvalidCode; } - CodeTypedef result = ( CodeTypedef )make_code(); - result->Type = ECode::Typedef; - result->ModuleFlags = mflags; - + CodeTypedef + result = (CodeTypedef) make_code(); + result->Type = CT_Typedef; + result->ModuleFlags = p.mflags; result->UnderlyingType = type; - if ( name.Len <= 0 ) + if ( name.Len <= 0 ) { - if ( type->Type != Untyped ) - { - log_failure( "gen::def_typedef: name was empty and type was not untyped (indicating its a function typedef) - %s", type.debug_str() ); - return CodeInvalid; + if (type->Type != CT_Untyped) { + log_failure( "gen::def_typedef: name was empty and type was not untyped (indicating its a function typedef) - %s", code_debug_str(type) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } - - result->Name = get_cached_string( type->Name ); + result->Name = cache_str( type->Name ); result->IsFunction = true; } else { - result->Name = get_cached_string( name ); + result->Name = cache_str( name ); result->IsFunction = false; } - return result; } -CodeUnion def_union( StrC name, Code body, CodeAttributes attributes, ModuleFlag mflags ) +CodeUnion def_union( Str name, CodeBody body, Opts_def_union p ) { - null_check( def_union, body ); - - if ( body->Type != ECode::Union_Body ) - { - log_failure( "gen::def_union: body was not a Union_Body type - %s", body.debug_str() ); - return CodeInvalid; + if ( ! null_check( def_union, body ) ) { + GEN_DEBUG_TRAP(); + return InvalidCode; } - - if ( attributes && attributes->Type != ECode::PlatformAttributes ) - { - log_failure( "gen::def_union: attributes was not a PlatformAttributes type - %s", attributes.debug_str() ); - return CodeInvalid; + if ( body->Type != CT_Union_Body ) { + log_failure( "gen::def_union: body was not a Union_Body type - %s", code_debug_str(body) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } - - CodeUnion result = ( CodeUnion )make_code(); - result->ModuleFlags = mflags; - result->Type = ECode::Union; - + if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { + log_failure( "gen::def_union: attributes was not a PlatformAttributes type - %s", code_debug_str(p.attributes) ); + GEN_DEBUG_TRAP(); + return InvalidCode; + } + CodeUnion + result = (CodeUnion) make_code(); + result->ModuleFlags = p.mflags; + result->Type = CT_Union; + result->Body = body; + result->Attributes = p.attributes; if ( name.Ptr ) - result->Name = get_cached_string( name ); - - result->Body = body; - - if ( attributes ) - result->Attributes = attributes; - + result->Name = cache_str( name ); return result; } -CodeUsing def_using( StrC name, CodeType type, CodeAttributes attributes, ModuleFlag mflags ) +CodeUsing def_using( Str name, CodeTypename type, Opts_def_using p ) { - name_check( def_using, name ); - null_check( def_using, type ); + if ( ! name_check( def_using, name ) || null_check( def_using, type ) ) { + GEN_DEBUG_TRAP(); + return InvalidCode; + } - Code register_type = def_type( name ); - - if ( ! register_type ) - { + CodeTypename register_type = def_type( name ); + if ( ! register_type ) { log_failure( "gen::def_using: failed to register type" ); - return CodeInvalid; + GEN_DEBUG_TRAP(); + return InvalidCode; } - - if ( attributes && attributes->Type != ECode::PlatformAttributes ) - { - log_failure( "gen::def_using: attributes was not a PlatformAttributes type - %s", attributes.debug_str() ); - return CodeInvalid; + if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { + log_failure( "gen::def_using: attributes was not a PlatformAttributes type - %s", code_debug_str(p.attributes) ); + GEN_DEBUG_TRAP(); + return InvalidCode; } - - CodeUsing result = ( CodeUsing )make_code(); - result->Name = get_cached_string( name ); - result->ModuleFlags = mflags; - result->Type = ECode::Using; - + CodeUsing + result = (CodeUsing) make_code(); + result->Name = cache_str( name ); + result->ModuleFlags = p.mflags; + result->Type = CT_Using; result->UnderlyingType = type; - - if ( attributes ) - result->Attributes = attributes; - + result->Attributes = p.attributes; return result; } -CodeUsing def_using_namespace( StrC name ) +CodeUsing def_using_namespace( Str name ) { - name_check( def_using_namespace, name ); - - Code result = make_code(); - result->Name = get_cached_string( name ); - result->Content = result->Name; - result->Type = ECode::Using_Namespace; - - return ( CodeUsing )result; + if ( ! name_check( def_using_namespace, name ) ) { + GEN_DEBUG_TRAP(); + return InvalidCode; + } + CodeUsing + result = (CodeUsing) make_code(); + result->Name = cache_str( name ); + result->Type = CT_Using_Namespace; + return result; } -CodeVar def_variable( CodeType type, StrC name, Code value, CodeSpecifiers specifiers, CodeAttributes attributes, ModuleFlag mflags ) +CodeVar def_variable( CodeTypename type, Str name, Opts_def_variable p ) { - name_check( def_variable, name ); - null_check( def_variable, type ); - - if ( attributes && attributes->Type != ECode::PlatformAttributes ) - { - log_failure( "gen::def_variable: attributes was not a `PlatformAttributes` type - %s", attributes.debug_str() ); - return CodeInvalid; + if ( ! name_check( def_variable, name ) || null_check( def_variable, type ) ) { + GEN_DEBUG_TRAP(); + return InvalidCode; } - - if ( specifiers && specifiers->Type != ECode::Specifiers ) + if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { - log_failure( "gen::def_variable: specifiers was not a `Specifiers` type - %s", specifiers.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_variable: attributes was not a `PlatformAttributes` type - %s", code_debug_str(p.attributes) ); + return InvalidCode; } - - if ( type->Type != ECode::Typename ) + if ( p.specifiers && p.specifiers->Type != CT_Specifiers ) { - log_failure( "gen::def_variable: type was not a Typename - %s", type.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_variable: specifiers was not a `Specifiers` type - %s", code_debug_str(p.specifiers) ); + return InvalidCode; } - - if ( value && value->Type != ECode::Untyped ) + if ( type->Type != CT_Typename ) { - log_failure( "gen::def_variable: value was not a `Untyped` type - %s", value.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_variable: type was not a Typename - %s", code_debug_str(type) ); + return InvalidCode; } - - CodeVar result = ( CodeVar )make_code(); - result->Name = get_cached_string( name ); - result->Type = ECode::Variable; - result->ModuleFlags = mflags; - + if ( p.value && p.value->Type != CT_Untyped ) + { + log_failure( "gen::def_variable: value was not a `Untyped` type - %s", code_debug_str(p.value) ); + return InvalidCode; + } + CodeVar + result = (CodeVar) make_code(); + result->Name = cache_str( name ); + result->Type = CT_Variable; + result->ModuleFlags = p.mflags; result->ValueType = type; - - if ( attributes ) - result->Attributes = attributes; - - if ( specifiers ) - result->Specs = specifiers; - - if ( value ) - result->Value = value; - + result->Attributes = p.attributes; + result->Specs = p.specifiers; + result->Value = p.value; return result; } #pragma region Helper Macros for def_**_body functions -#define def_body_start( Name_ ) \ - using namespace ECode; \ - \ - if ( num <= 0 ) \ - { \ - log_failure( "gen::" stringize( Name_ ) ": num cannot be zero or negative" ); \ - return CodeInvalid; \ - } +#define def_body_start( Name_ ) \ +if ( num <= 0 ) \ +{ \ + log_failure("gen::" stringize(Name_) ": num cannot be zero or negative"); \ + return InvalidCode; \ +} -#define def_body_code_array_start( Name_ ) \ - using namespace ECode; \ - \ - if ( num <= 0 ) \ - { \ - log_failure( "gen::" stringize( Name_ ) ": num cannot be zero or negative" ); \ - return CodeInvalid; \ - } \ - \ - if ( codes == nullptr ) \ - { \ - log_failure( "gen::" stringize( Name_ ) " : Provided a null array of codes" ); \ - return CodeInvalid; \ - } +#define def_body_code_array_start( Name_ ) \ +if ( num <= 0 ) \ +{ \ + log_failure("gen::" stringize(Name_) ": num cannot be zero or negative"); \ + return InvalidCode; \ +} \ + \ +if ( codes == nullptr ) \ +{ \ + log_failure("gen::" stringize(Name_)" : Provided a null array of codes"); \ + return InvalidCode; \ +} -#pragma endregion Helper Macros for def_** _body functions +#pragma endregion Helper Macros for def_**_body functions CodeBody def_class_body( s32 num, ... ) { def_body_start( def_class_body ); CodeBody result = ( CodeBody )make_code(); - result->Type = Class_Body; + result->Type = CT_Class_Body; va_list va; va_start( va, num ); do { - Code_POD pod = va_arg( va, Code_POD ); - Code entry = pcast( Code, pod ); - - if ( ! entry ) - { - log_failure( - "gen::" - "def_class_body" - ": Provided an null entry" - ); - return CodeInvalid; + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + if ( ! entry) { + log_failure("gen::" + "def_class_body" + ": Provided an null entry"); + return InvalidCode; } - - switch ( entry->Type ) + switch (entry->Type) { - GEN_AST_BODY_CLASS_UNALLOWED_TYPES - log_failure( - "gen::" - "def_class_body" - ": Entry type is not allowed: %s", - entry.debug_str() - ); - return CodeInvalid; + GEN_AST_BODY_CLASS_UNALLOWED_TYPES: + log_failure("gen::" "def_class_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; - default : - break; + default: + break; } - - result.append( entry ); - } while ( num--, num > 0 ); - va_end( va ); + body_append(result, entry); + } + while (num--, num > 0); + va_end(va); return result; } @@ -16488,41 +18000,29 @@ CodeBody def_class_body( s32 num, Code* codes ) { def_body_code_array_start( def_class_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Function_Body; - + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Function_Body; do { Code entry = *codes; codes++; - - if ( ! entry ) - { - log_failure( - "gen::" - "def_class_body" - ": Provided an null entry" - ); - return CodeInvalid; + if ( ! entry) { + log_failure("gen::" "def_class_body" ": Provided an null entry"); + return InvalidCode; } - - switch ( entry->Type ) + switch (entry->Type) { - GEN_AST_BODY_CLASS_UNALLOWED_TYPES - log_failure( - "gen::" - "def_class_body" - ": Entry type is not allowed: %s", - entry.debug_str() - ); - return CodeInvalid; + GEN_AST_BODY_CLASS_UNALLOWED_TYPES: + log_failure("gen::" "def_class_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; - default : - break; + default: + break; } - - result.append( entry ); - } while ( num--, num > 0 ); + body_append(result, entry); + } + while (num--, num > 0); return result; } @@ -16531,60 +18031,53 @@ CodeBody def_enum_body( s32 num, ... ) { def_body_start( def_enum_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Enum_Body; + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Enum_Body; va_list va; - va_start( va, num ); + va_start(va, num); do { - Code_POD pod = va_arg( va, Code_POD ); - Code entry = pcast( Code, pod ); - - if ( ! entry ) - { - log_failure( "gen::def_enum_body: Provided a null entry" ); - return CodeInvalid; + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + if ( ! entry ) { + log_failure("gen::def_enum_body: Provided a null entry"); + return InvalidCode; } - - if ( entry->Type != Untyped && entry->Type != Comment ) - { - log_failure( "gen::def_enum_body: Entry type is not allowed - %s. Must be of untyped or comment type.", entry.debug_str() ); - return CodeInvalid; + if ( entry->Type != CT_Untyped && entry->Type != CT_Comment ) { + log_failure("gen::def_enum_body: Entry type is not allowed - %s. Must be of untyped or comment type.", code_debug_str(entry) ); + return InvalidCode; } + body_append(result, entry ); + } + while ( num--, num > 0 ); + va_end(va); - result.append( entry ); - } while ( num--, num > 0 ); - va_end( va ); - - return ( CodeBody )result; + return (CodeBody) result; } CodeBody def_enum_body( s32 num, Code* codes ) { def_body_code_array_start( def_enum_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Enum_Body; - + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Enum_Body; do { Code entry = *codes; - - if ( ! entry ) - { - log_failure( "gen::def_enum_body: Provided a null entry" ); - return CodeInvalid; + if ( ! entry ) { + log_failure("gen::def_enum_body: Provided a null entry"); + return InvalidCode; } - - if ( entry->Type != Untyped && entry->Type != Comment ) - { - log_failure( "gen::def_enum_body: Entry type is not allowed: %s", entry.debug_str() ); - return CodeInvalid; + if ( entry->Type != CT_Untyped && entry->Type != CT_Comment ) { + log_failure("gen::def_enum_body: Entry type is not allowed: %s", code_debug_str(entry) ); + return InvalidCode; } - - result.append( entry ); - } while ( codes++, num--, num > 0 ); + body_append(result, entry ); + } + while ( codes++, num--, num > 0 ); return result; } @@ -16593,44 +18086,34 @@ CodeBody def_export_body( s32 num, ... ) { def_body_start( def_export_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Export_Body; + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Export_Body; va_list va; - va_start( va, num ); + va_start(va, num); do { - Code_POD pod = va_arg( va, Code_POD ); - Code entry = pcast( Code, pod ); - - if ( ! entry ) + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + if ( ! entry) { - log_failure( - "gen::" - "def_export_body" - ": Provided an null entry" - ); - return CodeInvalid; + log_failure("gen::" "def_export_body" ": Provided an null entry"); + return InvalidCode; } - - switch ( entry->Type ) + switch (entry->Type) { - GEN_AST_BODY_EXPORT_UNALLOWED_TYPES - log_failure( - "gen::" - "def_export_body" - ": Entry type is not allowed: %s", - entry.debug_str() - ); - return CodeInvalid; + GEN_AST_BODY_EXPORT_UNALLOWED_TYPES: + log_failure("gen::" "def_export_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; - default : - break; + default: + break; } - - result.append( entry ); - } while ( num--, num > 0 ); - va_end( va ); + body_append(result, entry); + } + while (num--, num > 0); + va_end(va); return result; } @@ -16639,41 +18122,29 @@ CodeBody def_export_body( s32 num, Code* codes ) { def_body_code_array_start( def_export_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Export_Body; - + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Export_Body; do { Code entry = *codes; codes++; - - if ( ! entry ) - { - log_failure( - "gen::" - "def_export_body" - ": Provided an null entry" - ); - return CodeInvalid; + if ( ! entry) { + log_failure("gen::" "def_export_body" ": Provided an null entry"); + return InvalidCode; } - - switch ( entry->Type ) + switch (entry->Type) { - GEN_AST_BODY_EXPORT_UNALLOWED_TYPES - log_failure( - "gen::" - "def_export_body" - ": Entry type is not allowed: %s", - entry.debug_str() - ); - return CodeInvalid; + GEN_AST_BODY_EXPORT_UNALLOWED_TYPES: + log_failure("gen::" "def_export_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; - default : - break; + default: + break; } - - result.append( entry ); - } while ( num--, num > 0 ); + body_append(result, entry); + } + while (num--, num > 0); return result; } @@ -16682,44 +18153,33 @@ CodeBody def_extern_link_body( s32 num, ... ) { def_body_start( def_extern_linkage_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Extern_Linkage_Body; + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Extern_Linkage_Body; va_list va; - va_start( va, num ); + va_start(va, num); do { - Code_POD pod = va_arg( va, Code_POD ); - Code entry = pcast( Code, pod ); - - if ( ! entry ) - { - log_failure( - "gen::" - "def_extern_linkage_body" - ": Provided an null entry" - ); - return CodeInvalid; + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + if ( ! entry) { + log_failure("gen::" "def_extern_linkage_body" ": Provided an null entry"); + return InvalidCode; } - - switch ( entry->Type ) + switch (entry->Type) { - GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES - log_failure( - "gen::" - "def_extern_linkage_body" - ": Entry type is not allowed: %s", - entry.debug_str() - ); - return CodeInvalid; + GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES: + log_failure("gen::" "def_extern_linkage_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; - default : - break; + default: + break; } - - result.append( entry ); - } while ( num--, num > 0 ); - va_end( va ); + body_append(result, entry); + } + while (num--, num > 0); + va_end(va); return result; } @@ -16728,42 +18188,30 @@ CodeBody def_extern_link_body( s32 num, Code* codes ) { def_body_code_array_start( def_extern_linkage_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Extern_Linkage_Body; - + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Extern_Linkage_Body; do { Code entry = *codes; codes++; - - if ( ! entry ) + if (!entry) { - log_failure( - "gen::" - "def_extern_linkage_body" - ": Provided an null entry" - ); - return CodeInvalid; + log_failure("gen::" "def_extern_linkage_body" ": Provided an null entry"); + return InvalidCode; } - - switch ( entry->Type ) + switch (entry->Type) { - GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES - log_failure( - "gen::" - "def_extern_linkage_body" - ": Entry type is not allowed: %s", - entry.debug_str() - ); - return CodeInvalid; + GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES: + log_failure("gen::" "def_extern_linkage_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; - default : - break; + default: + break; } - - result.append( entry ); - - } while ( num--, num > 0 ); + body_append(result, entry); + } + while (num--, num > 0); return result; } @@ -16772,36 +18220,33 @@ CodeBody def_function_body( s32 num, ... ) { def_body_start( def_function_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Function_Body; + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Function_Body; va_list va; - va_start( va, num ); + va_start(va, num); do { - Code_POD pod = va_arg( va, Code_POD ); - Code entry = pcast( Code, pod ); - - if ( ! entry ) - { - log_failure( "gen::" stringize( def_function_body ) ": Provided an null entry" ); - return CodeInvalid; + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + if ( ! entry) { + log_failure("gen::" stringize(def_function_body) ": Provided an null entry"); + return InvalidCode; } - - switch ( entry->Type ) + switch (entry->Type) { + GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES: + log_failure("gen::" stringize(def_function_body) ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; - GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES - log_failure( "gen::" stringize( def_function_body ) ": Entry type is not allowed: %s", entry.debug_str() ); - return CodeInvalid; - - default : - break; + default: + break; } - - result.append( entry ); - } while ( num--, num > 0 ); - va_end( va ); + body_append(result, entry); + } + while (num--, num > 0); + va_end(va); return result; } @@ -16810,40 +18255,29 @@ CodeBody def_function_body( s32 num, Code* codes ) { def_body_code_array_start( def_function_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Function_Body; - + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Function_Body; do { Code entry = *codes; codes++; - - if ( ! entry ) - { - log_failure( - "gen::" - "def_function_body" - ": Provided an null entry" - ); - return CodeInvalid; + if (!entry) { + log_failure("gen::" "def_function_body" ": Provided an null entry"); + return InvalidCode; } - - switch ( entry->Type ) + switch (entry->Type) { - GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES - log_failure( - "gen::" - "def_function_body" - ": Entry type is not allowed: %s", - entry.debug_str() - ); - return CodeInvalid; + GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES: + log_failure("gen::" "def_function_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; - default : - break; + default: + break; } - result.append( entry ); - } while ( num--, num > 0 ); + body_append(result, entry); + } + while (num--, num > 0); return result; } @@ -16852,48 +18286,38 @@ CodeBody def_global_body( s32 num, ... ) { def_body_start( def_global_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Global_Body; + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Global_Body; va_list va; - va_start( va, num ); + va_start(va, num); do { - Code_POD pod = va_arg( va, Code_POD ); - Code entry = pcast( Code, pod ); - - if ( ! entry ) - { - log_failure( - "gen::" - "def_global_body" - ": Provided an null entry" - ); - return CodeInvalid; + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + if ( ! entry) { + log_failure("gen::" "def_global_body" ": Provided an null entry"); + return InvalidCode; } - - switch ( entry->Type ) + switch (entry->Type) { - case Global_Body : - result.append( entry.cast< CodeBody >() ); + case CT_Global_Body: + // result.body_append( entry.code_cast() ) ; + body_append_body( result, cast(CodeBody, entry) ); continue; - GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES - log_failure( - "gen::" - "def_global_body" - ": Entry type is not allowed: %s", - entry.debug_str() - ); - return ( *Code::Invalid.ast ); + GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES: + log_failure("gen::" "def_global_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; - default : - break; + default: + break; } - - result.append( entry ); - } while ( num--, num > 0 ); - va_end( va ); + body_append(result, entry); + } + while (num--, num > 0); + va_end(va); return result; } @@ -16902,45 +18326,34 @@ CodeBody def_global_body( s32 num, Code* codes ) { def_body_code_array_start( def_global_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Global_Body; - + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Global_Body; do { Code entry = *codes; codes++; - - if ( ! entry ) - { - log_failure( - "gen::" - "def_global_body" - ": Provided an null entry" - ); - return CodeInvalid; + if ( ! entry) { + log_failure("gen::" "def_global_body" ": Provided an null entry"); + return InvalidCode; } - - switch ( entry->Type ) + switch (entry->Type) { - case Global_Body : - result.append( entry.cast< CodeBody >() ); + case CT_Global_Body: + body_append_body(result, cast(CodeBody, entry) ); continue; - GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES - log_failure( - "gen::" - "def_global_body" - ": Entry type is not allowed: %s", - entry.debug_str() - ); - return CodeInvalid; + GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES: + log_failure("gen::" "def_global_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; - default : - break; + default: + break; } - result.append( entry ); - } while ( num--, num > 0 ); + body_append(result, entry); + } + while (num--, num > 0); return result; } @@ -16949,44 +18362,33 @@ CodeBody def_namespace_body( s32 num, ... ) { def_body_start( def_namespace_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Namespace_Body; + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Namespace_Body; va_list va; - va_start( va, num ); + va_start(va, num); do { - Code_POD pod = va_arg( va, Code_POD ); - Code entry = pcast( Code, pod ); - - if ( ! entry ) - { - log_failure( - "gen::" - "def_namespace_body" - ": Provided an null entry" - ); - return CodeInvalid; + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + if ( ! entry) { + log_failure("gen::" "def_namespace_body" ": Provided an null entry"); + return InvalidCode; } - - switch ( entry->Type ) + switch (entry->Type) { - GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES - log_failure( - "gen::" - "def_namespace_body" - ": Entry type is not allowed: %s", - entry.debug_str() - ); - return CodeInvalid; + GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES: + log_failure("gen::" "def_namespace_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; - default : - break; + default: + break; } - - result.append( entry ); - } while ( num--, num > 0 ); - va_end( va ); + body_append(result, entry); + } + while (num--, num > 0); + va_end(va); return result; } @@ -16995,171 +18397,140 @@ CodeBody def_namespace_body( s32 num, Code* codes ) { def_body_code_array_start( def_namespace_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Global_Body; - + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Global_Body; do { Code entry = *codes; codes++; - - if ( ! entry ) - { - log_failure( - "gen::" - "def_namespace_body" - ": Provided an null entry" - ); - return CodeInvalid; + if ( ! entry) { + log_failure("gen::" "def_namespace_body" ": Provided an null entry"); + return InvalidCode; } - - switch ( entry->Type ) + switch (entry->Type) { - GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES - log_failure( - "gen::" - "def_namespace_body" - ": Entry type is not allowed: %s", - entry.debug_str() - ); - return CodeInvalid; + GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES: + log_failure("gen::" "def_namespace_body" ": Entry type is not allowed: %s", code_debug_str(entry) ); + return InvalidCode; - default : - break; + default: break; } - - result.append( entry ); - } while ( num--, num > 0 ); + body_append(result, entry); + } + while (num--, num > 0); return result; } -CodeParam def_params( s32 num, ... ) +CodeParams def_params( s32 num, ... ) { def_body_start( def_params ); va_list va; - va_start( va, num ); + va_start(va, num); - Code_POD pod = va_arg( va, Code_POD ); - CodeParam param = pcast( CodeParam, pod ); + Code_POD pod = va_arg(va, Code_POD); + CodeParams param = pcast( CodeParams, pod ); null_check( def_params, param ); - - if ( param->Type != Parameters ) - { + if ( param->Type != CT_Parameters ) { log_failure( "gen::def_params: param %d is not a Parameters", num - num + 1 ); - return CodeInvalid; + return InvalidCode; } - CodeParam result = ( CodeParam )param.duplicate(); - - while ( --num ) + CodeParams result = (CodeParams) code_duplicate(param); + while ( -- num ) { - pod = va_arg( va, Code_POD ); - param = pcast( CodeParam, pod ); - - if ( param->Type != Parameters ) - { + pod = va_arg(va, Code_POD); + param = pcast( CodeParams, pod ); + if ( param->Type != CT_Parameters ) { log_failure( "gen::def_params: param %d is not a Parameters", num - num + 1 ); - return CodeInvalid; + return InvalidCode; } - - result.append( param ); + params_append(result, param ); } - va_end( va ); + va_end(va); return result; } -CodeParam def_params( s32 num, CodeParam* codes ) +CodeParams def_params( s32 num, CodeParams* codes ) { def_body_code_array_start( def_params ); -#define check_current() \ - if ( current.ast == nullptr ) \ - { \ - log_failure( "gen::def_params: Provide a null code in codes array" ); \ - return CodeInvalid; \ - } \ - \ - if ( current->Type != Parameters ) \ - { \ - log_failure( "gen::def_params: Code in coes array is not of paramter type - %s", current.debug_str() ); \ - return CodeInvalid; \ +# define check_current(current) \ + if ( current == nullptr ) { \ + log_failure("gen::def_params: Provide a null code in codes array"); \ + return InvalidCode; \ + } \ + if (current->Type != CT_Parameters ) { \ + log_failure("gen::def_params: Code in coes array is not of paramter type - %s", code_debug_str(current) ); \ + return InvalidCode; \ } + CodeParams current = (CodeParams)code_duplicate(* codes); + check_current(current); - CodeParam current = ( CodeParam )codes->duplicate(); - check_current(); - - CodeParam result = ( CodeParam )make_code(); + CodeParams + result = (CodeParams) make_code(); result->Name = current->Name; result->Type = current->Type; result->ValueType = current->ValueType; - - while ( codes++, current = *codes, num--, num > 0 ) - { - check_current(); - result.append( current ); + while( codes++, current = * codes, num--, num > 0 ) { + check_current(current); + params_append(result, current ); } -#undef check_current +# undef check_current return result; } CodeSpecifiers def_specifiers( s32 num, ... ) { - if ( num <= 0 ) - { - log_failure( "gen::def_specifiers: num cannot be zero or less" ); - return CodeInvalid; + if ( num <= 0 ) { + log_failure("gen::def_specifiers: num cannot be zero or less"); + return InvalidCode; } - - if ( num > AST::ArrSpecs_Cap ) - { - log_failure( "gen::def_specifiers: num of speciifers to define AST larger than AST specicifier capacity - %d", num ); - return CodeInvalid; + if ( num > AST_ArrSpecs_Cap ) { + log_failure("gen::def_specifiers: num of speciifers to define AST larger than AST specicifier capacity - %d", num); + return InvalidCode; } - - CodeSpecifiers result = ( CodeSpecifiers )make_code(); - result->Type = ECode::Specifiers; + CodeSpecifiers + result = (CodeSpecifiers) make_code(); + result->Type = CT_Specifiers; va_list va; - va_start( va, num ); - do - { - SpecifierT type = ( SpecifierT )va_arg( va, int ); - - result.append( type ); - } while ( --num, num ); - va_end( va ); + va_start(va, num); + do { + Specifier type = (Specifier)va_arg(va, int); + specifiers_append(result, type ); + } + while ( --num, num ); + va_end(va); return result; } -CodeSpecifiers def_specifiers( s32 num, SpecifierT* specs ) +CodeSpecifiers def_specifiers( s32 num, Specifier* specs ) { - if ( num <= 0 ) - { - log_failure( "gen::def_specifiers: num cannot be zero or less" ); - return CodeInvalid; + if ( num <= 0 ) { + log_failure("gen::def_specifiers: num cannot be zero or less"); + return InvalidCode; } - - if ( num > AST::ArrSpecs_Cap ) - { - log_failure( "gen::def_specifiers: num of speciifers to define AST larger than AST specicifier capacity - %d", num ); - return CodeInvalid; + if ( num > AST_ArrSpecs_Cap ) { + log_failure("gen::def_specifiers: num of speciifers to define AST larger than AST specicifier capacity - %d", num); + return InvalidCode; } + CodeSpecifiers + result = (CodeSpecifiers) make_code(); + result->Type = CT_Specifiers; - CodeSpecifiers result = ( CodeSpecifiers )make_code(); - result->Type = ECode::Specifiers; - - s32 idx = 0; - do - { - result.append( specs[ idx ] ); + s32 idx = 0; + do { + specifiers_append(result, specs[idx] ); idx++; - } while ( --num, num ); + } + while ( --num, num ); return result; } @@ -17168,44 +18539,33 @@ CodeBody def_struct_body( s32 num, ... ) { def_body_start( def_struct_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Struct_Body; + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Struct_Body; va_list va; - va_start( va, num ); + va_start(va, num); do { - Code_POD pod = va_arg( va, Code_POD ); - Code entry = pcast( Code, pod ); - - if ( ! entry ) - { - log_failure( - "gen::" - "def_struct_body" - ": Provided an null entry" - ); - return CodeInvalid; + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + if ( ! entry) { + log_failure("gen::" "def_struct_body" ": Provided an null entry"); + return InvalidCode; } - - switch ( entry->Type ) + switch (entry->Type) { - GEN_AST_BODY_STRUCT_UNALLOWED_TYPES - log_failure( - "gen::" - "def_struct_body" - ": Entry type is not allowed: %s", - entry.debug_str() - ); - return CodeInvalid; + GEN_AST_BODY_STRUCT_UNALLOWED_TYPES: + log_failure("gen::" "def_struct_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; - default : - break; + default: + break; } - - result.append( entry ); - } while ( num--, num > 0 ); - va_end( va ); + body_append(result, entry); + } + while (num--, num > 0); + va_end(va); return result; } @@ -17214,41 +18574,29 @@ CodeBody def_struct_body( s32 num, Code* codes ) { def_body_code_array_start( def_struct_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Struct_Body; - + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Struct_Body; do { Code entry = *codes; codes++; - - if ( ! entry ) - { - log_failure( - "gen::" - "def_struct_body" - ": Provided an null entry" - ); - return CodeInvalid; + if ( ! entry) { + log_failure("gen::" "def_struct_body" ": Provided an null entry"); + return InvalidCode; } - - switch ( entry->Type ) + switch (entry->Type) { - GEN_AST_BODY_STRUCT_UNALLOWED_TYPES - log_failure( - "gen::" - "def_struct_body" - ": Entry type is not allowed: %s", - entry.debug_str() - ); - return CodeInvalid; + GEN_AST_BODY_STRUCT_UNALLOWED_TYPES: + log_failure("gen::" "def_struct_body" ": Entry type is not allowed: %s", code_debug_str(entry) ); + return InvalidCode; - default : - break; + default: + break; } - - result.append( entry ); - } while ( num--, num > 0 ); + body_append(result, entry); + } + while (num--, num > 0); return result; } @@ -17257,1653 +18605,1543 @@ CodeBody def_union_body( s32 num, ... ) { def_body_start( def_union_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Union_Body; + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Union_Body; va_list va; - va_start( va, num ); + va_start(va, num); do { - Code_POD pod = va_arg( va, Code_POD ); + Code_POD pod = va_arg(va, Code_POD); Code entry = pcast( Code, pod ); - - if ( ! entry ) - { - log_failure( "gen::def_union_body: Provided a null entry" ); - return CodeInvalid; + if ( ! entry ) { + log_failure("gen::def_union_body: Provided a null entry"); + return InvalidCode; } - - if ( entry->Type != Untyped && entry->Type != Comment ) - { - log_failure( "gen::def_union_body: Entry type is not allowed - %s. Must be of untyped or comment type.", entry.debug_str() ); - return CodeInvalid; + if ( entry->Type != CT_Untyped && entry->Type != CT_Comment ) { + log_failure("gen::def_union_body: Entry type is not allowed - %s. Must be of untyped or comment type.", code_debug_str(entry) ); + return InvalidCode; } - - result.append( entry ); - } while ( num--, num > 0 ); - va_end( va ); + body_append(result, entry ); + } + while ( num--, num > 0 ); + va_end(va); return result; } -CodeBody def_union_body( s32 num, CodeUnion* codes ) +CodeBody def_union_body( s32 num, Code* codes ) { def_body_code_array_start( def_union_body ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Union_Body; - + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Union_Body; do { Code entry = *codes; - - if ( ! entry ) - { - log_failure( "gen::def_union_body: Provided a null entry" ); - return CodeInvalid; + if ( ! entry ) { + log_failure("gen::def_union_body: Provided a null entry"); + return InvalidCode; } - - if ( entry->Type != Untyped && entry->Type != Comment ) - { - log_failure( "gen::def_union_body: Entry type is not allowed: %s", entry.debug_str() ); - return CodeInvalid; + if ( entry->Type != CT_Untyped && entry->Type != CT_Comment ) { + log_failure("gen::def_union_body: Entry type is not allowed: %s", code_debug_str(entry) ); + return InvalidCode; } + body_append(result, entry ); + } + while ( codes++, num--, num > 0 ); - result.append( entry ); - } while ( codes++, num--, num > 0 ); - - return ( CodeBody )result; + return (CodeBody) result; } -#undef name_check -#undef null_check -#undef null_or_invalid_check -#undef def_body_start -#undef def_body_code_array_start +# undef name_check +# undef null_check +# undef def_body_start +# undef def_body_code_array_start #pragma endregion Upfront #pragma region Parsing -namespace Parser + +StrBuilder tok_to_strbuilder(Token tok) { - namespace ETokType - { -#define GEN_DEFINE_ATTRIBUTE_TOKENS Entry( API_Export, GEN_API_Export_Code ) Entry( API_Import, GEN_API_Import_Code ) + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, kilobytes(4) ); + Str type_str = toktype_to_str( tok.Type ); - enum Type : u32 - { - Invalid, - Access_Private, - Access_Protected, - Access_Public, - Access_MemberSymbol, - Access_StaticSymbol, - Ampersand, - Ampersand_DBL, - Assign_Classifer, - Attribute_Open, - Attribute_Close, - BraceCurly_Open, - BraceCurly_Close, - BraceSquare_Open, - BraceSquare_Close, - Capture_Start, - Capture_End, - Comment, - Comment_End, - Comment_Start, - Char, - Comma, - Decl_Class, - Decl_GNU_Attribute, - Decl_MSVC_Attribute, - Decl_Enum, - Decl_Extern_Linkage, - Decl_Friend, - Decl_Module, - Decl_Namespace, - Decl_Operator, - Decl_Struct, - Decl_Template, - Decl_Typedef, - Decl_Using, - Decl_Union, - Identifier, - Module_Import, - Module_Export, - NewLine, - Number, - Operator, - Preprocess_Hash, - Preprocess_Define, - Preprocess_If, - Preprocess_IfDef, - Preprocess_IfNotDef, - Preprocess_ElIf, - Preprocess_Else, - Preprocess_EndIf, - Preprocess_Include, - Preprocess_Pragma, - Preprocess_Content, - Preprocess_Macro, - Preprocess_Unsupported, - Spec_Alignas, - Spec_Const, - Spec_Consteval, - Spec_Constexpr, - Spec_Constinit, - Spec_Explicit, - Spec_Extern, - Spec_Final, - Spec_ForceInline, - Spec_Global, - Spec_Inline, - Spec_Internal_Linkage, - Spec_LocalPersist, - Spec_Mutable, - Spec_NeverInline, - Spec_Override, - Spec_Static, - Spec_ThreadLocal, - Spec_Volatile, - Spec_Virtual, - Star, - Statement_End, - StaticAssert, - String, - Type_Unsigned, - Type_Signed, - Type_Short, - Type_Long, - Type_char, - Type_int, - Type_double, - Type_MS_int8, - Type_MS_int16, - Type_MS_int32, - Type_MS_int64, - Type_MS_W64, - Varadic_Argument, - __Attributes_Start, - API_Export, - API_Import, - NumTokens - }; + strbuilder_append_fmt( & result, "Line: %d Column: %d, Type: %.*s Content: %.*s" + , tok.Line, tok.Column + , type_str.Len, type_str.Ptr + , tok.Text.Len, tok.Text.Ptr + ); + return result; +} - StrC to_str( Type type ) - { - local_persist StrC lookup[] { - {sizeof( "__invalid__" ), "__invalid__" }, - { sizeof( "private" ), "private" }, - { sizeof( "protected" ), "protected" }, - { sizeof( "public" ), "public" }, - { sizeof( "." ), "." }, - { sizeof( "::" ), "::" }, - { sizeof( "&" ), "&" }, - { sizeof( "&&" ), "&&" }, - { sizeof( ":" ), ":" }, - { sizeof( "[[" ), "[[" }, - { sizeof( "]]" ), "]]" }, - { sizeof( "{" ), "{" }, - { sizeof( "}" ), "}" }, - { sizeof( "[" ), "[" }, - { sizeof( "]" ), "]" }, - { sizeof( "(" ), "(" }, - { sizeof( ")" ), ")" }, - { sizeof( "__comment__" ), "__comment__" }, - { sizeof( "__comment_end__" ), "__comment_end__" }, - { sizeof( "__comment_start__" ), "__comment_start__" }, - { sizeof( "__character__" ), "__character__" }, - { sizeof( "," ), "," }, - { sizeof( "class" ), "class" }, - { sizeof( "__attribute__" ), "__attribute__" }, - { sizeof( "__declspec" ), "__declspec" }, - { sizeof( "enum" ), "enum" }, - { sizeof( "extern" ), "extern" }, - { sizeof( "friend" ), "friend" }, - { sizeof( "module" ), "module" }, - { sizeof( "namespace" ), "namespace" }, - { sizeof( "operator" ), "operator" }, - { sizeof( "struct" ), "struct" }, - { sizeof( "template" ), "template" }, - { sizeof( "typedef" ), "typedef" }, - { sizeof( "using" ), "using" }, - { sizeof( "union" ), "union" }, - { sizeof( "__identifier__" ), "__identifier__" }, - { sizeof( "import" ), "import" }, - { sizeof( "export" ), "export" }, - { sizeof( "__new_line__" ), "__new_line__" }, - { sizeof( "__number__" ), "__number__" }, - { sizeof( "__operator__" ), "__operator__" }, - { sizeof( "#" ), "#" }, - { sizeof( "define" ), "define" }, - { sizeof( "if" ), "if" }, - { sizeof( "ifdef" ), "ifdef" }, - { sizeof( "ifndef" ), "ifndef" }, - { sizeof( "elif" ), "elif" }, - { sizeof( "else" ), "else" }, - { sizeof( "endif" ), "endif" }, - { sizeof( "include" ), "include" }, - { sizeof( "pragma" ), "pragma" }, - { sizeof( "__macro_content__" ), "__macro_content__" }, - { sizeof( "__macro__" ), "__macro__" }, - { sizeof( "__unsupported__" ), "__unsupported__" }, - { sizeof( "alignas" ), "alignas" }, - { sizeof( "const" ), "const" }, - { sizeof( "consteval" ), "consteval" }, - { sizeof( "constexpr" ), "constexpr" }, - { sizeof( "constinit" ), "constinit" }, - { sizeof( "explicit" ), "explicit" }, - { sizeof( "extern" ), "extern" }, - { sizeof( "final" ), "final" }, - { sizeof( "forceinline" ), "forceinline" }, - { sizeof( "global" ), "global" }, - { sizeof( "inline" ), "inline" }, - { sizeof( "internal" ), "internal" }, - { sizeof( "local_persist" ), "local_persist" }, - { sizeof( "mutable" ), "mutable" }, - { sizeof( "neverinline" ), "neverinline" }, - { sizeof( "override" ), "override" }, - { sizeof( "static" ), "static" }, - { sizeof( "thread_local" ), "thread_local" }, - { sizeof( "volatile" ), "volatile" }, - { sizeof( "virtual" ), "virtual" }, - { sizeof( "*" ), "*" }, - { sizeof( ";" ), ";" }, - { sizeof( "static_assert" ), "static_assert" }, - { sizeof( "__string__" ), "__string__" }, - { sizeof( "unsigned" ), "unsigned" }, - { sizeof( "signed" ), "signed" }, - { sizeof( "short" ), "short" }, - { sizeof( "long" ), "long" }, - { sizeof( "char" ), "char" }, - { sizeof( "int" ), "int" }, - { sizeof( "double" ), "double" }, - { sizeof( "__int8" ), "__int8" }, - { sizeof( "__int16" ), "__int16" }, - { sizeof( "__int32" ), "__int32" }, - { sizeof( "__int64" ), "__int64" }, - { sizeof( "_W64" ), "_W64" }, - { sizeof( "..." ), "..." }, - { sizeof( "__attrib_start__" ), "__attrib_start__" }, - { sizeof( "GEN_API_Export_Code" ), "GEN_API_Export_Code"}, - { sizeof( "GEN_API_Import_Code" ), "GEN_API_Import_Code"}, - }; - return lookup[ type ]; - } +bool lex__eat( TokArray* self, TokType type ); - Type to_type( StrC str ) - { - local_persist u32 keymap[ NumTokens ]; - do_once_start for ( u32 index = 0; index < NumTokens; index++ ) - { - StrC enum_str = to_str( ( Type )index ); - keymap[ index ] = crc32( enum_str.Ptr, enum_str.Len - 1 ); - } - do_once_end u32 hash = crc32( str.Ptr, str.Len ); - for ( u32 index = 0; index < NumTokens; index++ ) - { - if ( keymap[ index ] == hash ) - return ( Type )index; - } - return Invalid; - } - - } // namespace ETokType - - using TokType = ETokType::Type; - -} // namespace Parser - -namespace Parser +Token* lex_current(TokArray* self, bool skip_formatting ) { - enum TokFlags : u32 + if ( skip_formatting ) { - TF_Operator = bit( 0 ), - TF_Assign = bit( 0 ), - TF_Preprocess = bit( 1 ), - TF_Comment = bit( 2 ), - TF_Attribute = bit( 3 ), - TF_AccessSpecifier = bit( 4 ), - TF_Specifier = bit( 5 ), - TF_EndDefinition = bit( 6 ), // Either ; or } - }; + while ( self->Arr[self->Idx].Type == Tok_NewLine || self->Arr[self->Idx].Type == Tok_Comment ) + self->Idx++; + } + return & self->Arr[self->Idx]; +} - struct Token +Token* lex_peek(TokArray self, bool skip_formatting) +{ + s32 idx = self.Idx; + if ( skip_formatting ) { - char const* Text; - sptr Length; - TokType Type; - s32 Line; - s32 Column; - bool IsAssign; + while ( self.Arr[idx].Type == Tok_NewLine ) + idx++; - // TokFlags Flags; + return & self.Arr[idx]; + } + return & self.Arr[idx]; +} - operator bool() - { - return Text && Length && Type != TokType::Invalid; - } - - operator StrC() - { - return { Length, Text }; - } - - bool is_access_specifier() - { - return Type >= TokType::Access_Private && Type <= TokType::Access_Public; - } - - bool is_attribute() - { - return Type > TokType::__Attributes_Start; - } - - bool is_preprocessor() - { - return Type >= TokType::Preprocess_Define && Type <= TokType::Preprocess_Pragma; - } - - bool is_preprocess_cond() - { - return Type >= TokType::Preprocess_If && Type <= TokType::Preprocess_EndIf; - } - - bool is_specifier() - { - return ( Type <= TokType::Star && Type >= TokType::Spec_Alignas ) || Type == TokType::Ampersand || Type == TokType::Ampersand_DBL; - } - - AccessSpec to_access_specifier() - { - return scast( AccessSpec, Type ); - } - - String to_string() - { - 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", Line, Column, type_str.Len, type_str.Ptr, Length, Text ); - - return result; - } - }; - - constexpr Token NullToken { nullptr, 0, TokType::Invalid, false, 0, 0 }; - - struct TokArray +Token* lex_previous(TokArray self, bool skip_formatting) +{ + s32 idx = self.Idx; + if ( skip_formatting ) { - Array< Token > Arr; - s32 Idx; + while ( self.Arr[idx].Type == Tok_NewLine ) + idx --; - bool __eat( TokType type ); + return & self.Arr[idx]; + } + return & self.Arr[idx - 1]; +} - Token& current( bool skip_formatting = true ) - { - if ( skip_formatting ) - { - while ( Arr[ Idx ].Type == TokType::NewLine || Arr[ Idx ].Type == TokType::Comment ) - Idx++; - } - - return Arr[ Idx ]; - } - - Token& previous( bool skip_formatting = false ) - { - s32 idx = this->Idx; - - if ( skip_formatting ) - { - while ( Arr[ idx ].Type == TokType::NewLine ) - idx--; - - return Arr[ idx ]; - } - - return Arr[ idx - 1 ]; - } - - Token& next( bool skip_formatting = false ) - { - s32 idx = this->Idx; - - if ( skip_formatting ) - { - while ( Arr[ idx ].Type == TokType::NewLine ) - idx++; - - return Arr[ idx ]; - } - - return Arr[ idx + 1 ]; - } - - Token& operator[]( s32 idx ) - { - return Arr[ idx ]; - } - }; - - constexpr bool dont_skip_formatting = false; - - struct StackNode +Token* lex_next(TokArray self, bool skip_formatting) +{ + s32 idx = self.Idx; + if ( skip_formatting ) { - StackNode* Prev; + while ( self.Arr[idx].Type == Tok_NewLine ) + idx++; - Token Start; - Token Name; // The name of the AST node (if parsed) - StrC ProcName; // The name of the procedure - }; + return & self.Arr[idx + 1]; + } + return & self.Arr[idx + 1]; +} - struct ParseContext +enum +{ + Lex_Continue, + Lex_ReturnNull, +}; + +forceinline +void lexer_move_forward( LexContext* ctx ) +{ + if ( * ctx->scanner == '\n' ) { + ctx->line += 1; + ctx->column = 1; + } + else { + ++ ctx->column; + } + -- ctx->left; + ++ ctx->scanner; +} +#define move_forward() lexer_move_forward(ctx) + +forceinline +void lexer_skip_whitespace( LexContext* ctx ) +{ + while ( ctx->left && char_is_space( * ctx->scanner ) ) + move_forward(); +} +#define skip_whitespace() lexer_skip_whitespace(ctx) + +forceinline +void lexer_end_line( LexContext* ctx ) +{ + while ( ctx->left && (* ctx->scanner) == ' ' ) + move_forward(); + + if ( ctx->left && (* ctx->scanner) == '\r' ) { + move_forward(); + move_forward(); + } + else if ( ctx->left && (* ctx->scanner) == '\n' ) + move_forward(); +} +#define end_line() lexer_end_line(ctx) + +forceinline +s32 lex_preprocessor_directive( LexContext* ctx ) +{ + char const* hash = ctx->scanner; + Token hash_tok = { { hash, 1 }, Tok_Preprocess_Hash, ctx->line, ctx->column, TF_Preprocess }; + array_append( _ctx->Lexer_Tokens, hash_tok ); + + move_forward(); + skip_whitespace(); + + ctx->token.Text.Ptr = ctx->scanner; + while (ctx->left && ! char_is_space((* ctx->scanner)) ) { - TokArray Tokens; - StackNode* Scope; + move_forward(); + ctx->token.Text.Len++; + } - void push( StackNode* node ) + ctx->token.Type = str_to_toktype( tok_to_str(ctx->token) ); + + bool is_preprocessor = ctx->token.Type >= Tok_Preprocess_Define && ctx->token.Type <= Tok_Preprocess_Pragma; + if ( ! is_preprocessor ) + { + ctx->token.Type = Tok_Preprocess_Unsupported; + + // Its an unsupported directive, skip it + s32 within_string = false; + s32 within_char = false; + while ( ctx->left ) { - node->Prev = Scope; - Scope = node; + if ( * ctx->scanner == '"' && ! within_char ) + within_string ^= true; -#if 0 && Build_Debug - log_fmt("\tEntering Context: %.*s\n", Scope->ProcName.Len, Scope->ProcName.Ptr ); -#endif - } + if ( * ctx->scanner == '\'' && ! within_string ) + within_char ^= true; - void pop() - { -#if 0 && Build_Debug - log_fmt("\tPopping Context: %.*s\n", Scope->ProcName.Len, Scope->ProcName.Ptr ); -#endif - Scope = Scope->Prev; - } - - String to_string() - { - String result = String::make_reserve( GlobalAllocator, kilobytes( 4 ) ); - - Token scope_start = Scope->Start; - Token last_valid = Tokens.Idx >= Tokens.Arr.num() ? Tokens.Arr[ Tokens.Arr.num() - 1 ] : Tokens.current(); - - sptr length = scope_start.Length; - char const* current = scope_start.Text + length; - while ( current <= Tokens.Arr.back().Text && *current != '\n' && length < 74 ) + if ( * ctx->scanner == '\\' && ! within_string && ! within_char ) { - current++; - length++; - } + move_forward(); + ctx->token.Text.Len++; - String line = String::make( GlobalAllocator, { length, scope_start.Text } ); - result.append_fmt( "\tScope : %s\n", line ); - line.free(); - - sptr dist = ( sptr )last_valid.Text - ( sptr )scope_start.Text + 2; - sptr length_from_err = dist; - String line_from_err = String::make( GlobalAllocator, { length_from_err, last_valid.Text } ); - - if ( length_from_err < 100 ) - result.append_fmt( "\t(%d, %d):%*c\n", last_valid.Line, last_valid.Column, length_from_err, '^' ); - else - result.append_fmt( "\t(%d, %d)\n", last_valid.Line, last_valid.Column ); - - StackNode* curr_scope = Scope; - s32 level = 0; - do - { - if ( curr_scope->Name ) + if ( (* ctx->scanner) == '\r' ) { - result.append_fmt( "\t%d: %s, AST Name: %.*s\n", level, curr_scope->ProcName.Ptr, curr_scope->Name.Length, curr_scope->Name.Text ); + move_forward(); + ctx->token.Text.Len++; + } + + if ( (* ctx->scanner) == '\n' ) + { + move_forward(); + ctx->token.Text.Len++; + continue; } else { - result.append_fmt( "\t%d: %s\n", level, curr_scope->ProcName.Ptr ); - } - - curr_scope = curr_scope->Prev; - level++; - } while ( curr_scope ); - return result; - } - }; - - global ParseContext Context; - - bool TokArray::__eat( TokType type ) - { - if ( Arr.num() - Idx <= 0 ) - { - log_failure( "No tokens left.\n%s", Context.to_string() ); - return false; - } - - if ( ( Arr[ Idx ].Type == TokType::NewLine && type != TokType::NewLine ) || ( Arr[ Idx ].Type == TokType::Comment && type != TokType::Comment ) ) - { - Idx++; - } - - if ( Arr[ Idx ].Type != type ) - { - log_failure( - "Parse Error, TokArray::eat, Expected: ' %s ' not ' %.*s ' (%d, %d)`\n%s", - ETokType::to_str( type ).Ptr, - Arr[ Idx ].Length, - Arr[ Idx ].Text, - current().Line, - current().Column, - Context.to_string() - ); - - return false; - } - -#if 0 && Build_Debug - log_fmt("Ate: %S\n", Arr[Idx].to_string() ); -#endif - - Idx++; - return true; - } - - global Array< Token > Tokens; - - neverinline TokArray lex( StrC content ) - { -#define current ( *scanner ) - -#define move_forward() \ - { \ - if ( current == '\n' ) \ - { \ - line++; \ - column = 1; \ - } \ - else \ - { \ - column++; \ - } \ - left--; \ - scanner++; \ - } - -#define SkipWhitespace() \ - while ( left && char_is_space( current ) ) \ - { \ - move_forward(); \ - } - -#define end_line() \ - do \ - { \ - while ( left && current == ' ' ) \ - { \ - move_forward(); \ - } \ - if ( left && current == '\r' ) \ - { \ - move_forward(); \ - move_forward(); \ - } \ - else if ( left && current == '\n' ) \ - { \ - move_forward(); \ - } \ - } while ( 0 ) - - s32 left = content.Len; - char const* scanner = content.Ptr; - - char const* word = scanner; - s32 word_length = 0; - - s32 line = 1; - s32 column = 1; - - SkipWhitespace(); - if ( left <= 0 ) - { - log_failure( "gen::lex: no tokens found (only whitespace provided)" ); - return { { nullptr }, 0 }; - } - - local_persist Arena_64KB defines_map_arena = Arena_64KB::init(); - HashTable< StrC > defines = HashTable< StrC >::init( defines_map_arena ); - - Tokens.clear(); - - while ( left ) - { -#if 0 - if (Tokens.num()) - { - log_fmt("\nLastTok: %S", Tokens.back().to_string()); - } -#endif - - Token token = { scanner, 0, TokType::Invalid, line, column, false }; - - bool is_define = false; - - if ( column == 1 ) - { - if ( current == '\r' ) - { - move_forward(); - token.Length = 1; - } - - if ( current == '\n' ) - { - move_forward(); - - token.Type = TokType::NewLine; - token.Length++; - - Tokens.append( token ); - continue; + log_failure( "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)" + " in preprocessor directive (%d, %d)\n%.100s" + , (* ctx->scanner), ctx->line, ctx->column + , ctx->token.Line, ctx->token.Column, ctx->token.Text ); + break; } } - token.Length = 0; + if ( (* ctx->scanner) == '\r' ) + { + move_forward(); + ctx->token.Text.Len++; + } - SkipWhitespace(); - if ( left <= 0 ) + if ( (* ctx->scanner) == '\n' ) + { + move_forward(); + ctx->token.Text.Len++; break; + } - switch ( current ) + move_forward(); + ctx->token.Text.Len++; + } + + ctx->token.Text.Len = ctx->token.Text.Len + ctx->token.Text.Ptr - hash; + ctx->token.Text.Ptr = hash; + array_append( _ctx->Lexer_Tokens, ctx->token ); + return Lex_Continue; // Skip found token, its all handled here. + } + + if ( ctx->token.Type == Tok_Preprocess_Else || ctx->token.Type == Tok_Preprocess_EndIf ) + { + ctx->token.Flags |= TF_Preprocess_Cond; + array_append( _ctx->Lexer_Tokens, ctx->token ); + end_line(); + return Lex_Continue; + } + else if ( ctx->token.Type >= Tok_Preprocess_If && ctx->token.Type <= Tok_Preprocess_ElIf ) + { + ctx->token.Flags |= TF_Preprocess_Cond; + } + + array_append( _ctx->Lexer_Tokens, ctx->token ); + + skip_whitespace(); + + if ( ctx->token.Type == Tok_Preprocess_Define ) + { + Token name = { { ctx->scanner, 0 }, Tok_Identifier, ctx->line, ctx->column, TF_Preprocess }; + + name.Text.Ptr = ctx->scanner; + name.Text.Len = 1; + move_forward(); + + while ( ctx->left && ( char_is_alphanumeric((* ctx->scanner)) || (* ctx->scanner) == '_' ) ) + { + move_forward(); + name.Text.Len++; + } + + if ( ctx->left && (* ctx->scanner) == '(' ) + { + move_forward(); + name.Text.Len++; + } + + array_append( _ctx->Lexer_Tokens, name ); + + u64 key = crc32( name.Text.Ptr, name.Text.Len ); + hashtable_set(ctx->defines, key, tok_to_str(name) ); + } + + Token preprocess_content = { { ctx->scanner, 0 }, Tok_Preprocess_Content, ctx->line, ctx->column, TF_Preprocess }; + + if ( ctx->token.Type == Tok_Preprocess_Include ) + { + preprocess_content.Type = Tok_String; + + if ( (* ctx->scanner) != '"' && (* ctx->scanner) != '<' ) + { + StrBuilder directive_str = strbuilder_fmt_buf( _ctx->Allocator_Temp, "%.*s", min( 80, ctx->left + preprocess_content.Text.Len ), ctx->token.Text.Ptr ); + + log_failure( "gen::Parser::lex: Expected '\"' or '<' after #include, not '%c' (%d, %d)\n%s" + , (* ctx->scanner) + , preprocess_content.Line + , preprocess_content.Column + , (char*) directive_str + ); + return Lex_ReturnNull; + } + move_forward(); + preprocess_content.Text.Len++; + + while ( ctx->left && (* ctx->scanner) != '"' && (* ctx->scanner) != '>' ) + { + move_forward(); + preprocess_content.Text.Len++; + } + + move_forward(); + preprocess_content.Text.Len++; + + if ( (* ctx->scanner) == '\r' && ctx->scanner[1] == '\n' ) + { + move_forward(); + move_forward(); + } + else if ( (* ctx->scanner) == '\n' ) + { + move_forward(); + } + + array_append( _ctx->Lexer_Tokens, preprocess_content ); + return Lex_Continue; // Skip found token, its all handled here. + } + + s32 within_string = false; + s32 within_char = false; + + // SkipWhitespace(); + while ( ctx->left ) + { + if ( (* ctx->scanner) == '"' && ! within_char ) + within_string ^= true; + + if ( (* ctx->scanner) == '\'' && ! within_string ) + within_char ^= true; + + if ( (* ctx->scanner) == '\\' && ! within_string && ! within_char ) + { + move_forward(); + preprocess_content.Text.Len++; + + if ( (* ctx->scanner) == '\r' ) { - case '#' : + move_forward(); + preprocess_content.Text.Len++; + } + + if ( (* ctx->scanner) == '\n' ) + { + move_forward(); + preprocess_content.Text.Len++; + continue; + } + else + { + StrBuilder directive_str = strbuilder_make_length( _ctx->Allocator_Temp, ctx->token.Text.Ptr, ctx->token.Text.Len ); + StrBuilder content_str = strbuilder_fmt_buf( _ctx->Allocator_Temp, "%.*s", min( 400, ctx->left + preprocess_content.Text.Len ), preprocess_content.Text.Ptr ); + + log_failure( "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)" + " in preprocessor directive '%s' (%d, %d)\n%s" + , (* ctx->scanner), ctx->line, ctx->column + , directive_str, preprocess_content.Line, preprocess_content.Column + , content_str ); + break; + } + } + + if ( (* ctx->scanner) == '\r' ) + { + break; + //move_forward(); + } + + if ( (* ctx->scanner) == '\n' ) + { + //move_forward(); + break; + } + + move_forward(); + preprocess_content.Text.Len++; + } + + array_append( _ctx->Lexer_Tokens, preprocess_content ); + return Lex_Continue; // Skip found token, its all handled here. +} + +forceinline +void lex_found_token( LexContext* ctx ) +{ + if ( ctx->token.Type != Tok_Invalid ) + { + array_append( _ctx->Lexer_Tokens, ctx->token ); + return; + } + + TokType type = str_to_toktype( tok_to_str(ctx->token) ); + + if (type <= Tok_Access_Public && type >= Tok_Access_Private ) + { + ctx->token.Flags |= TF_AccessSpecifier; + } + + if ( type > Tok___Attributes_Start ) + { + ctx->token.Flags |= TF_Attribute; + } + + if ( type == Tok_Decl_Extern_Linkage ) + { + skip_whitespace(); + + if ( (* ctx->scanner) != '"' ) + { + type = Tok_Spec_Extern; + ctx->token.Flags |= TF_Specifier; + } + + ctx->token.Type = type; + array_append( _ctx->Lexer_Tokens, ctx->token ); + return; + } + + if ( ( type <= Tok_Star && type >= Tok_Spec_Alignas) + || type == Tok_Ampersand + || type == Tok_Ampersand_DBL ) + { + ctx->token.Type = type; + ctx->token.Flags |= TF_Specifier; + array_append( _ctx->Lexer_Tokens, ctx->token ); + return; + } + + + if ( type != Tok_Invalid ) + { + ctx->token.Type = type; + array_append( _ctx->Lexer_Tokens, ctx->token ); + return; + } + + u64 key = 0; + if ( (* ctx->scanner) == '(') + key = crc32( ctx->token.Text.Ptr, ctx->token.Text.Len + 1 ); + else + key = crc32( ctx->token.Text.Ptr, ctx->token.Text.Len ); + + Str* define = hashtable_get(ctx->defines, key ); + if ( define ) + { + ctx->token.Type = Tok_Preprocess_Macro; + + // Want to ignore any arguments the define may have as they can be execution expressions. + if ( ctx->left && (* ctx->scanner) == '(' ) + { + move_forward(); + ctx->token.Text.Len++; + + s32 level = 0; + while ( ctx->left && ((* ctx->scanner) != ')' || level > 0) ) + { + if ( (* ctx->scanner) == '(' ) + level++; + + else if ( (* ctx->scanner) == ')' && level > 0 ) + level--; + + move_forward(); + ctx->token.Text.Len++; + } + + move_forward(); + ctx->token.Text.Len++; + } + + //if ( (* ctx->scanner) == '\r' && ctx->scanner[1] == '\n' ) + //{ + // move_forward(); + // ctx->token..Text.Length++; + //} + //else if ( (* ctx->scanner) == '\n' ) + //{ + // move_forward(); + // ctx->token..Text.Length++; + //} + } + else + { + ctx->token.Type = Tok_Identifier; + } + + array_append( _ctx->Lexer_Tokens, ctx->token ); +} + +neverinline +// TokArray lex( Array tokens, Str content ) +TokArray lex( Str content ) +{ + LexContext c; LexContext* ctx = & c; + c.content = content; + c.left = content.Len; + c.scanner = content.Ptr; + c.defines = _ctx->Lexer_defines; + + char const* word = c.scanner; + s32 word_length = 0; + + c.line = 1; + c.column = 1; + + skip_whitespace(); + if ( c.left <= 0 ) + { + log_failure( "gen::lex: no tokens found (only whitespace provided)" ); + TokArray null_array = {}; + return null_array; + } + + for ( StrCached* entry = array_begin(_ctx->PreprocessorDefines); entry != array_end(_ctx->PreprocessorDefines); entry = array_next(_ctx->PreprocessorDefines, entry)) + { + s32 length = 0; + char const* entry_scanner = (*entry).Ptr; + while ( entry->Len > length && (char_is_alphanumeric( *entry_scanner ) || *entry_scanner == '_') ) + { + entry_scanner++; + length ++; + } + if ( entry_scanner[0] == '(' ) + { + length++; + } + + u64 key = crc32( entry->Ptr, length ); + hashtable_set(c.defines, key, * entry ); + } + + array_clear(_ctx->Lexer_Tokens); + + while (c.left ) + { + #if 0 + if (Tokens.num()) + { + log_fmt("\nLastTok: %SB", Tokens.back().to_strbuilder()); + } + #endif + + { + Token thanks_c = { { c.scanner, 0 }, Tok_Invalid, c.line, c.column, TF_Null }; + c.token = thanks_c; + } + + bool is_define = false; + + if ( c.column == 1 ) + { + if ( (* ctx->scanner) == '\r') + { + move_forward(); + c.token.Text.Len = 1; + } + + if ( (* ctx->scanner) == '\n' ) + { + move_forward(); + + c.token.Type = Tok_NewLine; + c.token.Text.Len++; + + array_append( _ctx->Lexer_Tokens, c.token ); + continue; + } + } + + c.token.Text.Len = 0; + + skip_whitespace(); + if ( c.left <= 0 ) + break; + + switch ( (* ctx->scanner) ) + { + case '#': + { + s32 result = lex_preprocessor_directive( ctx ); + switch ( result ) { - char const* hash = scanner; - Tokens.append( { hash, 1, TokType::Preprocess_Hash, line, column, false } ); - - move_forward(); - SkipWhitespace(); - - token.Text = scanner; - while ( left && ! char_is_space( current ) ) + case Lex_Continue: { - move_forward(); - token.Length++; - } - - token.Type = ETokType::to_type( token ); - - if ( ! token.is_preprocessor() ) - { - token.Type = TokType::Preprocess_Unsupported; - - // Its an unsupported directive, skip it - s32 within_string = false; - s32 within_char = false; - while ( left ) + //TokType last_type = Tokens[array_get_header(Tokens)->Num - 2].Type; + //if ( last_type == Tok_Preprocess_Pragma ) { - if ( current == '"' && ! within_char ) - within_string ^= true; - - if ( current == '\'' && ! within_string ) - within_char ^= true; - - if ( current == '\\' && ! within_string && ! within_char ) + { + Token thanks_c = { { c.scanner, 0 }, Tok_Invalid, c.line, c.column, TF_Null }; + c.token = thanks_c; + } + if ( (* ctx->scanner) == '\r') { move_forward(); - token.Length++; - - if ( current == '\r' ) - { - move_forward(); - token.Length++; - } - - if ( current == '\n' ) - { - move_forward(); - token.Length++; - continue; - } - else - { - log_failure( - "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)" - " in preprocessor directive (%d, %d)\n%.100s", - current, - line, - column, - token.Line, - token.Column, - token.Text - ); - break; - } + c.token.Text.Len = 1; } - if ( current == '\r' ) + if ( (* ctx->scanner) == '\n' ) { + c.token.Type = Tok_NewLine; + c.token.Text.Len++; move_forward(); - token.Length++; - } - if ( current == '\n' ) - { - move_forward(); - token.Length++; - break; + array_append( _ctx->Lexer_Tokens, c.token ); } - - move_forward(); - token.Length++; } - - token.Length = token.Length + token.Text - hash; - token.Text = hash; - Tokens.append( token ); - continue; // Skip found token, its all handled here. - } - - if ( token.Type == TokType::Preprocess_Else || token.Type == TokType::Preprocess_EndIf ) - { - Tokens.append( token ); - end_line(); continue; } - Tokens.append( token ); - - SkipWhitespace(); - - if ( token.Type == TokType::Preprocess_Define ) + case Lex_ReturnNull: { - Token name = { scanner, 0, TokType::Identifier, line, column, false }; - - name.Text = scanner; - name.Length = 1; - move_forward(); - - while ( left && ( char_is_alphanumeric( current ) || current == '_' ) ) - { - move_forward(); - name.Length++; - } - - if ( left && current == '(' ) - { - move_forward(); - name.Length++; - } - - Tokens.append( name ); - - u64 key = crc32( name.Text, name.Length ); - defines.set( key, name ); + TokArray tok_array = {}; + return tok_array; } - - Token content = { scanner, 0, TokType::Preprocess_Content, line, column, false }; - - if ( token.Type == TokType::Preprocess_Include ) - { - content.Type = TokType::String; - - if ( current != '"' && current != '<' ) - { - String directive_str = String::fmt_buf( GlobalAllocator, "%.*s", min( 80, left + content.Length ), token.Text ); - - log_failure( - "gen::Parser::lex: Expected '\"' or '<' after #include, not '%c' (%d, %d)\n%s", - current, - content.Line, - content.Column, - directive_str.Data - ); - return { { nullptr }, 0 }; - } - move_forward(); - content.Length++; - - while ( left && current != '"' && current != '>' ) - { - move_forward(); - content.Length++; - } - - move_forward(); - content.Length++; - - Tokens.append( content ); - continue; // Skip found token, its all handled here. - } - - s32 within_string = false; - s32 within_char = false; - - // SkipWhitespace(); - while ( left ) - { - if ( current == '"' && ! within_char ) - within_string ^= true; - - if ( current == '\'' && ! within_string ) - within_char ^= true; - - if ( current == '\\' && ! within_string && ! within_char ) - { - move_forward(); - content.Length++; - - if ( current == '\r' ) - { - move_forward(); - content.Length++; - } - - if ( current == '\n' ) - { - move_forward(); - content.Length++; - continue; - } - else - { - String directive_str = String::make_length( GlobalAllocator, token.Text, token.Length ); - String content_str = String::fmt_buf( GlobalAllocator, "%.*s", min( 400, left + content.Length ), content.Text ); - - log_failure( - "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)" - " in preprocessor directive '%s' (%d, %d)\n%s", - current, - line, - column, - directive_str, - content.Line, - content.Column, - content_str - ); - break; - } - } - - if ( current == '\r' ) - { - move_forward(); - } - - if ( current == '\n' ) - { - move_forward(); - break; - } - - move_forward(); - content.Length++; - } - - Tokens.append( content ); - continue; // Skip found token, its all handled here. } - case '.' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Access_MemberSymbol; - - if ( left ) - { - move_forward(); - } - - if ( current == '.' ) - { - move_forward(); - if ( current == '.' ) - { - token.Length = 3; - token.Type = TokType::Varadic_Argument; - move_forward(); - } - else - { - 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 ); - } - } - - goto FoundToken; - } - case '&' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Ampersand; - - if ( left ) - move_forward(); - - if ( current == '&' ) // && - { - token.Length = 2; - token.Type = TokType::Ampersand_DBL; - - if ( left ) - move_forward(); - } - - goto FoundToken; - } - case ':' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Assign_Classifer; - // Can be either a classifier (ParentType, Bitfield width), or ternary else - // token.Type = TokType::Colon; - - if ( left ) - move_forward(); - - if ( current == ':' ) - { - move_forward(); - token.Type = TokType::Access_StaticSymbol; - token.Length++; - } - goto FoundToken; - } - case '{' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::BraceCurly_Open; - - if ( left ) - move_forward(); - goto FoundToken; - } - case '}' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::BraceCurly_Close; - - if ( left ) - move_forward(); - - end_line(); - goto FoundToken; - } - case '[' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::BraceSquare_Open; - if ( left ) - { - move_forward(); - - if ( current == ']' ) - { - token.Length = 2; - token.Type = TokType::Operator; - move_forward(); - } - } - goto FoundToken; - } - case ']' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::BraceSquare_Close; - - if ( left ) - move_forward(); - goto FoundToken; - } - case '(' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Capture_Start; - - if ( left ) - move_forward(); - goto FoundToken; - } - case ')' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Capture_End; - - if ( left ) - move_forward(); - goto FoundToken; - } - case '\'' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Char; + } + case '.': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Access_MemberSymbol; + c.token.Flags = TF_AccessOperator; + if (c.left) { move_forward(); - - if ( left && current == '\\' ) - { - move_forward(); - token.Length++; - - if ( current == '\'' ) - { - move_forward(); - token.Length++; - } - } - - while ( left && current != '\'' ) - { - move_forward(); - token.Length++; - } - - if ( left ) - { - move_forward(); - token.Length++; - } - goto FoundToken; } - case ',' : + + if ( (* ctx->scanner) == '.' ) { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Comma; - - if ( left ) - move_forward(); - goto FoundToken; - } - case '*' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Star; - - if ( left ) - move_forward(); - - if ( current == '=' ) - { - token.Length++; - token.IsAssign = true; - // token.Flags |= TokFlags::Assignment; - // token.Type = TokType::Assign_Multiply; - - if ( left ) - move_forward(); - } - - goto FoundToken; - } - case ';' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Statement_End; - - if ( left ) - move_forward(); - - end_line(); - goto FoundToken; - } - case '"' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::String; - move_forward(); - while ( left ) + if( (* ctx->scanner) == '.' ) { - if ( current == '"' ) - { - move_forward(); - break; - } - - if ( current == '\\' ) - { - move_forward(); - token.Length++; - - if ( left ) - { - move_forward(); - token.Length++; - } - continue; - } - + c.token.Text.Len = 3; + c.token.Type = Tok_Varadic_Argument; + c.token.Flags = TF_Null; move_forward(); - token.Length++; - } - goto FoundToken; - } - case '?' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Operator; - // token.Type = TokType::Ternary; - token.IsAssign = false; - - if ( left ) - move_forward(); - - goto FoundToken; - } - case '=' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Operator; - // token.Type = TokType::Assign; - token.IsAssign = true; - // token.Flags |= TokFlags::Assignment; - - if ( left ) - move_forward(); - - if ( current == '=' ) - { - token.Length++; - token.IsAssign = false; - - if ( left ) - move_forward(); - } - - goto FoundToken; - } - case '+' : - { - // token.Type = TokType::Add - } - case '%' : - { - // token.Type = TokType::Modulo; - } - case '^' : - { - // token.Type = TokType::B_XOr; - } - case '~' : - { - // token.Type = TokType::Unary_Not; - } - case '!' : - { - // token.Type = TokType::L_Not; - } - case '<' : - { - // token.Type = TokType::Lesser; - } - case '>' : - { - // token.Type = TokType::Greater; - } - case '|' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Operator; - // token.Type = TokType::L_Or; - - if ( left ) - move_forward(); - - if ( current == '=' ) - { - token.Length++; - token.IsAssign = true; - // token.Flags |= TokFlags::Assignment; - // token.Type = TokType::Assign_L_Or; - - if ( left ) - move_forward(); } else - while ( left && current == *( scanner - 1 ) && token.Length < 3 ) - { - token.Length++; - - if ( left ) - move_forward(); - } - goto FoundToken; - } - - // Dash is unfortunatlly a bit more complicated... - case '-' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Operator; - // token.Type = TokType::Subtract; - if ( left ) { - move_forward(); + StrBuilder context_str = strbuilder_fmt_buf( _ctx->Allocator_Temp, "%s", c.scanner, min( 100, c.left ) ); - if ( current == '>' ) - { - token.Length++; - move_forward(); - - if ( current == '*' ) - { - token.Length++; - move_forward(); - } - } - else if ( current == '=' ) - { - token.Length++; - token.IsAssign = true; - // token.Flags |= TokFlags::Assignment; - // token.Type = TokType::Assign_Subtract; - - if ( left ) - move_forward(); - } - else - while ( left && current == *( scanner - 1 ) && token.Length < 3 ) - { - token.Length++; - - if ( left ) - move_forward(); - } - } - goto FoundToken; - } - case '/' : - { - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Operator; - // token.Type = TokType::Divide; - move_forward(); - - if ( left ) - { - if ( current == '=' ) - { - // token.Type = TokeType::Assign_Divide; - move_forward(); - token.Length++; - token.IsAssign = true; - } - else if ( current == '/' ) - { - token.Type = TokType::Comment; - token.Length = 2; - move_forward(); - - while ( left && current != '\n' && current != '\r' ) - { - move_forward(); - token.Length++; - } - - if ( current == '\r' ) - { - move_forward(); - token.Length++; - } - if ( current == '\n' ) - { - move_forward(); - token.Length++; - } - Tokens.append( token ); - continue; - } - else if ( current == '*' ) - { - token.Type = TokType::Comment; - token.Length = 2; - move_forward(); - - bool star = current == '*'; - bool slash = scanner[ 1 ] == '/'; - bool at_end = star && slash; - while ( left && ! at_end ) - { - move_forward(); - token.Length++; - - star = current == '*'; - slash = scanner[ 1 ] == '/'; - at_end = star && slash; - } - token.Length += 2; - move_forward(); - move_forward(); - - if ( current == '\r' ) - { - move_forward(); - token.Length++; - } - if ( current == '\n' ) - { - move_forward(); - token.Length++; - } - Tokens.append( token ); - // end_line(); - continue; - } - } - goto FoundToken; - } - } - - if ( char_is_alpha( current ) || current == '_' ) - { - token.Text = scanner; - token.Length = 1; - move_forward(); - - while ( left && ( char_is_alphanumeric( current ) || current == '_' ) ) - { - move_forward(); - token.Length++; - } - - goto FoundToken; - } - else if ( char_is_digit( current ) ) - { - // This is a very brute force lex, no checks are done for validity of literal. - - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Number; - move_forward(); - - if ( left && ( current == 'x' || current == 'X' || current == 'b' || current == 'B' || current == 'o' || current == 'O' ) ) - { - move_forward(); - token.Length++; - - while ( left && char_is_hex_digit( current ) ) - { - move_forward(); - token.Length++; - } - - goto FoundToken; - } - - while ( left && char_is_digit( current ) ) - { - move_forward(); - token.Length++; - } - - if ( left && current == '.' ) - { - move_forward(); - token.Length++; - - while ( left && char_is_digit( current ) ) - { - move_forward(); - token.Length++; + log_failure( "gen::lex: invalid varadic argument, expected '...' got '..%c' (%d, %d)\n%s", (* ctx->scanner), c.line, c.column, context_str ); } } goto FoundToken; } - else + case '&' : { - s32 start = max( 0, Tokens.num() - 100 ); - log_fmt( "\n%d\n", start ); - for ( s32 idx = start; idx < Tokens.num(); idx++ ) + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Ampersand; + c.token.Flags |= TF_Operator; + c.token.Flags |= TF_Specifier; + + if (c.left) + move_forward(); + + if ( (* ctx->scanner) == '&' ) // && { - log_fmt( "Token %d Type: %s : %.*s\n", idx, ETokType::to_str( Tokens[ idx ].Type ).Ptr, Tokens[ idx ].Length, Tokens[ idx ].Text ); + c.token.Text.Len = 2; + c.token.Type = Tok_Ampersand_DBL; + + if (c.left) + move_forward(); } - 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 ); + goto FoundToken; + } + case ':': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Assign_Classifer; + // Can be either a classifier (ParentType, Bitfield width), or ternary else + // token.Type = Tok_Colon; - // Skip to next whitespace since we can't know if anything else is valid until then. - while ( left && ! char_is_space( current ) ) + if (c.left) + move_forward(); + + if ( (* ctx->scanner) == ':' ) { move_forward(); + c.token.Type = Tok_Access_StaticSymbol; + c.token.Text.Len++; + } + goto FoundToken; + } + case '{': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_BraceCurly_Open; + + if (c.left) + move_forward(); + goto FoundToken; + } + case '}': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_BraceCurly_Close; + c.token.Flags = TF_EndDefinition; + + if (c.left) + move_forward(); + + end_line(); + goto FoundToken; + } + case '[': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_BraceSquare_Open; + if ( c.left ) + { + move_forward(); + + if ( (* ctx->scanner) == ']' ) + { + c.token.Text.Len = 2; + c.token.Type = Tok_Operator; + move_forward(); + } + } + goto FoundToken; + } + case ']': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_BraceSquare_Close; + + if (c.left) + move_forward(); + goto FoundToken; + } + case '(': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Capture_Start; + + if (c.left) + move_forward(); + goto FoundToken; + } + case ')': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Capture_End; + + if (c.left) + move_forward(); + goto FoundToken; + } + case '\'': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Char; + c.token.Flags = TF_Literal; + + move_forward(); + + if ( c.left && (* ctx->scanner) == '\\' ) + { + move_forward(); + c.token.Text.Len++; + + if ( (* ctx->scanner) == '\'' ) + { + move_forward(); + c.token.Text.Len++; + } + } + + while ( c.left && (* ctx->scanner) != '\'' ) + { + move_forward(); + c.token.Text.Len++; + } + + if ( c.left ) + { + move_forward(); + c.token.Text.Len++; + } + goto FoundToken; + } + case ',': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Comma; + c.token.Flags = TF_Operator; + + if (c.left) + move_forward(); + goto FoundToken; + } + case '*': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Star; + c.token.Flags |= TF_Specifier; + c.token.Flags |= TF_Operator; + + if (c.left) + move_forward(); + + if ( (* ctx->scanner) == '=' ) + { + c.token.Text.Len++; + c.token.Flags |= TF_Assign; + // c.token.Type = Tok_Assign_Multiply; + + if ( c.left ) + move_forward(); + } + + goto FoundToken; + } + case ';': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Statement_End; + c.token.Flags = TF_EndDefinition; + + if (c.left) + move_forward(); + + end_line(); + goto FoundToken; + } + case '"': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_String; + c.token.Flags |= TF_Literal; + + move_forward(); + while ( c.left ) + { + if ( (* ctx->scanner) == '"' ) + { + move_forward(); + break; + } + + if ( (* ctx->scanner) == '\\' ) + { + move_forward(); + c.token.Text.Len++; + + if ( c.left ) + { + move_forward(); + c.token.Text.Len++; + } + continue; + } + + move_forward(); + c.token.Text.Len++; + } + goto FoundToken; + } + case '?': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Operator; + // c.token.Type = Tok_Ternary; + c.token.Flags = TF_Operator; + + if (c.left) + move_forward(); + + goto FoundToken; + } + case '=': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Operator; + // c.token.Type = Tok_Assign; + c.token.Flags = TF_Operator; + c.token.Flags |= TF_Assign; + + if (c.left) + move_forward(); + + if ( (* ctx->scanner) == '=' ) + { + c.token.Text.Len++; + c.token.Flags = TF_Operator; + + if (c.left) + move_forward(); + } + + goto FoundToken; + } + case '+': + { + // c.token.Type = Tok_Add + + } + case '%': + { + // c.token.Type = Tok_Modulo; + + } + case '^': + { + // c.token.Type = Tok_B_XOr; + } + case '~': + { + // c.token.Type = Tok_Unary_Not; + + } + case '!': + { + // c.token.Type = Tok_L_Not; + } + case '<': + { + // c.token.Type = Tok_Lesser; + + } + case '>': + { + // c.token.Type = Tok_Greater; + + } + case '|': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Operator; + c.token.Flags = TF_Operator; + // token.Type = Tok_L_Or; + + if (c.left) + move_forward(); + + if ( (* ctx->scanner) == '=' ) + { + c.token.Text.Len++; + c.token.Flags |= TF_Assign; + // token.Flags |= TokFlags::Assignment; + // token.Type = Tok_Assign_L_Or; + + if (c.left) + move_forward(); + } + else while ( c.left && (* ctx->scanner) == *(c.scanner - 1) && c.token.Text.Len < 3 ) + { + c.token.Text.Len++; + + if (c.left) + move_forward(); + } + goto FoundToken; + } + + // Dash is unfortunatlly a bit more complicated... + case '-': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Operator; + // token.Type = Tok_Subtract; + c.token.Flags = TF_Operator; + if ( c.left ) + { + move_forward(); + + if ( (* ctx->scanner) == '>' ) + { + c.token.Text.Len++; +// token.Type = Tok_Access_PointerToMemberSymbol; + c.token.Flags |= TF_AccessOperator; + move_forward(); + + if ( (* ctx->scanner) == '*' ) + { +// token.Type = Tok_Access_PointerToMemberOfPointerSymbol; + c.token.Text.Len++; + move_forward(); + } + } + else if ( (* ctx->scanner) == '=' ) + { + c.token.Text.Len++; + // token.Type = Tok_Assign_Subtract; + c.token.Flags |= TF_Assign; + + if (c.left) + move_forward(); + } + else while ( c.left && (* ctx->scanner) == *(c.scanner - 1) && c.token.Text.Len < 3 ) + { + c.token.Text.Len++; + + if (c.left) + move_forward(); + } + } + goto FoundToken; + } + case '/': + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Operator; + // token.Type = Tok_Divide; + c.token.Flags = TF_Operator; + move_forward(); + + if ( c.left ) + { + if ( (* ctx->scanner) == '=' ) + { + // token.Type = TokeType::Assign_Divide; + move_forward(); + c.token.Text.Len++; + c.token.Flags = TF_Assign; + } + else if ( (* ctx->scanner) == '/' ) + { + c.token.Type = Tok_Comment; + c.token.Text.Len = 2; + c.token.Flags = TF_Null; + move_forward(); + + while ( c.left && (* ctx->scanner) != '\n' && (* ctx->scanner) != '\r' ) + { + move_forward(); + c.token.Text.Len++; + } + + if ( (* ctx->scanner) == '\r' ) + { + move_forward(); + c.token.Text.Len++; + } + if ( (* ctx->scanner) == '\n' ) + { + move_forward(); + c.token.Text.Len++; + } + array_append( _ctx->Lexer_Tokens, c.token ); + continue; + } + else if ( (* ctx->scanner) == '*' ) + { + c.token.Type = Tok_Comment; + c.token.Text.Len = 2; + c.token.Flags = TF_Null; + move_forward(); + + bool star = (* ctx->scanner) == '*'; + bool slash = c.scanner[1] == '/'; + bool at_end = star && slash; + while ( c.left && ! at_end ) + { + move_forward(); + c.token.Text.Len++; + + star = (* ctx->scanner) == '*'; + slash = c.scanner[1] == '/'; + at_end = star && slash; + } + c.token.Text.Len += 2; + move_forward(); + move_forward(); + + if ( (* ctx->scanner) == '\r' ) + { + move_forward(); + c.token.Text.Len++; + } + if ( (* ctx->scanner) == '\n' ) + { + move_forward(); + c.token.Text.Len++; + } + array_append( _ctx->Lexer_Tokens, c.token ); + // end_line(); + continue; + } + } + goto FoundToken; + } + } + + if ( char_is_alpha( (* ctx->scanner) ) || (* ctx->scanner) == '_' ) + { + Str text = { c.scanner, 1 }; + c.token.Text = text; + move_forward(); + + while ( c.left && ( char_is_alphanumeric((* ctx->scanner)) || (* ctx->scanner) == '_' ) ) + { + move_forward(); + c.token.Text.Len++; + } + + goto FoundToken; + } + else if ( char_is_digit((* ctx->scanner)) ) + { + // This is a very brute force lex, no checks are done for validity of literal. + + Str text = { c.scanner, 1 }; + c.token.Text = text; + c.token.Type = Tok_Number; + c.token.Flags = TF_Literal; + move_forward(); + + if (c.left + && ( (* ctx->scanner) == 'x' || (* ctx->scanner) == 'X' + || (* ctx->scanner) == 'b' || (* ctx->scanner) == 'B' + || (* ctx->scanner) == 'o' || (* ctx->scanner) == 'O' ) + ) + { + move_forward(); + c.token.Text.Len++; + + while ( c.left && char_is_hex_digit((* ctx->scanner)) ) + { + move_forward(); + c.token.Text.Len++; + } + + goto FoundToken; + } + + while ( c.left && char_is_digit((* ctx->scanner)) ) + { + move_forward(); + c.token.Text.Len++; + } + + if ( c.left && (* ctx->scanner) == '.' ) + { + move_forward(); + c.token.Text.Len++; + + while ( c.left && char_is_digit((* ctx->scanner)) ) + { + move_forward(); + c.token.Text.Len++; + } + + // Handle number literal suffixes in a botched way + if (c.left && ( + (* ctx->scanner) == 'l' || (* ctx->scanner) == 'L' || // long/long long + (* ctx->scanner) == 'u' || (* ctx->scanner) == 'U' || // unsigned + (* ctx->scanner) == 'f' || (* ctx->scanner) == 'F' || // float + (* ctx->scanner) == 'i' || (* ctx->scanner) == 'I' || // imaginary + (* ctx->scanner) == 'z' || (* ctx->scanner) == 'Z')) // complex + { + char prev = (* ctx->scanner); + move_forward(); + c.token.Text.Len++; + + // Handle 'll'/'LL' as a special case when we just processed an 'l'/'L' + if (c.left && (prev == 'l' || prev == 'L') && ((* ctx->scanner) == 'l' || (* ctx->scanner) == 'L')) + { + move_forward(); + c.token.Text.Len++; + } } } + goto FoundToken; + } + else + { + s32 start = max( 0, array_num(_ctx->Lexer_Tokens) - 100 ); + log_fmt("\n%d\n", start); + for ( s32 idx = start; idx < array_num(_ctx->Lexer_Tokens); idx++ ) + { + log_fmt( "Token %d Type: %s : %.*s\n" + , idx + , toktype_to_str( _ctx->Lexer_Tokens[ idx ].Type ).Ptr + , _ctx->Lexer_Tokens[ idx ].Text.Len, _ctx->Lexer_Tokens[ idx ].Text.Ptr + ); + } + + StrBuilder context_str = strbuilder_fmt_buf( _ctx->Allocator_Temp, "%.*s", min( 100, c.left ), c.scanner ); + log_failure( "Failed to lex token '%c' (%d, %d)\n%s", (* ctx->scanner), c.line, c.column, context_str ); + + // Skip to next whitespace since we can't know if anything else is valid until then. + while ( c.left && ! char_is_space( (* ctx->scanner) ) ) + { + move_forward(); + } + } + FoundToken: - - if ( token.Type != TokType::Invalid ) - { - Tokens.append( token ); - continue; - } - - TokType type = ETokType::to_type( token ); - - if ( type == ETokType::Decl_Extern_Linkage ) - { - SkipWhitespace(); - - if ( current != '"' ) - type = ETokType::Spec_Extern; - - token.Type = type; - Tokens.append( token ); - continue; - } - - if ( type != TokType::Invalid ) - { - token.Type = type; - Tokens.append( token ); - continue; - } - - u64 key = 0; - if ( current == '(' ) - key = crc32( token.Text, token.Length + 1 ); - else - key = crc32( token.Text, token.Length ); - - StrC* define = defines.get( key ); - if ( define ) - { - token.Type = TokType::Preprocess_Macro; - - // Want to ignore any arguments the define may have as they can be execution expressions. - if ( left && current == '(' ) - { - move_forward(); - token.Length++; - - s32 level = 0; - while ( left && ( current != ')' || level > 0 ) ) - { - if ( current == '(' ) - level++; - - else if ( current == ')' && level > 0 ) - level--; - - move_forward(); - token.Length++; - } - - move_forward(); - token.Length++; - } - - if ( current == '\r' && scanner[ 1 ] == '\n' ) - { - move_forward(); - } - else if ( current == '\n' ) - { - move_forward(); - } - } - else - { - token.Type = TokType::Identifier; - } - - Tokens.append( token ); - } - - if ( Tokens.num() == 0 ) { - log_failure( "Failed to lex any tokens" ); - return { { nullptr }, 0 }; + lex_found_token( ctx ); + TokType last_type = array_back(_ctx->Lexer_Tokens)->Type; + if ( last_type == Tok_Preprocess_Macro ) + { + Token thanks_c = { { c.scanner, 0 }, Tok_Invalid, c.line, c.column, TF_Null }; + c.token = thanks_c; + if ( (* ctx->scanner) == '\r') + { + move_forward(); + c.token.Text.Len = 1; + } + + if ( (* ctx->scanner) == '\n' ) + { + c.token.Type = Tok_NewLine; + c.token.Text.Len++; + move_forward(); + + array_append( _ctx->Lexer_Tokens, c.token ); + continue; + } + } } - - defines.clear(); - // defines_map_arena.free(); - return { Tokens, 0 }; -#undef current -#undef move_forward -#undef SkipWhitespace } -} // namespace Parser -internal void init_parser() + if ( array_num(_ctx->Lexer_Tokens) == 0 ) + { + log_failure( "Failed to lex any tokens" ); + { + TokArray tok_array = {}; + return tok_array; + } + } + + hashtable_clear(_ctx->Lexer_defines); + // defines_map_arena.free(); + TokArray result = { _ctx->Lexer_Tokens, 0 }; + return result; +} +#undef move_forward +#undef skip_whitespace +#undef end_line + +// TODO(Ed) : Rename ETok_Capture_Start, ETok_Capture_End to Open_Parenthesis adn Close_Parenthesis + +constexpr bool lex_dont_skip_formatting = false; +constexpr bool lex_skip_formatting = true; + +void parser_push( ParseContext* ctx, StackNode* node ) { - using namespace Parser; + node->Prev = ctx->Scope; + ctx->Scope = node; - Tokens = Array< Token >::init_reserve( LexArena, ( LexAllocator_Size - sizeof( Array< Token >::Header ) ) / sizeof( Token ) ); +#if 0 && GEN_BUILD_DEBUG + log_fmt("\tEntering _ctx->parser: %.*s\n", Scope->ProcName.Len, Scope->ProcName.Ptr ); +#endif } -internal void deinit_parser() +void parser_pop(ParseContext* ctx) { - Parser::Tokens = { nullptr }; +#if 0 && GEN_BUILD_DEBUG + log_fmt("\tPopping _ctx->parser: %.*s\n", Scope->ProcName.Len, Scope->ProcName.Ptr ); +#endif + ctx->Scope = ctx->Scope->Prev; +} + +StrBuilder parser_to_strbuilder(ParseContext ctx) +{ + StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, kilobytes(4) ); + + Token scope_start = * ctx.Scope->Start; + Token last_valid = ctx.Tokens.Idx >= array_num(ctx.Tokens.Arr) ? ctx.Tokens.Arr[array_num(ctx.Tokens.Arr) -1] : (* lex_current(& ctx.Tokens, true)); + + sptr length = scope_start.Text.Len; + char const* current = scope_start.Text.Ptr + length; + while ( current <= array_back( ctx.Tokens.Arr)->Text.Ptr && (* current) != '\n' && length < 74 ) + { + current++; + length++; + } + + Str scope_str = { scope_start.Text.Ptr, length }; + StrBuilder line = strbuilder_make_str( _ctx->Allocator_Temp, scope_str ); + strbuilder_append_fmt( & result, "\tScope : %s\n", line ); + strbuilder_free(& line); + + sptr dist = (sptr)last_valid.Text.Ptr - (sptr)scope_start.Text.Ptr + 2; + sptr length_from_err = dist; + + Str err_str = { last_valid.Text.Ptr, length_from_err }; + StrBuilder line_from_err = strbuilder_make_str( _ctx->Allocator_Temp, err_str ); + + if ( length_from_err < 100 ) + strbuilder_append_fmt(& result, "\t(%d, %d):%*c\n", last_valid.Line, last_valid.Column, length_from_err, '^' ); + else + strbuilder_append_fmt(& result, "\t(%d, %d)\n", last_valid.Line, last_valid.Column ); + + StackNode* curr_scope = ctx.Scope; + s32 level = 0; + do + { + if ( curr_scope->Name.Ptr ) + { + strbuilder_append_fmt(& result, "\t%d: %s, AST Name: %.*s\n", level, curr_scope->ProcName.Ptr, curr_scope->Name.Len, curr_scope->Name.Ptr ); + } + else + { + strbuilder_append_fmt(& result, "\t%d: %s\n", level, curr_scope->ProcName.Ptr ); + } + + curr_scope = curr_scope->Prev; + level++; + } + while ( curr_scope ); + return result; +} + +bool lex__eat(TokArray* self, TokType type ) +{ + if ( array_num(self->Arr) - self->Idx <= 0 ) + { + log_failure( "No tokens left.\n%s", parser_to_strbuilder(_ctx->parser) ); + return false; + } + + Token at_idx = self->Arr[ self->Idx ]; + + if ( ( at_idx.Type == Tok_NewLine && type != Tok_NewLine ) + || ( at_idx.Type == Tok_Comment && type != Tok_Comment ) ) + { + self->Idx ++; + } + + if ( at_idx.Type != type ) + { + Token tok = * lex_current( self, lex_skip_formatting ); + log_failure( "Parse Error, TokArray::eat, Expected: ' %s ' not ' %.*s ' (%d, %d)`\n%s" + , toktype_to_str(type).Ptr + , at_idx.Text.Len, at_idx.Text.Ptr + , tok.Line + , tok.Column + , parser_to_strbuilder(_ctx->parser) + ); + GEN_DEBUG_TRAP(); + return false; + } + +#if 0 && GEN_BUILD_DEBUG + log_fmt("Ate: %SB\n", self->Arr[Idx].to_strbuilder() ); +#endif + + self->Idx ++; + return true; +} + +internal +void parser_init() +{ + _ctx->Lexer_Tokens = array_init_reserve(Token, arena_allocator_info( & _ctx->LexArena) + , ( _ctx->InitSize_LexArena - sizeof( ArrayHeader ) ) / sizeof(Token) + ); + + _ctx->Lexer_defines = hashtable_init_reserve(Str, _ctx->Allocator_DyanmicContainers, 256 ); +} + +internal +void parser_deinit() +{ + Array(Token) null_array = { nullptr }; + _ctx->Lexer_Tokens = null_array; } #pragma region Helper Macros -#define check_parse_args( def ) \ - if ( def.Len <= 0 ) \ - { \ - log_failure( "gen::" stringize( __func__ ) ": length must greater than 0" ); \ - Parser::Context.pop(); \ - return CodeInvalid; \ - } \ - if ( def.Ptr == nullptr ) \ - { \ - log_failure( "gen::" stringize( __func__ ) ": def was null" ); \ - Parser::Context.pop(); \ - return CodeInvalid; \ +#define check_parse_args( def ) _check_parse_args(def, stringize(_func_) ) +bool _check_parse_args( Str def, char const* func_name ) +{ + if ( def.Len <= 0 ) + { + log_failure( c_str_fmt_buf("gen::%s: length must greater than 0", func_name) ); + parser_pop(& _ctx->parser); + return false; } + if ( def.Ptr == nullptr ) + { + log_failure( c_str_fmt_buf("gen::%s: def was null", func_name) ); + parser_pop(& _ctx->parser); + return false; + } + return true; +} -#define currtok_noskip Context.Tokens.current( dont_skip_formatting ) -#define currtok Context.Tokens.current() -#define prevtok Context.Tokens.previous() -#define nexttok Context.Tokens.next() -#define eat( Type_ ) Context.Tokens.__eat( Type_ ) -#define left ( Context.Tokens.Arr.num() - Context.Tokens.Idx ) +# define currtok_noskip (* lex_current( & _ctx->parser.Tokens, lex_dont_skip_formatting )) +# define currtok (* lex_current( & _ctx->parser.Tokens, lex_skip_formatting )) +# define peektok (* lex_peek(_ctx->parser.Tokens, lex_skip_formatting)) +# define prevtok (* lex_previous( _ctx->parser.Tokens, lex_dont_skip_formatting)) +# define nexttok (* lex_next( _ctx->parser.Tokens, lex_skip_formatting )) +# define nexttok_noskip (* lex_next( _ctx->parser.Tokens, lex_dont_skip_formatting)) +# define eat( Type_ ) lex__eat( & _ctx->parser.Tokens, Type_ ) +# define left ( array_num(_ctx->parser.Tokens.Arr) - _ctx->parser.Tokens.Idx ) -#define check_noskip( Type_ ) ( left && currtok_noskip.Type == Type_ ) -#define check( Type_ ) ( left && currtok.Type == Type_ ) +#if GEN_COMPILER_CPP +# define def_assign( ... ) { __VA_ARGS__ } +#else +# define def_assign( ... ) __VA_ARGS__ +#endif -#define push_scope() \ - StackNode scope { nullptr, currtok_noskip, NullToken, txt( __func__ ) }; \ - Context.push( &scope ) + +#ifdef check +#define CHECK_WAS_DEFINED +#pragma push_macro("check") +#undef check +#endif + +# define check_noskip( Type_ ) ( left && currtok_noskip.Type == Type_ ) +# define check( Type_ ) ( left && currtok.Type == Type_ ) + +# define push_scope() \ + Str null_name = {}; \ + StackNode scope = { nullptr, lex_current( & _ctx->parser.Tokens, lex_dont_skip_formatting ), null_name, txt( __func__ ) }; \ + parser_push( & _ctx->parser, & scope ) #pragma endregion Helper Macros // Procedure Forwards ( Entire parser internal parser interface ) -internal Code parse_array_decl(); -internal CodeAttributes parse_attributes(); -internal CodeComment parse_comment(); -internal Code parse_compilcated_definition(); -internal CodeBody parse_class_struct_body( Parser::TokType which, Parser::Token name = Parser::NullToken ); -internal Code parse_class_struct( Parser::TokType which, bool inplace_def ); -internal CodeDefine parse_define(); -internal Code parse_foward_or_definition( Parser::TokType which, bool is_inplace ); -internal CodeFn parse_function_after_name( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType ret_type, Parser::Token name ); -internal Code parse_function_body(); -internal Code parse_global_nspace(); -internal Parser::Token parse_identifier( bool* possible_member_function = nullptr ); -internal CodeInclude parse_include(); -internal CodeOperator parse_operator_after_ret_type( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType ret_type ); +internal Code parse_array_decl (); +internal CodeAttributes parse_attributes (); +internal CodeComment parse_comment (); +internal Code parse_complicated_definition ( TokType which ); +internal CodeBody parse_class_struct_body ( TokType which, Token name ); +internal Code parse_class_struct ( TokType which, bool inplace_def ); +internal CodeDefine parse_define (); +internal Code parse_expression (); +internal Code parse_forward_or_definition ( TokType which, bool is_inplace ); +internal CodeFn parse_function_after_name ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeTypename ret_type, Token name ); +internal Code parse_function_body (); +internal CodeBody parse_global_nspace ( CodeType which ); +internal Code parse_global_nspace_constructor_destructor( CodeSpecifiers specifiers ); +internal Token parse_identifier ( bool* possible_member_function ); +internal CodeInclude parse_include (); +internal CodeOperator parse_operator_after_ret_type ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeTypename ret_type ); internal Code parse_operator_function_or_variable( bool expects_function, CodeAttributes attributes, CodeSpecifiers specifiers ); -internal CodePragma parse_pragma(); -internal CodeParam parse_params( bool use_template_capture = false ); -internal CodePreprocessCond parse_preprocess_cond(); -internal Code parse_simple_preprocess( Parser::TokType which ); -internal Code parse_static_assert(); -internal void parse_template_args( Parser::Token& token ); -internal CodeVar parse_variable_after_name( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType type, StrC name ); +internal CodePragma parse_pragma (); +internal CodeParams parse_params ( bool use_template_capture ); +internal CodePreprocessCond parse_preprocess_cond (); +internal Code parse_simple_preprocess ( TokType which, bool dont_consume_braces ); +internal Code parse_static_assert (); +internal void parse_template_args ( Token* token ); +internal CodeVar parse_variable_after_name ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeTypename type, Str name ); +internal CodeVar parse_variable_declaration_list (); -internal CodeClass parse_class( bool inplace_def = false ); -internal CodeConstructor parse_constructor(); -internal CodeDestructor parse_destructor( CodeSpecifiers specifiers = NoCode ); -internal CodeEnum parse_enum( bool inplace_def = false ); -internal CodeBody parse_export_body(); -internal CodeBody parse_extern_link_body(); -internal CodeExtern parse_exten_link(); -internal CodeFriend parse_friend(); -internal CodeFn parse_function(); -internal CodeNS parse_namespace(); -internal CodeOpCast parse_operator_cast( CodeSpecifiers specifiers = NoCode ); -internal CodeStruct parse_struct( bool inplace_def = false ); -internal CodeVar parse_variable(); -internal CodeTemplate parse_template(); -internal CodeType parse_type( bool* is_function = nullptr ); -internal CodeTypedef parse_typedef(); -internal CodeUnion parse_union( bool inplace_def = false ); -internal CodeUsing parse_using(); +internal CodeClass parser_parse_class ( bool inplace_def ); +internal CodeConstructor parser_parse_constructor ( CodeSpecifiers specifiers ); +internal CodeDestructor parser_parse_destructor ( CodeSpecifiers specifiers ); +internal CodeEnum parser_parse_enum ( bool inplace_def ); +internal CodeBody parser_parse_export_body (); +internal CodeBody parser_parse_extern_link_body(); +internal CodeExtern parser_parse_extern_link (); +internal CodeFriend parser_parse_friend (); +internal CodeFn parser_parse_function (); +internal CodeNS parser_parse_namespace (); +internal CodeOpCast parser_parse_operator_cast ( CodeSpecifiers specifiers ); +internal CodeStruct parser_parse_struct ( bool inplace_def ); +internal CodeVar parser_parse_variable (); +internal CodeTemplate parser_parse_template (); +internal CodeTypename parser_parse_type ( bool from_template, bool* is_function ); +internal CodeTypedef parser_parse_typedef (); +internal CodeUnion parser_parse_union ( bool inplace_def ); +internal CodeUsing parser_parse_using (); -constexpr bool inplace_def = true; +constexpr bool parser_inplace_def = true; +constexpr bool parser_not_inplace_def = false; +constexpr bool parser_dont_consume_braces = true; +constexpr bool parser_consume_braces = false; +constexpr bool parser_not_from_template = false; + +constexpr bool parser_use_parenthesis = false; // Internal parsing functions -constexpr bool strip_formatting_dont_preserve_newlines = false; - +constexpr bool parser_strip_formatting_dont_preserve_newlines = false; /* - This function was an attempt at stripping formatting from any c++ code. - It has edge case failures that prevent it from being used in function bodies. + This function was an attempt at stripping formatting from any c++ code. + It has edge case failures that prevent it from being used in function bodies. */ -String strip_formatting( StrC raw_text, bool preserve_newlines = true ) +internal +StrBuilder parser_strip_formatting( Str raw_text, bool preserve_newlines ) { - String content = String::make_reserve( GlobalAllocator, raw_text.Len ); + StrBuilder content = strbuilder_make_reserve( _ctx->Allocator_Temp, raw_text.Len ); if ( raw_text.Len == 0 ) return content; #define cut_length ( scanner - raw_text.Ptr - last_cut ) -#define cut_ptr ( raw_text.Ptr + last_cut ) -#define pos ( sptr( scanner ) - sptr( raw_text.Ptr ) ) -#define move_fwd() \ - do \ - { \ - scanner++; \ - tokleft--; \ - } while ( 0 ) +#define cut_ptr ( raw_text.Ptr + last_cut ) +#define pos ( rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ) ) +#define move_fwd() do { scanner++; tokleft--; } while(0) s32 tokleft = raw_text.Len; sptr last_cut = 0; char const* scanner = raw_text.Ptr; - if ( scanner[ 0 ] == ' ' ) + if ( scanner[0] == ' ' ) { move_fwd(); last_cut = 1; @@ -18915,13 +20153,13 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) while ( tokleft ) { // Skip over the content of string literals - if ( scanner[ 0 ] == '"' ) + if ( scanner[0] == '"' ) { move_fwd(); - while ( tokleft && ( scanner[ 0 ] != '"' || *( scanner - 1 ) == '\\' ) ) + while ( tokleft && ( scanner[0] != '"' || *( scanner - 1 ) == '\\' ) ) { - if ( scanner[ 0 ] == '\\' && tokleft > 1 ) + if ( scanner[0] == '\\' && tokleft > 1 ) { scanner += 2; tokleft -= 2; @@ -18936,17 +20174,20 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) if ( tokleft ) move_fwd(); - content.append( cut_ptr, cut_length ); - last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); + strbuilder_append_c_str_len( & content, cut_ptr, cut_length ); + last_cut = rcast(sptr, scanner ) - rcast( sptr, raw_text.Ptr ); continue; } // Skip over the content of character literals - if ( scanner[ 0 ] == '\'' ) + if ( scanner[0] == '\'' ) { move_fwd(); - while ( tokleft && ( scanner[ 0 ] != '\'' || ( *( scanner - 1 ) == '\\' ) ) ) + while ( tokleft + && ( scanner[0] != '\'' + || ( *(scanner -1 ) == '\\' ) + ) ) { move_fwd(); } @@ -18955,87 +20196,87 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) if ( tokleft ) move_fwd(); - content.append( cut_ptr, cut_length ); - last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); + strbuilder_append_c_str_len( & content, cut_ptr, cut_length ); + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); continue; } // Block comments - if ( tokleft > 1 && scanner[ 0 ] == '/' && scanner[ 1 ] == '*' ) + if ( tokleft > 1 && scanner[0] == '/' && scanner[1] == '*' ) { - while ( tokleft > 1 && ! ( scanner[ 0 ] == '*' && scanner[ 1 ] == '/' ) ) + while ( tokleft > 1 && !(scanner[0] == '*' && scanner[1] == '/') ) move_fwd(); scanner += 2; tokleft -= 2; - content.append( cut_ptr, cut_length ); - last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); + strbuilder_append_c_str_len( & content, cut_ptr, cut_length ); + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); continue; } // Line comments - if ( tokleft > 1 && scanner[ 0 ] == '/' && scanner[ 1 ] == '/' ) + if ( tokleft > 1 && scanner[0] == '/' && scanner[1] == '/' ) { - must_keep_newline = true; + must_keep_newline = true; - scanner += 2; - tokleft -= 2; + scanner += 2; + tokleft -= 2; while ( tokleft && scanner[ 0 ] != '\n' ) move_fwd(); - if ( tokleft ) + if (tokleft) move_fwd(); - content.append( cut_ptr, cut_length ); - last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); + strbuilder_append_c_str_len( & content, cut_ptr, cut_length ); + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); continue; } // Tabs - if ( scanner[ 0 ] == '\t' ) + if (scanner[0] == '\t') { - if ( pos > last_cut ) - content.append( cut_ptr, cut_length ); + if (pos > last_cut) + strbuilder_append_c_str_len( & content, cut_ptr, cut_length); - if ( content.back() != ' ' ) - content.append( ' ' ); + if ( * strbuilder_back( content ) != ' ' ) + strbuilder_append_char( & content, ' ' ); move_fwd(); - last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); + last_cut = rcast( sptr, scanner) - rcast( sptr, raw_text.Ptr); continue; } - if ( tokleft > 1 && scanner[ 0 ] == '\r' && scanner[ 1 ] == '\n' ) + if ( tokleft > 1 && scanner[0] == '\r' && scanner[1] == '\n' ) { if ( must_keep_newline || preserve_newlines ) { - must_keep_newline = false; + must_keep_newline = false; - scanner += 2; - tokleft -= 2; + scanner += 2; + tokleft -= 2; - content.append( cut_ptr, cut_length ); - last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); + strbuilder_append_c_str_len( & content, cut_ptr, cut_length ); + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); continue; } if ( pos > last_cut ) - content.append( cut_ptr, cut_length ); + strbuilder_append_c_str_len( & content, cut_ptr, cut_length ); // Replace with a space - if ( content.back() != ' ' ) - content.append( ' ' ); + if ( * strbuilder_back( content ) != ' ' ) + strbuilder_append_char( & content, ' ' ); - scanner += 2; - tokleft -= 2; + scanner += 2; + tokleft -= 2; - last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); continue; } - if ( scanner[ 0 ] == '\n' ) + if ( scanner[0] == '\n' ) { if ( must_keep_newline || preserve_newlines ) { @@ -19043,35 +20284,35 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) move_fwd(); - content.append( cut_ptr, cut_length ); - last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); + strbuilder_append_c_str_len( & content, cut_ptr, cut_length ); + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); continue; } if ( pos > last_cut ) - content.append( cut_ptr, cut_length ); + strbuilder_append_c_str_len( & content, cut_ptr, cut_length ); // Replace with a space - if ( content.back() != ' ' ) - content.append( ' ' ); + if ( * strbuilder_back( content ) != ' ' ) + strbuilder_append_char( & content, ' ' ); move_fwd(); - last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); continue; } // Escaped newlines - if ( scanner[ 0 ] == '\\' ) + if ( scanner[0] == '\\' ) { - content.append( cut_ptr, cut_length ); + strbuilder_append_c_str_len( & content, cut_ptr, cut_length ); s32 amount_to_skip = 1; - if ( tokleft > 1 && scanner[ 1 ] == '\n' ) + if ( tokleft > 1 && scanner[1] == '\n' ) { amount_to_skip = 2; } - else if ( tokleft > 2 && scanner[ 1 ] == '\r' && scanner[ 2 ] == '\n' ) + else if ( tokleft > 2 && scanner[1] == '\r' && scanner[2] == '\n' ) { amount_to_skip = 3; } @@ -19084,24 +20325,26 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) else move_fwd(); - last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); continue; } // Consectuive spaces - if ( tokleft > 1 && char_is_space( scanner[ 0 ] ) && char_is_space( scanner[ 1 ] ) ) + if ( tokleft > 1 && char_is_space( scanner[0] ) && char_is_space( scanner[ 1 ] ) ) { - content.append( cut_ptr, cut_length ); + strbuilder_append_c_str_len( & content, cut_ptr, cut_length ); do { move_fwd(); - } while ( tokleft && char_is_space( scanner[ 0 ] ) ); + } + while ( tokleft && char_is_space( scanner[0] ) ); - last_cut = sptr( scanner ) - sptr( raw_text.Ptr ); + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); // Preserve only 1 space of formattting - if ( content.back() != ' ' ) - content.append( ' ' ); + char* last = strbuilder_back(content); + if ( last == nullptr || * last != ' ' ) + strbuilder_append_char( & content, ' ' ); continue; } @@ -19111,7 +20354,7 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) if ( last_cut < raw_text.Len ) { - content.append( cut_ptr, raw_text.Len - last_cut ); + strbuilder_append_c_str_len( & content, cut_ptr, raw_text.Len - last_cut ); } #undef cut_ptr @@ -19122,231 +20365,782 @@ String strip_formatting( StrC raw_text, bool preserve_newlines = true ) return content; } -internal Code parse_array_decl() +internal +Code parse_array_decl() { - using namespace Parser; push_scope(); - if ( check( TokType::Operator ) && currtok.Text[ 0 ] == '[' && currtok.Text[ 1 ] == ']' ) + if ( check( Tok_Operator ) && currtok.Text.Ptr[0] == '[' && currtok.Text.Ptr[1] == ']' ) { - Code array_expr = untyped_str( currtok ); - eat( TokType::Operator ); + Code array_expr = untyped_str( txt(" ") ); + eat( Tok_Operator ); + // [] - Context.pop(); + parser_pop(& _ctx->parser); return array_expr; } - if ( check( TokType::BraceSquare_Open ) ) + if ( check( Tok_BraceSquare_Open ) ) { - eat( TokType::BraceSquare_Open ); + eat( Tok_BraceSquare_Open ); + // [ if ( left == 0 ) { - log_failure( "Error, unexpected end of array declaration ( '[]' scope started )\n%s", Context.to_string() ); - Context.pop(); - return CodeInvalid; + log_failure( "Error, unexpected end of array declaration ( '[]' scope started )\n%s", parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; } - if ( currtok.Type == TokType::BraceSquare_Close ) + if ( currtok.Type == Tok_BraceSquare_Close ) { - log_failure( "Error, empty array expression in definition\n%s", Context.to_string() ); - Context.pop(); - return CodeInvalid; + log_failure( "Error, empty array expression in definition\n%s", parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; } Token untyped_tok = currtok; - while ( left && currtok.Type != TokType::BraceSquare_Close ) + while ( left && currtok.Type != Tok_BraceSquare_Close ) { eat( currtok.Type ); } - untyped_tok.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )untyped_tok.Text; + untyped_tok.Text.Len = ( (sptr)prevtok.Text.Ptr + prevtok.Text.Len ) - (sptr)untyped_tok.Text.Ptr; - Code array_expr = untyped_str( untyped_tok ); + Code array_expr = untyped_str( tok_to_str(untyped_tok) ); + // [ if ( left == 0 ) { - log_failure( "Error, unexpected end of array declaration, expected ]\n%s", Context.to_string() ); - Context.pop(); - return CodeInvalid; + log_failure( "Error, unexpected end of array declaration, expected ]\n%s", parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; } - if ( currtok.Type != TokType::BraceSquare_Close ) + if ( currtok.Type != Tok_BraceSquare_Close ) { - log_failure( "%s: Error, expected ] in array declaration, not %s\n%s", ETokType::to_str( currtok.Type ), Context.to_string() ); - Context.pop(); - return CodeInvalid; + log_failure( "%s: Error, expected ] in array declaration, not %s\n%s", toktype_to_str( currtok.Type ), parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; } - eat( TokType::BraceSquare_Close ); + eat( Tok_BraceSquare_Close ); + // [ ] // Its a multi-dimensional array - if ( check( TokType::BraceSquare_Open ) ) + if ( check( Tok_BraceSquare_Open )) { Code adjacent_arr_expr = parse_array_decl(); + // [ ][ ]... - array_expr->Next = adjacent_arr_expr.ast; + array_expr->Next = adjacent_arr_expr; } - Context.pop(); + parser_pop(& _ctx->parser); return array_expr; } - Context.pop(); - return { nullptr }; + parser_pop(& _ctx->parser); + return NullCode; } -internal inline CodeAttributes parse_attributes() +internal inline +CodeAttributes parse_attributes() { - using namespace Parser; push_scope(); - Token start = NullToken; + Token start = currtok; s32 len = 0; - if ( check( TokType::Attribute_Open ) ) + // There can be more than one attribute. If there is flatten them to a single string. + // TODO(Ed): Support keeping an linked list of attributes similar to parameters + while ( left && tok_is_attribute(currtok) ) { - eat( TokType::Attribute_Open ); + if ( check( Tok_Attribute_Open ) ) + { + eat( Tok_Attribute_Open ); + // [[ - start = currtok; - while ( left && currtok.Type != TokType::Attribute_Close ) + while ( left && currtok.Type != Tok_Attribute_Close ) + { + eat( currtok.Type ); + } + // [[ + + eat( Tok_Attribute_Close ); + // [[ ]] + + len = ( ( sptr )prevtok.Text.Ptr + prevtok.Text.Len ) - ( sptr )start.Text.Ptr; + } + else if ( check( Tok_Decl_GNU_Attribute ) ) + { + eat( Tok_Decl_GNU_Attribute ); + eat( Tok_Capture_Start ); + eat( Tok_Capture_Start ); + // __attribute__(( + + while ( left && currtok.Type != Tok_Capture_End ) + { + eat( currtok.Type ); + } + // __attribute__(( + + eat( Tok_Capture_End ); + eat( Tok_Capture_End ); + // __attribute__(( )) + + len = ( ( sptr )prevtok.Text.Ptr + prevtok.Text.Len ) - ( sptr )start.Text.Ptr; + } + else if ( check( Tok_Decl_MSVC_Attribute ) ) + { + eat( Tok_Decl_MSVC_Attribute ); + eat( Tok_Capture_Start ); + // __declspec( + + while ( left && currtok.Type != Tok_Capture_End ) + { + eat( currtok.Type ); + } + // __declspec( + + eat( Tok_Capture_End ); + // __declspec( ) + + len = ( ( sptr )prevtok.Text.Ptr + prevtok.Text.Len ) - ( sptr )start.Text.Ptr; + } + else if ( tok_is_attribute(currtok) ) { eat( currtok.Type ); + // + + // If its a macro based attribute, this could be a functional macro such as Unreal's UE_DEPRECATED(...) + if ( check( Tok_Capture_Start)) + { + eat( Tok_Capture_Start ); + + s32 level = 0; + while (left && currtok.Type != Tok_Capture_End && level == 0) + { + if (currtok.Type == Tok_Capture_Start) + ++ level; + if (currtok.Type == Tok_Capture_End) + --level; + eat(currtok.Type); + } + eat(Tok_Capture_End); + } + + len = ( ( sptr )prevtok.Text.Ptr + prevtok.Text.Len ) - ( sptr )start.Text.Ptr; + // ( ... ) } - - eat( TokType::Attribute_Close ); - - s32 len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; - } - - else if ( check( TokType::Decl_GNU_Attribute ) ) - { - eat( TokType::Capture_Start ); - eat( TokType::Capture_Start ); - - start = currtok; - while ( left && currtok.Type != TokType::Capture_End ) - { - eat( currtok.Type ); - } - - eat( TokType::Capture_End ); - eat( TokType::Capture_End ); - - s32 len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; - } - - else if ( check( TokType::Decl_MSVC_Attribute ) ) - { - eat( TokType::Decl_MSVC_Attribute ); - eat( TokType::Capture_Start ); - - start = currtok; - while ( left && currtok.Type != TokType::Capture_End ) - { - eat( currtok.Type ); - } - - eat( TokType::Capture_End ); - - s32 len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; - } - - else if ( currtok.is_attribute() ) - { - eat( currtok.Type ); - s32 len = start.Length; } if ( len > 0 ) { - StrC attribute_txt = { len, start.Text }; - Context.pop(); + Str attribute_txt = { start.Text.Ptr, len }; + parser_pop(& _ctx->parser); - String name_stripped = strip_formatting( attribute_txt, strip_formatting_dont_preserve_newlines ); + StrBuilder name_stripped = parser_strip_formatting( attribute_txt, parser_strip_formatting_dont_preserve_newlines ); - Code result = make_code(); - result->Type = ECode::PlatformAttributes; - result->Name = get_cached_string( name_stripped ); - result->Content = result->Name; + Code result = make_code(); + result->Type = CT_PlatformAttributes; + result->Name = cache_str( strbuilder_to_str(name_stripped) ); + result->Content = result->Name; // result->Token = return ( CodeAttributes )result; } - Context.pop(); - return { nullptr }; + parser_pop(& _ctx->parser); + return NullCode; } -internal CodeComment parse_comment() +internal +Code parse_class_struct( TokType which, bool inplace_def ) { - using namespace Parser; - StackNode scope { nullptr, currtok_noskip, NullToken, txt( __func__ ) }; - Context.push( &scope ); + if ( which != Tok_Decl_Class && which != Tok_Decl_Struct ) + { + log_failure( "Error, expected class or struct, not %s\n%s", toktype_to_str( which ), parser_to_strbuilder(_ctx->parser) ); + return InvalidCode; + } - CodeComment result = ( CodeComment )make_code(); - result->Type = ECode::Comment; - result->Content = get_cached_string( currtok_noskip ); - result->Name = result->Content; - // result->Token = currtok_noskip; - eat( TokType::Comment ); + Token name = NullToken; - Context.pop(); + AccessSpec access = AccessSpec_Default; + CodeTypename parent = { nullptr }; + CodeBody body = { nullptr }; + CodeAttributes attributes = { nullptr }; + ModuleFlag mflags = ModuleFlag_None; + + Code result = InvalidCode; + + if ( check(Tok_Module_Export) ) + { + mflags = ModuleFlag_Export; + eat( Tok_Module_Export ); + } + // + + eat( which ); + // + + attributes = parse_attributes(); + // + + if ( check( Tok_Identifier ) ) + { + name = parse_identifier(nullptr); + _ctx->parser.Scope->Name = name.Text; + } + // + + local_persist + char interface_arr_mem[ kilobytes(4) ] = {0}; + Array(CodeTypename) interfaces; { + Arena arena = arena_init_from_memory( interface_arr_mem, kilobytes(4) ); + interfaces = array_init_reserve(CodeTypename, arena_allocator_info(& arena), 4 ); + } + + // TODO(Ed) : Make an AST_DerivedType, we'll store any arbitary derived type into there as a linear linked list of them. + if ( check( Tok_Assign_Classifer ) ) + { + eat( Tok_Assign_Classifer ); + // : + + if ( tok_is_access_specifier(currtok) ) + { + access = tok_to_access_specifier(currtok); + // : + eat( currtok.Type ); + } + + Token parent_tok = parse_identifier(nullptr); + parent = def_type( tok_to_str(parent_tok) ); + // : + + while ( check(Tok_Comma) ) + { + eat( Tok_Comma ); + // : , + + if ( tok_is_access_specifier(currtok) ) + { + eat(currtok.Type); + } + Token interface_tok = parse_identifier(nullptr); + + array_append( interfaces, def_type( tok_to_str(interface_tok) ) ); + // : , ... + } + } + + if ( check( Tok_BraceCurly_Open ) ) + { + body = parse_class_struct_body( which, name ); + } + // : , ... { } + + CodeComment inline_cmt = NullCode; + if ( ! inplace_def ) + { + Token stmt_end = currtok; + eat( Tok_Statement_End ); + // : , ... { }; + + if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line ) + inline_cmt = parse_comment(); + // : , ... { }; + } + + if ( which == Tok_Decl_Class ) + result = cast(Code, def_class( tok_to_str(name), def_assign( body, parent, access, attributes, interfaces, scast(s32, array_num(interfaces)), mflags ) )); + + else + result = cast(Code, def_struct( tok_to_str(name), def_assign( body, (CodeTypename)parent, access, attributes, interfaces, scast(s32, array_num(interfaces)), mflags ) )); + + if ( inline_cmt ) + result->InlineCmt = cast(Code, inline_cmt); + + array_free(interfaces); return result; } -internal Code parse_complicated_definition( Parser::TokType which ) +internal neverinline +CodeBody parse_class_struct_body( TokType which, Token name ) +{ + push_scope(); + + eat( Tok_BraceCurly_Open ); + // { + + CodeBody + result = (CodeBody) make_code(); + + if ( which == Tok_Decl_Class ) + result->Type = CT_Class_Body; + + else + result->Type = CT_Struct_Body; + + while ( left && currtok_noskip.Type != Tok_BraceCurly_Close ) + { + Code member = Code_Invalid; + CodeAttributes attributes = { nullptr }; + CodeSpecifiers specifiers = { nullptr }; + + bool expects_function = false; + + // _ctx->parser.Scope->Start = currtok_noskip; + + if ( currtok_noskip.Type == Tok_Preprocess_Hash ) + eat( Tok_Preprocess_Hash ); + + b32 macro_found = true; + + switch ( currtok_noskip.Type ) + { + case Tok_Statement_End: + { + // TODO(Ed): Convert this to a general warning procedure + log_fmt("Dangling end statement found %SB\n", tok_to_strbuilder(currtok_noskip)); + eat( Tok_Statement_End ); + continue; + } + case Tok_NewLine: + member = fmt_newline; + eat( Tok_NewLine ); + break; + + case Tok_Comment: + member = cast(Code, parse_comment()); + break; + + case Tok_Access_Public: + member = access_public; + eat( Tok_Access_Public ); + eat( Tok_Assign_Classifer ); + // public: + break; + + case Tok_Access_Protected: + member = access_protected; + eat( Tok_Access_Protected ); + eat( Tok_Assign_Classifer ); + // protected: + break; + + case Tok_Access_Private: + member = access_private; + eat( Tok_Access_Private ); + eat( Tok_Assign_Classifer ); + // private: + break; + + case Tok_Decl_Class: + member = parse_complicated_definition( Tok_Decl_Class ); + // class + break; + + case Tok_Decl_Enum: + member = parse_complicated_definition( Tok_Decl_Enum ); + // enum + break; + + case Tok_Decl_Friend: + member = cast(Code, parser_parse_friend()); + // friend + break; + + case Tok_Decl_Operator: + member = cast(Code, parser_parse_operator_cast(NullCode)); + // operator () + break; + + case Tok_Decl_Struct: + member = parse_complicated_definition( Tok_Decl_Struct ); + // struct + break; + + case Tok_Decl_Template: + member = cast(Code, parser_parse_template()); + // template< ... > + break; + + case Tok_Decl_Typedef: + member = cast(Code, parser_parse_typedef()); + // typedef + break; + + case Tok_Decl_Union: + member = parse_complicated_definition( Tok_Decl_Union ); + // union + break; + + case Tok_Decl_Using: + member = cast(Code, parser_parse_using()); + // using + break; + + case Tok_Operator: + //if ( currtok.Text[0] != '~' ) + //{ + // log_failure( "Operator token found in global body but not destructor unary negation\n%s", to_strbuilder(_ctx->parser) ); + // return InvalidCode; + //} + + member = cast(Code, parser_parse_destructor(NullCode)); + // ~() + break; + + case Tok_Preprocess_Define: + member = cast(Code, parse_define()); + // #define + break; + + case Tok_Preprocess_Include: + member = cast(Code, parse_include()); + // #include + break; + + case Tok_Preprocess_If: + case Tok_Preprocess_IfDef: + case Tok_Preprocess_IfNotDef: + case Tok_Preprocess_ElIf: + member = cast(Code, parse_preprocess_cond()); + // # + break; + + case Tok_Preprocess_Else: + member = cast(Code, preprocess_else); + eat( Tok_Preprocess_Else ); + // #else + break; + + case Tok_Preprocess_EndIf: + member = cast(Code, preprocess_endif); + eat( Tok_Preprocess_EndIf ); + // #endif + break; + + case Tok_Preprocess_Macro: + // + macro_found = true; + goto Preprocess_Macro_Bare_In_Body; + break; + + case Tok_Preprocess_Pragma: + member = cast(Code, parse_pragma()); + // #pragma + break; + + case Tok_Preprocess_Unsupported: + member = cast(Code, parse_simple_preprocess( Tok_Preprocess_Unsupported, parser_consume_braces )); + // # + break; + + case Tok_StaticAssert: + member = parse_static_assert(); + // static_assert + break; + + case Tok_Attribute_Open: + case Tok_Decl_GNU_Attribute: + case Tok_Decl_MSVC_Attribute: + #define Entry( attribute, str ) case attribute: + GEN_DEFINE_ATTRIBUTE_TOKENS + #undef Entry + { + attributes = parse_attributes(); + // + } + //! Fallthrough intended + case Tok_Spec_Consteval: + case Tok_Spec_Constexpr: + case Tok_Spec_Constinit: + case Tok_Spec_Explicit: + case Tok_Spec_ForceInline: + case Tok_Spec_Inline: + case Tok_Spec_Mutable: + case Tok_Spec_NeverInline: + case Tok_Spec_Static: + case Tok_Spec_Volatile: + case Tok_Spec_Virtual: + { + Specifier specs_found[16] = { Spec_NumSpecifiers }; + s32 NumSpecifiers = 0; + + while ( left && tok_is_specifier(currtok) ) + { + Specifier spec = str_to_specifier( tok_to_str(currtok) ); + + b32 ignore_spec = false; + + switch ( spec ) + { + case Spec_Constexpr: + case Spec_Constinit: + case Spec_Explicit: + case Spec_Inline: + case Spec_ForceInline: + case Spec_Mutable: + case Spec_NeverInline: + case Spec_Static: + case Spec_Volatile: + case Spec_Virtual: + break; + + case Spec_Consteval: + expects_function = true; + break; + + case Spec_Const : + ignore_spec = true; + break; + + default: + log_failure( "Invalid specifier %S for variable\n%S", spec_to_str(spec), strbuilder_to_str( parser_to_strbuilder(_ctx->parser)) ); + parser_pop(& _ctx->parser); + return InvalidCode; + } + + // Every specifier after would be considered part of the type type signature + if (ignore_spec) + break; + + specs_found[NumSpecifiers] = spec; + NumSpecifiers++; + eat( currtok.Type ); + } + + if ( NumSpecifiers ) + { + specifiers = def_specifiers( NumSpecifiers, specs_found ); + } + // + + if ( tok_is_attribute(currtok) ) + { + // Unfortuantely Unreal has code where there is attirbutes before specifiers + CodeAttributes more_attributes = parse_attributes(); + + if ( attributes ) + { + StrBuilder fused = strbuilder_make_reserve( _ctx->Allocator_Temp, attributes->Content.Len + more_attributes->Content.Len ); + strbuilder_append_fmt( & fused, "%SB %SB", attributes->Content, more_attributes->Content ); + + Str attrib_name = strbuilder_to_str(fused); + attributes->Name = cache_str( attrib_name ); + attributes->Content = attributes->Name; + // + } + + attributes = more_attributes; + } + + if ( currtok.Type == Tok_Operator && currtok.Text.Ptr[0] == '~' ) + { + member = cast(Code, parser_parse_destructor( specifiers )); + // ~() + break; + } + + if ( currtok.Type == Tok_Decl_Operator ) + { + member = cast(Code, parser_parse_operator_cast( specifiers )); + // operator () + break; + } + } + //! Fallthrough intentional + case Tok_Identifier: + case Tok_Spec_Const: + case Tok_Type_Unsigned: + case Tok_Type_Signed: + case Tok_Type_Short: + case Tok_Type_Long: + case Tok_Type_bool: + case Tok_Type_char: + case Tok_Type_int: + case Tok_Type_double: + { + if ( nexttok.Type == Tok_Capture_Start && name.Text.Len && currtok.Type == Tok_Identifier ) + { + if ( c_str_compare_len( name.Text.Ptr, currtok.Text.Ptr, name.Text.Len ) == 0 ) + { + member = cast(Code, parser_parse_constructor( specifiers )); + // () + break; + } + } + + if (macro_found) + { + Preprocess_Macro_Bare_In_Body: + b32 lone_macro = nexttok.Type == Tok_Statement_End || nexttok_noskip.Type == Tok_NewLine; + if (lone_macro) + { + member = cast(Code, parse_simple_preprocess( Tok_Preprocess_Macro, parser_consume_braces )); + // ; + + if ( member == Code_Invalid ) + { + log_failure( "Failed to parse member\n%s", parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; + } + continue; + } + + // We have a macro but its most likely behaving as a typename + // operator ... + // or + // ... + } + break; + + default: + Token untyped_tok = currtok; + + while ( left && currtok.Type != Tok_BraceCurly_Close ) + { + untyped_tok.Text.Len = ( (sptr)currtok.Text.Ptr + currtok.Text.Len ) - (sptr)untyped_tok.Text.Ptr; + eat( currtok.Type ); + } + + member = untyped_str( tok_to_str(untyped_tok) ); + // Something unknown + break; + } + + if ( member == Code_Invalid ) + { + log_failure( "Failed to parse member\n%s", parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; + } + + body_append(result, member ); + } + + eat( Tok_BraceCurly_Close ); + // { } + parser_pop(& _ctx->parser); + return result; +} + +internal +CodeComment parse_comment() +{ + push_scope(); + + CodeComment + result = (CodeComment) make_code(); + result->Type = CT_Comment; + result->Content = cache_str( tok_to_str(currtok_noskip) ); + // result->Token = currtok_noskip; + eat( Tok_Comment ); + + parser_pop(& _ctx->parser); + return result; +} + +internal +Code parse_complicated_definition( TokType which ) { - using namespace Parser; push_scope(); bool is_inplace = false; - TokArray tokens = Context.Tokens; + TokArray tokens = _ctx->parser.Tokens; s32 idx = tokens.Idx; s32 level = 0; - for ( ; idx < tokens.Arr.num(); idx++ ) + for ( ; idx < array_num(tokens.Arr); idx++ ) { - if ( tokens[ idx ].Type == TokType::BraceCurly_Open ) + if ( tokens.Arr[ idx ].Type == Tok_BraceCurly_Open ) level++; - if ( tokens[ idx ].Type == TokType::BraceCurly_Close ) + if ( tokens.Arr[ idx ].Type == Tok_BraceCurly_Close ) level--; - if ( level == 0 && tokens[ idx ].Type == TokType::Statement_End ) + if ( level == 0 && tokens.Arr[ idx ].Type == Tok_Statement_End ) break; } if ( ( idx - 2 ) == tokens.Idx ) { // Its a forward declaration only - return parse_foward_or_definition( which, is_inplace ); + Code result = parse_forward_or_definition( which, is_inplace ); + // ; + parser_pop(& _ctx->parser); + return result; } - Token tok = tokens[ idx - 1 ]; - if ( tok.Type == TokType::Identifier ) + Token tok = tokens.Arr[ idx - 1 ]; + if ( tok_is_specifier(tok) && spec_is_trailing( str_to_specifier( tok_to_str(tok))) ) { - tok = tokens[ idx - 2 ]; + // (...) ...; - bool is_indirection = tok.Type == TokType::Ampersand || tok.Type == TokType::Star; + s32 spec_idx = idx - 1; + Token spec = tokens.Arr[spec_idx]; + while ( tok_is_specifier(spec) && spec_is_trailing( str_to_specifier( tok_to_str(spec))) ) + { + -- spec_idx; + spec = tokens.Arr[spec_idx]; + } + if ( tokens.Arr[spec_idx].Type == Tok_Capture_End ) + { + // Forward declaration with trailing specifiers for a procedure + tok = tokens.Arr[spec_idx]; + + Code result = parse_operator_function_or_variable( false, NullCode, NullCode ); + // , or Name> ... + parser_pop(& _ctx->parser); + return result; + } + + log_failure( "Unsupported or bad member definition after %s declaration\n%s", toktype_to_str(which), parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; + } + if ( tok.Type == Tok_Identifier ) + { + tok = tokens.Arr[ idx - 2 ]; + bool is_indirection = tok.Type == Tok_Ampersand || tok.Type == Tok_Star; bool ok_to_parse = false; - if ( tok.Type == TokType::BraceCurly_Close ) + if ( tok.Type == Tok_BraceCurly_Close ) { // Its an inplace definition // { ... } ; ok_to_parse = true; is_inplace = true; } - else if ( tok.Type == TokType::Identifier && tokens[ idx - 3 ].Type == TokType::Decl_Struct ) + else if ( tok.Type == Tok_Identifier && tokens.Arr[ idx - 3 ].Type == which ) { - // Its a variable with type ID using struct namespace. + // Its a variable with type ID using namespace. // ; ok_to_parse = true; } + else if ( tok.Type == Tok_Assign_Classifer + && ( ( tokens.Arr[idx - 5].Type == which && tokens.Arr[idx - 4].Type == Tok_Decl_Class ) + || ( tokens.Arr[idx - 4].Type == which)) + ) + { + // Its a forward declaration of an enum + // : ; + // : ; + ok_to_parse = true; + Code result = cast(Code, parser_parse_enum( ! parser_inplace_def)); + parser_pop(& _ctx->parser); + return result; + } else if ( is_indirection ) { // Its a indirection type with type ID using struct namespace. @@ -19356,563 +21150,281 @@ internal Code parse_complicated_definition( Parser::TokType which ) if ( ! ok_to_parse ) { - log_failure( "Unsupported or bad member definition after struct declaration\n%s", Context.to_string() ); - Context.pop(); - return CodeInvalid; + log_failure( "Unsupported or bad member definition after %s declaration\n%s", toktype_to_str(which), parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; } - Code result = parse_operator_function_or_variable( false, { nullptr }, { nullptr } ); - Context.pop(); + Code result = parse_operator_function_or_variable( false, NullCode, NullCode ); + // , or Name> ... + parser_pop(& _ctx->parser); return result; } - else if ( tok.Type == TokType::BraceCurly_Close ) + else if ( tok.Type >= Tok_Type_Unsigned && tok.Type <= Tok_Type_MS_W64 ) + { + tok = tokens.Arr[ idx - 2 ]; + + if ( tok.Type != Tok_Assign_Classifer + || ( ( tokens.Arr[idx - 5].Type != which && tokens.Arr[idx - 4].Type != Tok_Decl_Class ) + && ( tokens.Arr[idx - 4].Type != which)) + ) + { + log_failure( "Unsupported or bad member definition after %s declaration\n%s", toktype_to_str(which), parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; + } + + // Its a forward declaration of an enum class + // : ; + // : ; + Code result = cast(Code, parser_parse_enum( ! parser_inplace_def)); + parser_pop(& _ctx->parser); + return result; + } + else if ( tok.Type == Tok_BraceCurly_Close ) { // Its a definition + Code result = parse_forward_or_definition( which, is_inplace ); // { ... }; - return parse_foward_or_definition( which, is_inplace ); + parser_pop(& _ctx->parser); + return result; } - else if ( tok.Type == TokType::BraceSquare_Close ) + else if ( tok.Type == Tok_BraceSquare_Close ) { // Its an array definition + Code result = parse_operator_function_or_variable( false, NullCode, NullCode ); // [ ... ]; - Code result = parse_operator_function_or_variable( false, { nullptr }, { nullptr } ); - Context.pop(); + parser_pop(& _ctx->parser); return result; } else { - log_failure( "Unsupported or bad member definition after struct declaration\n%s", Context.to_string() ); - Context.pop(); - return CodeInvalid; + log_failure( "Unsupported or bad member definition after %s declaration\n%SB", toktype_to_str(which).Ptr, parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; } } -internal neverinline CodeBody parse_class_struct_body( Parser::TokType which, Parser::Token name ) +internal inline +CodeDefine parse_define() { - using namespace Parser; - using namespace ECode; push_scope(); + eat( Tok_Preprocess_Define ); + // #define - eat( TokType::BraceCurly_Open ); + CodeDefine + define = (CodeDefine) make_code(); + define->Type = CT_Preprocess_Define; - CodeBody result = ( CodeBody )make_code(); - - if ( which == TokType::Decl_Class ) - result->Type = Class_Body; - - else - result->Type = Struct_Body; - - while ( left && currtok_noskip.Type != TokType::BraceCurly_Close ) + if ( ! check( Tok_Identifier ) ) { - Code member = Code::Invalid; - CodeAttributes attributes = { nullptr }; - CodeSpecifiers specifiers = { nullptr }; - - bool expects_function = false; - - Context.Scope->Start = currtok_noskip; - - if ( currtok_noskip.Type == TokType::Preprocess_Hash ) - eat( TokType::Preprocess_Hash ); - - switch ( currtok_noskip.Type ) - { - case TokType::NewLine : - member = fmt_newline; - eat( TokType::NewLine ); - break; - - case TokType::Comment : - member = parse_comment(); - break; - - case TokType::Access_Public : - member = access_public; - eat( TokType::Access_Public ); - eat( TokType::Assign_Classifer ); - break; - - case TokType::Access_Protected : - member = access_protected; - eat( TokType::Access_Protected ); - eat( TokType::Assign_Classifer ); - break; - - case TokType::Access_Private : - member = access_private; - eat( TokType::Access_Private ); - eat( TokType::Assign_Classifer ); - break; - - case TokType::Decl_Class : - member = parse_complicated_definition( TokType::Decl_Class ); - break; - - case TokType::Decl_Enum : - member = parse_complicated_definition( TokType::Decl_Enum ); - break; - - case TokType::Decl_Friend : - member = parse_friend(); - break; - - case TokType::Decl_Operator : - member = parse_operator_cast(); - break; - - case TokType::Decl_Struct : - member = parse_complicated_definition( TokType::Decl_Struct ); - break; - - case TokType::Decl_Template : - member = parse_template(); - break; - - case TokType::Decl_Typedef : - member = parse_typedef(); - break; - - case TokType::Decl_Union : - member = parse_complicated_definition( TokType::Decl_Union ); - break; - - case TokType::Decl_Using : - member = parse_using(); - break; - - case TokType::Operator : - if ( currtok.Text[ 0 ] != '~' ) - { - log_failure( "Operator token found in global body but not destructor unary negation\n%s", Context.to_string() ); - return CodeInvalid; - } - - member = parse_destructor(); - break; - - case TokType::Preprocess_Define : - member = parse_define(); - break; - - case TokType::Preprocess_Include : - member = parse_include(); - break; - - case TokType::Preprocess_If : - case TokType::Preprocess_IfDef : - case TokType::Preprocess_IfNotDef : - case TokType::Preprocess_ElIf : - member = parse_preprocess_cond(); - break; - - case TokType::Preprocess_Macro : - member = parse_simple_preprocess( TokType::Preprocess_Macro ); - break; - - case TokType::Preprocess_Pragma : - member = parse_pragma(); - break; - - case TokType::Preprocess_Else : - member = preprocess_else; - eat( TokType::Preprocess_Else ); - break; - - case TokType::Preprocess_EndIf : - member = preprocess_endif; - eat( TokType::Preprocess_EndIf ); - break; - - case TokType::Preprocess_Unsupported : - member = parse_simple_preprocess( TokType::Preprocess_Unsupported ); - break; - - case TokType::StaticAssert : - member = parse_static_assert(); - break; - - case TokType::Attribute_Open : - case TokType::Decl_GNU_Attribute : - case TokType::Decl_MSVC_Attribute : -#define Entry( attribute, str ) case TokType::attribute : - GEN_DEFINE_ATTRIBUTE_TOKENS -#undef Entry - { - attributes = parse_attributes(); - } - //! Fallthrough intended - case TokType::Spec_Consteval : - case TokType::Spec_Constexpr : - case TokType::Spec_Constinit : - case TokType::Spec_ForceInline : - case TokType::Spec_Inline : - case TokType::Spec_Mutable : - case TokType::Spec_NeverInline : - case TokType::Spec_Static : - case TokType::Spec_Volatile : - { - SpecifierT specs_found[ 16 ] { ESpecifier::NumSpecifiers }; - s32 NumSpecifiers = 0; - - while ( left && currtok.is_specifier() ) - { - SpecifierT spec = ESpecifier::to_type( currtok ); - - switch ( spec ) - { - case ESpecifier::Constexpr : - case ESpecifier::Constinit : - case ESpecifier::Inline : - case ESpecifier::ForceInline : - case ESpecifier::Mutable : - case ESpecifier::NeverInline : - case ESpecifier::Static : - case ESpecifier::Volatile : - break; - - case ESpecifier::Consteval : - expects_function = true; - break; - - default : - log_failure( "Invalid specifier %s for variable\n%s", ESpecifier::to_str( spec ), Context.to_string() ); - Context.pop(); - return CodeInvalid; - } - - specs_found[ NumSpecifiers ] = spec; - NumSpecifiers++; - eat( currtok.Type ); - } - - if ( NumSpecifiers ) - { - specifiers = def_specifiers( NumSpecifiers, specs_found ); - } - - if ( currtok.Type == TokType::Operator && currtok.Text[ 0 ] == '~' ) - { - member = parse_destructor( specifiers ); - break; - } - - if ( currtok.Type == TokType::Decl_Operator ) - { - member = parse_operator_cast( specifiers ); - break; - } - } - //! Fallthrough intentional - case TokType::Identifier : - case TokType::Spec_Const : - case TokType::Type_Unsigned : - case TokType::Type_Signed : - case TokType::Type_Short : - case TokType::Type_Long : - case TokType::Type_char : - case TokType::Type_int : - case TokType::Type_double : - { - if ( nexttok.Type == TokType::Capture_Start && name.Length && currtok.Type == TokType::Identifier ) - { - if ( str_compare( name.Text, currtok.Text, name.Length ) == 0 ) - { - member = parse_constructor(); - break; - } - } - - member = parse_operator_function_or_variable( expects_function, attributes, specifiers ); - } - break; - - default : - Token untyped_tok = currtok; - - while ( left && currtok.Type != TokType::BraceCurly_Close ) - { - untyped_tok.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )untyped_tok.Text; - eat( currtok.Type ); - } - - member = untyped_str( untyped_tok ); - break; - } - - if ( member == Code::Invalid ) - { - log_failure( "Failed to parse member\n%s", Context.to_string() ); - Context.pop(); - return CodeInvalid; - } - - result.append( member ); + log_failure( "Error, expected identifier after #define\n%s", parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; } - eat( TokType::BraceCurly_Close ); - Context.pop(); - return result; -} + _ctx->parser.Scope->Name = currtok.Text; + define->Name = cache_str( tok_to_str(currtok) ); + eat( Tok_Identifier ); + // #define -internal Code parse_class_struct( Parser::TokType which, bool inplace_def = false ) -{ - using namespace Parser; - - if ( which != TokType::Decl_Class && which != TokType::Decl_Struct ) + if ( ! check( Tok_Preprocess_Content )) { - log_failure( "Error, expected class or struct, not %s\n%s", ETokType::to_str( which ), Context.to_string() ); - return CodeInvalid; + log_failure( "Error, expected content after #define %s\n%s", define->Name, parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; } - Token name { nullptr, 0, TokType::Invalid }; - - AccessSpec access = AccessSpec::Default; - CodeType parent = { nullptr }; - CodeBody body = { nullptr }; - CodeAttributes attributes = { nullptr }; - ModuleFlag mflags = ModuleFlag::None; - - CodeClass result = CodeInvalid; - - if ( check( TokType::Module_Export ) ) + if ( currtok.Text.Len == 0 ) { - mflags = ModuleFlag::Export; - eat( TokType::Module_Export ); - } + define->Content = cache_str( tok_to_str(currtok) ); + eat( Tok_Preprocess_Content ); + // #define - eat( which ); - - attributes = parse_attributes(); - - if ( check( TokType::Identifier ) ) - { - name = parse_identifier(); - Context.Scope->Name = name; - } - - local_persist char interface_arr_mem[ kilobytes( 4 ) ] { 0 }; - Array< CodeType > interfaces = Array< CodeType >::init_reserve( Arena::init_from_memory( interface_arr_mem, kilobytes( 4 ) ), 4 ); - - if ( check( TokType::Assign_Classifer ) ) - { - eat( TokType::Assign_Classifer ); - - if ( currtok.is_access_specifier() ) - { - access = currtok.to_access_specifier(); - } - - Token parent_tok = parse_identifier(); - parent = def_type( parent_tok ); - - while ( check( TokType::Comma ) ) - { - eat( TokType::Access_Public ); - - if ( currtok.is_access_specifier() ) - { - eat( currtok.Type ); - } - - Token interface_tok = parse_identifier(); - - interfaces.append( def_type( interface_tok ) ); - } - } - - if ( check( TokType::BraceCurly_Open ) ) - { - body = parse_class_struct_body( which, name ); - } - - CodeComment inline_cmt = NoCode; - if ( ! inplace_def ) - { - Token stmt_end = currtok; - eat( TokType::Statement_End ); - - if ( currtok_noskip.Type == TokType::Comment && currtok_noskip.Line == stmt_end.Line ) - inline_cmt = parse_comment(); - } - - if ( which == TokType::Decl_Class ) - result = def_class( name, body, parent, access, attributes, mflags ); - - else - result = def_struct( name, body, ( CodeType )parent, access, attributes, mflags ); - - if ( inline_cmt ) - result->InlineCmt = inline_cmt; - - interfaces.free(); - return result; -} - -internal inline CodeDefine parse_define() -{ - using namespace Parser; - push_scope(); - - eat( TokType::Preprocess_Define ); - - CodeDefine define = ( CodeDefine )make_code(); - define->Type = ECode::Preprocess_Define; - - if ( ! check( TokType::Identifier ) ) - { - log_failure( "Error, expected identifier after #define\n%s", Context.to_string() ); - Context.pop(); - return CodeInvalid; - } - - Context.Scope->Name = currtok; - define->Name = get_cached_string( currtok ); - eat( TokType::Identifier ); - - if ( ! check( TokType::Preprocess_Content ) ) - { - log_failure( "Error, expected content after #define %s\n%s", define->Name, Context.to_string() ); - Context.pop(); - return CodeInvalid; - } - - if ( currtok.Length == 0 ) - { - define->Content = get_cached_string( currtok ); - eat( TokType::Preprocess_Content ); - - Context.pop(); + parser_pop(& _ctx->parser); return define; } - define->Content = get_cached_string( strip_formatting( currtok, strip_formatting_dont_preserve_newlines ) ); - eat( TokType::Preprocess_Content ); + define->Content = cache_str( strbuilder_to_str( parser_strip_formatting( tok_to_str(currtok), parser_strip_formatting_dont_preserve_newlines )) ); + eat( Tok_Preprocess_Content ); + // #define - Context.pop(); + parser_pop(& _ctx->parser); return define; } -internal inline Code parse_foward_or_definition( Parser::TokType which, bool is_inplace ) +internal inline +Code parse_assignment_expression() { - using namespace Parser; + Code expr = { nullptr }; - Code result = CodeInvalid; + eat( Tok_Operator ); + // = + + Token expr_tok = currtok; + + if ( currtok.Type == Tok_Statement_End && currtok.Type != Tok_Comma ) + { + log_failure( "Expected expression after assignment operator\n%s", parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; + } + + s32 level = 0; + while ( left && currtok.Type != Tok_Statement_End && (currtok.Type != Tok_Comma || level > 0) ) + { + if (currtok.Type == Tok_BraceCurly_Open ) + level++; + if (currtok.Type == Tok_BraceCurly_Close ) + level--; + if (currtok.Type == Tok_Capture_Start) + level++; + else if (currtok.Type == Tok_Capture_End) + level--; + + eat( currtok.Type ); + } + + expr_tok.Text.Len = ( ( sptr )currtok.Text.Ptr + currtok.Text.Len ) - ( sptr )expr_tok.Text.Ptr - 1; + expr = untyped_str( tok_to_str(expr_tok) ); + // = + return expr; +} + +internal inline +Code parse_forward_or_definition( TokType which, bool is_inplace ) +{ + Code result = InvalidCode; switch ( which ) { - case TokType::Decl_Class : - result = parse_class( is_inplace ); - Context.pop(); + case Tok_Decl_Class: + result = cast(Code, parser_parse_class( is_inplace )); return result; - case TokType::Decl_Enum : - result = parse_enum( is_inplace ); - Context.pop(); + case Tok_Decl_Enum: + result = cast(Code, parser_parse_enum( is_inplace )); return result; - case TokType::Decl_Struct : - result = parse_struct( is_inplace ); - Context.pop(); + case Tok_Decl_Struct: + result = cast(Code, parser_parse_struct( is_inplace )); return result; - case TokType::Decl_Union : - result = parse_union( is_inplace ); - Context.pop(); + case Tok_Decl_Union: + result = cast(Code, parser_parse_union( is_inplace )); return result; - default : - log_failure( - "Error, wrong token type given to parse_complicated_definition " - "(only supports class, enum, struct, union) \n%s", - Context.to_string() - ); + default: + log_failure( "Error, wrong token type given to parse_complicated_definition " + "(only supports class, enum, struct, union) \n%s" + , parser_to_strbuilder(_ctx->parser) ); - Context.pop(); - return CodeInvalid; + return InvalidCode; } - - return CodeInvalid; } // Function parsing is handled in multiple places because its initial signature is shared with variable parsing -internal inline CodeFn - parse_function_after_name( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType ret_type, Parser::Token name ) +internal inline +CodeFn parse_function_after_name( + ModuleFlag mflags + , CodeAttributes attributes + , CodeSpecifiers specifiers + , CodeTypename ret_type + , Token name +) { - using namespace Parser; push_scope(); + CodeParams params = parse_params(parser_use_parenthesis); + // ( ) - CodeParam params = parse_params(); - - // These have to be kept separate from the return type's specifiers. - while ( left && currtok.is_specifier() ) + // TODO(Ed), Review old comment : These have to be kept separate from the return type's specifiers. + while ( left && tok_is_specifier(currtok) ) { - if ( specifiers.ast == nullptr ) + if ( specifiers == nullptr ) { - specifiers = def_specifier( ESpecifier::to_type( currtok ) ); + specifiers = def_specifier( str_to_specifier( tok_to_str(currtok)) ); eat( currtok.Type ); continue; } - specifiers.append( ESpecifier::to_type( currtok ) ); + specifiers_append(specifiers, str_to_specifier( tok_to_str(currtok)) ); eat( currtok.Type ); } + // ( ) - CodeBody body = NoCode; - CodeComment inline_cmt = NoCode; - if ( check( TokType::BraceCurly_Open ) ) + CodeBody body = NullCode; + CodeComment inline_cmt = NullCode; + if ( check( Tok_BraceCurly_Open ) ) { - body = parse_function_body(); - if ( body == Code::Invalid ) + body = cast(CodeBody, parse_function_body()); + if ( cast(Code, body) == Code_Invalid ) { - Context.pop(); - return CodeInvalid; + parser_pop(& _ctx->parser); + return InvalidCode; } + // ( ) { } + } + else if ( check(Tok_Operator) && currtok.Text.Ptr[0] == '=' ) + { + eat(Tok_Operator); + specifiers_append(specifiers, Spec_Pure ); + + eat( Tok_Number); + Token stmt_end = currtok; + eat( Tok_Statement_End ); + // ( ) = 0; + + if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line ) + inline_cmt = parse_comment(); + // ( ) ; } else { Token stmt_end = currtok; - eat( TokType::Statement_End ); + eat( Tok_Statement_End ); + // ( ) ; - if ( currtok_noskip.Type == TokType::Comment && currtok_noskip.Line == stmt_end.Line ) + if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line ) inline_cmt = parse_comment(); + // ( ) ; } - using namespace ECode; + StrBuilder + name_stripped = strbuilder_make_str( _ctx->Allocator_Temp, tok_to_str(name) ); + strbuilder_strip_space(name_stripped); - - - String name_stripped = String::make( GlobalAllocator, name ); - name_stripped.strip_space(); - - CodeFn result = ( CodeFn )make_code(); - result->Name = get_cached_string( name_stripped ); + CodeFn + result = (CodeFn) make_code(); + result->Name = cache_str( strbuilder_to_str(name_stripped) ); result->ModuleFlags = mflags; if ( body ) { switch ( body->Type ) { - case Function_Body : - case Untyped : + case CT_Function_Body: + case CT_Untyped: break; - default : + default: { - log_failure( "Body must be either of Function_Body or Untyped type, %s\n%s", body.debug_str(), Context.to_string() ); - Context.pop(); - return CodeInvalid; + log_failure("Body must be either of Function_Body or Untyped type, %s\n%s", code_debug_str(body), parser_to_strbuilder(_ctx->parser)); + parser_pop(& _ctx->parser); + return InvalidCode; } } - result->Type = Function; + result->Type = CT_Function; result->Body = body; } else { - result->Type = Function_Fwd; + result->Type = CT_Function_Fwd; } + if ( attributes ) + result->Attributes = attributes; + if ( specifiers ) result->Specs = specifiers; @@ -19924,245 +21436,293 @@ internal inline CodeFn if ( inline_cmt ) result->InlineCmt = inline_cmt; - Context.pop(); + parser_pop(& _ctx->parser); return result; } -internal Code parse_function_body() +internal +Code parse_function_body() { - using namespace Parser; - using namespace ECode; push_scope(); - eat( TokType::BraceCurly_Open ); + eat( Tok_BraceCurly_Open ); - CodeBody result = ( CodeBody )make_code(); - result->Type = Function_Body; + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Function_Body; // TODO : Support actual parsing of function body - Token start = currtok; + Token start = currtok_noskip; - s32 level = 0; - while ( left && ( currtok.Type != TokType::BraceCurly_Close || level > 0 ) ) + s32 level = 0; + while ( left && ( currtok_noskip.Type != Tok_BraceCurly_Close || level > 0 ) ) { - if ( currtok.Type == TokType::BraceCurly_Open ) + if ( currtok_noskip.Type == Tok_BraceCurly_Open ) level++; - else if ( currtok.Type == TokType::BraceCurly_Close && level > 0 ) + else if ( currtok_noskip.Type == Tok_BraceCurly_Close && level > 0 ) level--; - eat( currtok.Type ); + eat( currtok_noskip.Type ); } - Token previous = prevtok; + Token past = prevtok; - s32 len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; + s32 len = ( (sptr)prevtok.Text.Ptr + prevtok.Text.Len ) - (sptr)start.Text.Ptr; if ( len > 0 ) { - result.append( def_execution( { len, start.Text } ) ); + Str str = { start.Text.Ptr, len }; + body_append( result, cast(Code, def_execution( str )) ); } - eat( TokType::BraceCurly_Close ); + eat( Tok_BraceCurly_Close ); - Context.pop(); - return result; + parser_pop(& _ctx->parser); + return cast(Code, result); } -internal neverinline CodeBody parse_global_nspace( CodeT which ) +internal neverinline +CodeBody parse_global_nspace( CodeType which ) { - using namespace Parser; - using namespace ECode; + push_scope(); - if ( which != Namespace_Body && which != Global_Body && which != Export_Body && which != Extern_Linkage_Body ) - return CodeInvalid; + if ( which != CT_Namespace_Body && which != CT_Global_Body && which != CT_Export_Body && which != CT_Extern_Linkage_Body ) + return InvalidCode; - if ( which != Global_Body ) - eat( TokType::BraceCurly_Open ); + if ( which != CT_Global_Body ) + eat( Tok_BraceCurly_Open ); + // { - CodeBody result = ( CodeBody )make_code(); - result->Type = which; + CodeBody + result = (CodeBody) make_code(); + result->Type = which; - while ( left && currtok_noskip.Type != TokType::BraceCurly_Close ) + while ( left && currtok_noskip.Type != Tok_BraceCurly_Close ) { - Code member = Code::Invalid; + Code member = Code_Invalid; CodeAttributes attributes = { nullptr }; CodeSpecifiers specifiers = { nullptr }; - bool expects_function = false; + bool expects_function = false; - Context.Scope->Start = currtok_noskip; + // _ctx->parser.Scope->Start = currtok_noskip; - if ( currtok_noskip.Type == TokType::Preprocess_Hash ) - eat( TokType::Preprocess_Hash ); + if ( currtok_noskip.Type == Tok_Preprocess_Hash ) + eat( Tok_Preprocess_Hash ); + + b32 macro_found = false; switch ( currtok_noskip.Type ) { - case TokType::NewLine : + case Tok_Comma: + { + log_failure("Dangling comma found: %SB\nContext:\n%SB", tok_to_strbuilder(currtok), parser_to_strbuilder(_ctx->parser)); + parser_pop( & _ctx->parser); + return InvalidCode; + } + break; + case Tok_Statement_End: + { + // TODO(Ed): Convert this to a general warning procedure + log_fmt("Dangling end statement found %SB\n", tok_to_strbuilder(currtok_noskip)); + eat( Tok_Statement_End ); + continue; + } + case Tok_NewLine: // Empty lines are auto skipped by Tokens.current() member = fmt_newline; - eat( TokType::NewLine ); - break; + eat( Tok_NewLine ); + break; - case TokType::Comment : - member = parse_comment(); - break; + case Tok_Comment: + member = cast(Code, parse_comment()); + break; - case TokType::Decl_Class : - member = parse_complicated_definition( TokType::Decl_Class ); - break; + case Tok_Decl_Class: + member = parse_complicated_definition( Tok_Decl_Class ); + // class + break; - case TokType::Decl_Enum : - member = parse_complicated_definition( TokType::Decl_Enum ); - break; + case Tok_Decl_Enum: + member = parse_complicated_definition( Tok_Decl_Enum ); + // enum + break; - case TokType::Decl_Extern_Linkage : - if ( which == Extern_Linkage_Body ) - log_failure( "Nested extern linkage\n%s", Context.to_string() ); + case Tok_Decl_Extern_Linkage: + if ( which == CT_Extern_Linkage_Body ) + log_failure( "Nested extern linkage\n%s", parser_to_strbuilder(_ctx->parser) ); - member = parse_extern_link_body(); - break; + member = cast(Code, parser_parse_extern_link()); + // extern "..." { ... } + break; - case TokType::Decl_Namespace : - member = parse_namespace(); - break; + case Tok_Decl_Namespace: + member = cast(Code, parser_parse_namespace()); + // namespace { ... } + break; - case TokType::Decl_Struct : - member = parse_complicated_definition( TokType::Decl_Struct ); - break; + case Tok_Decl_Struct: + member = parse_complicated_definition( Tok_Decl_Struct ); + // struct ... + break; - case TokType::Decl_Template : - member = parse_template(); - break; + case Tok_Decl_Template: + member = cast(Code, parser_parse_template()); + // template<...> ... + break; - case TokType::Decl_Typedef : - member = parse_typedef(); - break; + case Tok_Decl_Typedef: + member = cast(Code, parser_parse_typedef()); + // typedef ... + break; - case TokType::Decl_Union : - member = parse_complicated_definition( TokType::Decl_Union ); - break; + case Tok_Decl_Union: + member = parse_complicated_definition( Tok_Decl_Union ); + // union ... + break; - case TokType::Decl_Using : - member = parse_using(); - break; + case Tok_Decl_Using: + member = cast(Code, parser_parse_using()); + // using ... + break; - case TokType::Preprocess_Define : - member = parse_define(); - break; + case Tok_Preprocess_Define: + member = cast(Code, parse_define()); + // #define ... + break; - case TokType::Preprocess_Include : - member = parse_include(); - break; + case Tok_Preprocess_Include: + member = cast(Code, parse_include()); + // #include ... + break; - case TokType::Preprocess_If : - case TokType::Preprocess_IfDef : - case TokType::Preprocess_IfNotDef : - case TokType::Preprocess_ElIf : - member = parse_preprocess_cond(); - break; + case Tok_Preprocess_If: + case Tok_Preprocess_IfDef: + case Tok_Preprocess_IfNotDef: + case Tok_Preprocess_ElIf: + member = cast(Code, parse_preprocess_cond()); + // # ... + break; - case TokType::Preprocess_Macro : - member = parse_simple_preprocess( TokType::Preprocess_Macro ); - break; + case Tok_Preprocess_Else: + member = cast(Code, preprocess_else); + eat( Tok_Preprocess_Else ); + // #else + break; - case TokType::Preprocess_Pragma : - member = parse_pragma(); - break; + case Tok_Preprocess_EndIf: + member = cast(Code, preprocess_endif); + eat( Tok_Preprocess_EndIf ); + // #endif + break; - case TokType::Preprocess_Else : - member = preprocess_else; - eat( TokType::Preprocess_Else ); - break; + case Tok_Preprocess_Macro: { + // + macro_found = true; + goto Preprocess_Macro_Bare_In_Body; + } + break; - case TokType::Preprocess_EndIf : - member = preprocess_endif; - eat( TokType::Preprocess_EndIf ); - break; + case Tok_Preprocess_Pragma: { + member = cast(Code, parse_pragma()); + // #pragma ... + } + break; - case TokType::Preprocess_Unsupported : - member = parse_simple_preprocess( TokType::Preprocess_Unsupported ); - break; + case Tok_Preprocess_Unsupported: { + member = cast(Code, parse_simple_preprocess( Tok_Preprocess_Unsupported, parser_consume_braces )); + // # ... + } + break; - case TokType::StaticAssert : - member = parse_static_assert(); - break; + case Tok_StaticAssert: { + member = cast(Code, parse_static_assert()); + // static_assert( , ... ); + } + break; - case TokType::Module_Export : - if ( which == Export_Body ) - log_failure( "Nested export declaration\n%s", Context.to_string() ); + case Tok_Module_Export: { + if ( which == CT_Export_Body ) + log_failure( "Nested export declaration\n%s", parser_to_strbuilder(_ctx->parser) ); - member = parse_export_body(); - break; + member = cast(Code, parser_parse_export_body()); + // export { ... } + } + break; - case TokType::Module_Import : - { - not_implemented( context ); + case Tok_Module_Import: { + // import ... + log_failure( "gen::%s: This function is not implemented" ); + return InvalidCode; } //! Fallthrough intentional - case TokType::Decl_GNU_Attribute : - case TokType::Decl_MSVC_Attribute : -#define Entry( attribute, str ) case TokType::attribute : - GEN_DEFINE_ATTRIBUTE_TOKENS -#undef Entry - { - attributes = parse_attributes(); - } - //! Fallthrough intentional - case TokType::Spec_Consteval : - case TokType::Spec_Constexpr : - case TokType::Spec_Constinit : - case TokType::Spec_Extern : - case TokType::Spec_ForceInline : - case TokType::Spec_Global : - case TokType::Spec_Inline : - case TokType::Spec_Internal_Linkage : - case TokType::Spec_NeverInline : - case TokType::Spec_Static : + case Tok_Attribute_Open: + case Tok_Decl_GNU_Attribute: + case Tok_Decl_MSVC_Attribute: + #define Entry( attribute, str ) case attribute: + GEN_DEFINE_ATTRIBUTE_TOKENS + #undef Entry { - SpecifierT specs_found[ 16 ] { ESpecifier::NumSpecifiers }; + attributes = parse_attributes(); + // + } + //! Fallthrough intentional + case Tok_Spec_Consteval: + case Tok_Spec_Constexpr: + case Tok_Spec_Constinit: + case Tok_Spec_Extern: + case Tok_Spec_ForceInline: + case Tok_Spec_Global: + case Tok_Spec_Inline: + case Tok_Spec_Internal_Linkage: + case Tok_Spec_NeverInline: + case Tok_Spec_Static: + { + Specifier specs_found[16] = { Spec_NumSpecifiers }; s32 NumSpecifiers = 0; - while ( left && currtok.is_specifier() ) + while ( left && tok_is_specifier(currtok) ) { - SpecifierT spec = ESpecifier::to_type( currtok ); + Specifier spec = str_to_specifier( tok_to_str(currtok) ); bool ignore_spec = false; switch ( spec ) { - case ESpecifier::Constexpr : - case ESpecifier::Constinit : - case ESpecifier::ForceInline : - case ESpecifier::Global : - case ESpecifier::External_Linkage : - case ESpecifier::Internal_Linkage : - case ESpecifier::Inline : - case ESpecifier::Mutable : - case ESpecifier::NeverInline : - case ESpecifier::Static : - case ESpecifier::Volatile : - break; - - case ESpecifier::Consteval : - expects_function = true; - break; - - case ESpecifier::Const : - ignore_spec = true; - break; - - default : - StrC spec_str = ESpecifier::to_str( spec ); - - log_failure( "Invalid specifier %.*s for variable\n%s", spec_str.Len, spec_str, Context.to_string() ); - return CodeInvalid; - } - - if ( ignore_spec ) + case Spec_Constexpr: + case Spec_Constinit: + case Spec_ForceInline: + case Spec_Global: + case Spec_External_Linkage: + case Spec_Internal_Linkage: + case Spec_Inline: + case Spec_Mutable: + case Spec_NeverInline: + case Spec_Static: + case Spec_Volatile: break; - specs_found[ NumSpecifiers ] = spec; + case Spec_Consteval: + expects_function = true; + break; + + case Spec_Const: + ignore_spec = true; + break; + + default: + Str spec_str = spec_to_str(spec); + + log_failure( "Invalid specifier %S for variable\n%S", spec_str, strbuilder_to_str( parser_to_strbuilder(_ctx->parser)) ); + parser_pop(& _ctx->parser); + return InvalidCode; + } + + if (ignore_spec) + break; + + specs_found[NumSpecifiers] = spec; NumSpecifiers++; eat( currtok.Type ); } @@ -20171,472 +21731,748 @@ internal neverinline CodeBody parse_global_nspace( CodeT which ) { specifiers = def_specifiers( NumSpecifiers, specs_found ); } + // } //! Fallthrough intentional - case TokType::Identifier : - case TokType::Spec_Const : - case TokType::Type_Long : - case TokType::Type_Short : - case TokType::Type_Signed : - case TokType::Type_Unsigned : - case TokType::Type_char : - case TokType::Type_double : - case TokType::Type_int : + case Tok_Identifier: + case Tok_Spec_Const: + case Tok_Type_Long: + case Tok_Type_Short: + case Tok_Type_Signed: + case Tok_Type_Unsigned: + case Tok_Type_bool: + case Tok_Type_char: + case Tok_Type_double: + case Tok_Type_int: { - bool found_operator_cast = false; - s32 idx = Context.Tokens.Idx; - - for ( ; idx < Context.Tokens.Arr.num(); idx++ ) + // This s only in a scope so that Preprocess_Macro_Bare_In_Body works without microsoft extension warnings { - Token tok = Context.Tokens[ idx ]; - - if ( tok.Type == TokType::Identifier ) + Code constructor_destructor = parse_global_nspace_constructor_destructor( specifiers ); + // Possible constructor implemented at global file scope. + if ( constructor_destructor ) { - idx++; - tok = Context.Tokens[ idx ]; - if ( tok.Type == TokType::Access_StaticSymbol ) - continue; + member = constructor_destructor; + break; + } + + bool found_operator_cast_outside_class_implmentation = false; + s32 idx = _ctx->parser.Tokens.Idx; + + for ( ; idx < array_num(_ctx->parser.Tokens.Arr); idx++ ) + { + Token tok = _ctx->parser.Tokens.Arr[ idx ]; + + if ( tok.Type == Tok_Identifier ) + { + idx++; + tok = _ctx->parser.Tokens.Arr[ idx ]; + if ( tok.Type == Tok_Access_StaticSymbol ) + continue; + + break; + } + + if ( tok.Type == Tok_Decl_Operator ) + found_operator_cast_outside_class_implmentation = true; break; } - if ( tok.Type == TokType::Decl_Operator ) - found_operator_cast = true; - - break; + if ( found_operator_cast_outside_class_implmentation ) + { + member = cast(Code, parser_parse_operator_cast( specifiers )); + // ::operator () { ... } + break; + } } - if ( found_operator_cast ) + if (macro_found) { - member = parse_operator_cast(); - break; + Preprocess_Macro_Bare_In_Body: + b32 lone_macro = nexttok.Type == Tok_Statement_End || nexttok_noskip.Type == Tok_NewLine; + if (lone_macro) + { + member = parse_simple_preprocess( Tok_Preprocess_Macro, parser_consume_braces ); + // ; + + if ( member == Code_Invalid ) + { + log_failure( "Failed to parse member\n%s", parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; + } + goto Member_Resolved_To_Lone_Macro; + } + + // We have a macro but its most likely behaving as a typename + // ... } } - if ( member == Code::Invalid ) + Member_Resolved_To_Lone_Macro: + if ( member == Code_Invalid ) { - log_failure( "Failed to parse member\n%s", Context.to_string() ); - return CodeInvalid; + log_failure( "Failed to parse member\nToken: %SB\nContext:\n%SB", tok_to_strbuilder(currtok_noskip), parser_to_strbuilder(_ctx->parser) ); + parser_pop(& _ctx->parser); + return InvalidCode; } // log_fmt("Global Body Member: %s", member->debug_str()); - result.append( member ); + body_append(result, member ); } - if ( which != Global_Body ) - eat( TokType::BraceCurly_Close ); + if ( which != CT_Global_Body ) + eat( Tok_BraceCurly_Close ); + // { } + + parser_pop(& _ctx->parser); + return result; +} + +internal inline +Code parse_global_nspace_constructor_destructor( CodeSpecifiers specifiers ) +{ + Code result = { nullptr }; + + /* + To check if a definition is for a constructor we can go straight to the opening parenthesis for its parameters + From There we work backwards to see if we come across two identifiers with the same name between an member access + :: operator, there can be template parameters on the left of the :: so we ignore those. + Whats important is that its back to back. + + This has multiple possible faults. What we parse using this method may not filter out if something has a "return type" + This is bad since technically you could have a namespace nested into another namespace with the same name. + If this awful pattern is done the only way to distiguish with this coarse parse is to know there is no return type defined. + + TODO(Ed): We could fix this by attempting to parse a type, but we would have to have a way to have it soft fail and rollback. + */ + TokArray tokens = _ctx->parser.Tokens; + + s32 idx = tokens.Idx; + Token nav = tokens.Arr[ idx ]; + for ( ; idx < array_num(tokens.Arr); idx++, nav = tokens.Arr[ idx ] ) + { + if ( nav.Text.Ptr[0] == '<' ) + { + // Skip templated expressions as they mey have expressions with the () operators + s32 capture_level = 0; + s32 template_level = 0; + for ( ; idx < array_num(tokens.Arr); idx++, nav = tokens.Arr[idx] ) + { + if (nav.Text.Ptr[ 0 ] == '<') + ++ template_level; + + if (nav.Text.Ptr[ 0 ] == '>') + -- template_level; + if (nav.Type == Tok_Operator && nav.Text.Ptr[1] == '>') + -- template_level; + + if ( nav.Type == Tok_Capture_Start) + { + if (template_level != 0 ) + ++ capture_level; + else + break; + } + + if ( template_level != 0 && nav.Type == Tok_Capture_End) + -- capture_level; + } + } + + if ( nav.Type == Tok_Capture_Start ) + break; + } + + -- idx; + Token tok_right = tokens.Arr[idx]; + Token tok_left = NullToken; + + if (tok_right.Type != Tok_Identifier) + { + // We're not dealing with a constructor if there is no identifier right before the opening of a parameter's scope. + return result; + } + + -- idx; + tok_left = tokens.Arr[idx]; + // ... + + bool possible_destructor = false; + if ( tok_left.Type == Tok_Operator && tok_left.Text.Ptr[0] == '~') + { + possible_destructor = true; + -- idx; + tok_left = tokens.Arr[idx]; + } + + if ( tok_left.Type != Tok_Access_StaticSymbol ) + return result; + + -- idx; + tok_left = tokens.Arr[idx]; + // ... :: + + // We search toward the left until we find the next valid identifier + s32 capture_level = 0; + s32 template_level = 0; + while ( idx != tokens.Idx ) + { + if (tok_left.Text.Ptr[ 0 ] == '<') + ++ template_level; + + if (tok_left.Text.Ptr[ 0 ] == '>') + -- template_level; + if (tok_left.Type == Tok_Operator && tok_left.Text.Ptr[1] == '>') + -- template_level; + + if ( template_level != 0 && tok_left.Type == Tok_Capture_Start) + ++ capture_level; + + if ( template_level != 0 && tok_left.Type == Tok_Capture_End) + -- capture_level; + + if ( capture_level == 0 && template_level == 0 && tok_left.Type == Tok_Identifier ) + break; + + -- idx; + tok_left = tokens.Arr[idx]; + } + + bool is_same = c_str_compare_len( tok_right.Text.Ptr, tok_left.Text.Ptr, tok_right.Text.Len ) == 0; + if (tok_left.Type == Tok_Identifier && is_same) + { + // We have found the pattern we desired + if (possible_destructor) + { + // :: ~ ( + result = cast(Code, parser_parse_destructor( specifiers )); + } + else { + // :: ( + result = cast(Code, parser_parse_constructor( specifiers )); + } + } return result; } -internal Parser::Token parse_identifier( bool* possible_member_function ) +// TODO(Ed): I want to eventually change the identifier to its own AST type. +// This would allow distinction of the qualifier for a symbol :: +// This would also allow +internal +Token parse_identifier( bool* possible_member_function ) { - using namespace Parser; push_scope(); - Token name = currtok; - Context.Scope->Name = name; - eat( TokType::Identifier ); + Token name = currtok; + _ctx->parser.Scope->Name = name.Text; + eat( Tok_Identifier ); + // - parse_template_args( name ); + parse_template_args( & name ); + //