SectrPrototype/examples/gencpp_singleheader.hpp

10003 lines
308 KiB
C++

// This file was generated automatially by gencpp's singleheader.cpp(See: https://github.com/Ed94/gencpp)
#pragma once
#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
#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++.
See Readme.md for more information from the project repository.
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.25-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
#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 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
#else
# 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
#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
#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
# else
# error This UNIX operating system is not supported
# endif
#else
# error This operating system is not supported
#endif
/* Platform compiler */
#if defined( _MSC_VER )
# pragma message("Detected MSVC")
// # define GEN_COMPILER_CLANG 0
# define GEN_COMPILER_MSVC 1
// # define GEN_COMPILER_GCC 0
#elif defined( __GNUC__ )
# pragma message("Detected GCC")
// # define GEN_COMPILER_CLANG 0
// # define GEN_COMPILER_MSVC 0
# define GEN_COMPILER_GCC 1
#elif defined( __clang__ )
# 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 )
#else
# define GEN_HAS_ATTRIBUTE( attribute ) ( 0 )
#endif
#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))
#else
# define GEN_GCC_VERSION_CHECK(major,minor,patch) (0)
#endif
#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 <stdarg.h>
# include <stddef.h>
# if defined( GEN_SYSTEM_WINDOWS )
# include <intrin.h>
# endif
#if GEN_COMPILER_C
#include <assert.h>
#include <stdbool.h>
#endif
#pragma endregion Mandatory Includes
#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 }
#endif
GEN_NS_BEGIN
#pragma region Macros
#ifndef GEN_API
#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
#endif // GEN_API
#ifndef global // Global variables
# if defined(GEN_STATIC_LINK) || defined(GEN_DYN_LINK)
# define global
# else
# define global static
# endif
#endif
#ifndef internal
#define internal static // Internal linkage
#endif
#ifndef local_persist
#define local_persist static // Local Persisting variables
#endif
#ifndef bit
#define bit( Value ) ( 1 << Value )
#endif
#ifndef bitfield_is_set
#define bitfield_is_set( Type, Field, Mask ) ( (scast(Type, Mask) & scast(Type, Field)) == scast(Type, Mask) )
#endif
// 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
#if GEN_COMPILER_CPP
# ifndef cast
# define cast( type, value ) (tmpl_cast<type>( value ))
# endif
#else
# ifndef cast
# define cast( type, value ) ( (type)(value) )
# endif
#endif
#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
#ifndef stringize
#define stringize_va( ... ) #__VA_ARGS__
#define stringize( ... ) stringize_va( __VA_ARGS__ )
#endif
#define src_line_str stringize(__LINE__)
#ifndef do_once
#define do_once() \
local_persist int __do_once_counter_##src_line_str = 0; \
for(; __do_once_counter_##src_line_str != 1; __do_once_counter_##src_line_str = 1 ) \
#define do_once_defer( expression ) \
local_persist int __do_once_counter_##src_line_str = 0; \
for(;__do_once_counter_##src_line_str != 1; __do_once_counter_##src_line_str = 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
# elif GEN_COMPILER_GCC
# define forceinline inline __attribute__((__always_inline__))
# elif GEN_COMPILER_CLANG
# if __has_attribute(__always_inline__)
# define forceinline inline __attribute__((__always_inline__))
# else
# define forceinline
# endif
# else
# define forceinline
# 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 __typeof__
# elif defined(__GNUC__) || defined(__clang__)
# define typeof __typeof__
# 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
#ifndef get_optional
# if GEN_COMPILER_C
# define get_optional(opt) opt ? *opt : (typeof(*opt)){0}
# else
# define get_optional(opt) opt
# endif
#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_U16_MIN 0u
#define GEN_U16_MAX 0xffffu
#define GEN_I16_MIN ( -0x7fff - 1 )
#define GEN_I16_MAX 0x7fff
#define GEN_U32_MIN 0u
#define GEN_U32_MAX 0xffffffffu
#define GEN_I32_MIN ( -0x7fffffff - 1 )
#define GEN_I32_MAX 0x7fffffff
#define GEN_U64_MIN 0ull
#define GEN_U64_MAX 0xffffffffffffffffull
#define GEN_I64_MIN ( -0x7fffffffffffffffll - 1 )
#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
#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
#else
# error Unknown architecture size. This library only supports 32 bit and 64 bit architectures.
#endif
#define GEN_F32_MIN 1.17549435e-38f
#define GEN_F32_MAX 3.40282347e+38f
#define GEN_F64_MIN 2.2250738585072014e-308
#define GEN_F64_MAX 1.7976931348623157e+308
#if defined( GEN_COMPILER_MSVC )
# if _MSC_VER < 1300
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
# else
typedef unsigned __int8 u8;
typedef signed __int8 s8;
typedef unsigned __int16 u16;
typedef signed __int16 s16;
typedef unsigned __int32 u32;
typedef signed __int32 s32;
# endif
typedef unsigned __int64 u64;
typedef signed __int64 s64;
#else
# include <stdint.h>
typedef uint8_t u8;
typedef int8_t s8;
typedef uint16_t u16;
typedef int16_t s16;
typedef uint32_t u32;
typedef int32_t s32;
typedef uint64_t u64;
typedef int64_t s64;
#endif
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( u16 ) == 2, "sizeof(u16) != 2" );
static_assert( sizeof( u32 ) == 4, "sizeof(u32) != 4" );
static_assert( sizeof( u64 ) == 8, "sizeof(u64) != 8" );
typedef size_t usize;
typedef ptrdiff_t ssize;
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 )
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
typedef _W64 signed int sptr;
typedef _W64 unsigned int uptr;
#else
typedef uintptr_t uptr;
typedef intptr_t sptr;
#endif
static_assert( sizeof( uptr ) == sizeof( sptr ), "sizeof(uptr) != sizeof(sptr)" );
typedef float f32;
typedef double f64;
static_assert( sizeof( f32 ) == 4, "sizeof(f32) != 4" );
static_assert( sizeof( f64 ) == 8, "sizeof(f64) != 8" );
typedef s8 b8;
typedef s16 b16;
typedef s32 b32;
typedef void* mem_ptr;
typedef void const* mem_ptr_const ;
#if GEN_COMPILER_CPP
template<typename Type> uptr to_uptr( Type* ptr ) { return (uptr)ptr; }
template<typename Type> sptr to_sptr( Type* ptr ) { return (sptr)ptr; }
template<typename Type> mem_ptr to_mem_ptr ( Type ptr ) { return (mem_ptr) ptr; }
template<typename Type> mem_ptr_const to_mem_ptr_const( Type ptr ) { return (mem_ptr_const)ptr; }
#else
#define to_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 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
// #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__, __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" )
// NOTE: Things that shouldn't happen with a message!
#define GEN_PANIC( msg, ... ) GEN_ASSERT_MSG( 0, msg, ##__VA_ARGS__ )
#if GEN_BUILD_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 \
{ \
c_str_fmt_out_err( __VA_ARGS__ ); \
GEN_DEBUG_TRAP(); \
process_exit(1); \
} \
while (0)
#endif
GEN_API void assert_handler( char const* condition, char const* file, char const* function, s32 line, char const* msg, ... );
GEN_API s32 assert_crash( char const* condition );
GEN_API 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 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 )
template< class Type >
void swap( Type& a, Type& b )
{
Type tmp = a;
a = b;
b = tmp;
}
//! Checks if value is power of 2.
b32 is_power_of_two( ssize x );
//! Aligns address to specified alignment.
void* align_forward( void* ptr, ssize alignment );
//! Aligns value to a specified alignment.
s64 align_forward_by_value( s64 value, ssize alignment );
//! Moves pointer forward by bytes.
void* pointer_add( void* ptr, ssize bytes );
//! Moves pointer forward by bytes.
void const* pointer_add_const( void const* ptr, ssize bytes );
//! Calculates difference between two addresses.
ssize pointer_diff( void const* begin, void const* end );
//! Copy non-overlapping memory from source to destination.
GEN_API void* mem_copy( void* dest, void const* source, ssize size );
//! Search for a constant value within the size limit at memory location.
GEN_API void const* mem_find( void const* data, u8 byte_value, ssize size );
//! Copy memory from source to destination.
void* mem_move( void* dest, void const* source, ssize size );
//! Set constant value at memory location with specified 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.
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
//! Clears up an array.
#define zero_array( a, count ) zero_size( ( a ), size_of( *( a ) ) * count )
enum AllocType : u8
{
EAllocation_ALLOC,
EAllocation_FREE,
EAllocation_FREE_ALL,
EAllocation_RESIZE,
};
typedef void*(AllocatorProc)( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags );
struct AllocatorInfo
{
AllocatorProc* Proc;
void* Data;
};
enum AllocFlag
{
ALLOCATOR_FLAG_CLEAR_TO_ZERO = bit( 0 ),
};
#ifndef GEN_DEFAULT_MEMORY_ALIGNMENT
# 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 )
#endif
//! Allocate memory with default alignment.
void* alloc( AllocatorInfo a, ssize size );
//! Allocate memory with specified alignment.
void* alloc_align( AllocatorInfo a, ssize size, ssize alignment );
//! Free allocated memory.
void allocator_free( AllocatorInfo a, void* ptr );
//! Free all memory allocated by an allocator.
void free_all( AllocatorInfo a );
//! Resize an allocated memory.
void* resize( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size );
//! Resize an allocated memory with specified 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 ) )
//! Allocate memory for an array of items.
#define alloc_array( allocator_, Type, count ) ( Type* )alloc( allocator_, size_of( Type ) * ( count ) )
/* heap memory analysis tools */
/* 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 */
GEN_API void heap_stats_init( void );
GEN_API ssize heap_stats_used_memory( void );
GEN_API ssize heap_stats_alloc_count( void );
GEN_API void heap_stats_check( void );
//! Allocate/Resize memory using default options.
//! Use this if you don't need a "fancy" resize allocation
void* default_resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size, ssize alignment );
GEN_API 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 ) { AllocatorInfo allocator = { heap_allocator_proc, nullptr }; return allocator; }
//! Helper to allocate memory using heap allocator.
#define malloc( sz ) alloc( heap(), sz )
//! Helper to free memory allocated by heap allocator.
#define mfree( ptr ) allocator_free( heap(), ptr )
struct VirtualMemory
{
void* data;
ssize size;
};
//! Initialize virtual memory from existing data.
GEN_API 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.
GEN_API VirtualMemory vm_alloc( void* addr, ssize size );
//! Release the virtual memory.
GEN_API b32 vm_free( VirtualMemory vm );
//! Trim virtual memory.
GEN_API VirtualMemory vm_trim( VirtualMemory vm, ssize lead_size, ssize size );
//! Purge virtual memory.
GEN_API b32 vm_purge( VirtualMemory vm );
//! Retrieve VM's page size and alignment.
GEN_API 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
GEN_API 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<s32 Size>
struct FixedArena;
template<s32 Size> FixedArena<Size> fixed_arena_init();
template<s32 Size> AllocatorInfo fixed_arena_allocator_info(FixedArena<Size>* fixed_arena );
template<s32 Size> ssize fixed_arena_size_remaining(FixedArena<Size>* fixed_arena, ssize alignment);
template<s32 Size> void fixed_arena_free(FixedArena<Size>* fixed_arena);
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
template<s32 Size> AllocatorInfo allocator_info( FixedArena<Size>& fixed_arena ) { return allocator_info(& fixed_arena); }
template<s32 Size> ssize size_remaining(FixedArena<Size>& fixed_arena, ssize alignment) { return size_remaining( & fixed_arena, alignment); }
#endif
// Just a wrapper around using an arena with memory associated with its scope instead of from an allocator.
// Used for static segment or stack allocations.
template< s32 Size >
struct FixedArena
{
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<Size>(result); return result; }
forceinline ssize size_remaining(ssize alignment) { fixed_arena_size_remaining(this, alignment); }
#pragma endregion Member Mapping
#endif
};
template<s32 Size> inline
AllocatorInfo fixed_arena_allocator_info( FixedArena<Size>* fixed_arena ) {
GEN_ASSERT(fixed_arena);
return { arena_allocator_proc, & fixed_arena->arena };
}
template<s32 Size> inline
void fixed_arena_init(FixedArena<Size>* result) {
zero_size(& result->memory[0], Size);
result->arena = arena_init_from_memory(& result->memory[0], Size);
}
template<s32 Size> inline
void fixed_arena_free(FixedArena<Size>* fixed_arena) {
arena_free( & fixed_arena->arena);
}
template<s32 Size> inline
ssize fixed_arena_size_remaining(FixedArena<Size>* 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;
GEN_API 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);
GEN_API void pool_clear(Pool* pool);
void pool_free(Pool* pool);
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
forceinline AllocatorInfo allocator_info(Pool& pool) { return pool_allocator_info(& pool); }
forceinline void clear(Pool& pool) { return pool_clear(& pool); }
forceinline 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 ) );
}
inline
mem_ptr align_forward( void* ptr, ssize alignment )
{
GEN_ASSERT( is_power_of_two( alignment ) );
uptr p = to_uptr(ptr);
uptr forward = (p + ( alignment - 1 ) ) & ~( alignment - 1 );
return to_mem_ptr(forward);
}
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) );
}
inline
void* mem_move( void* destination, void const* source, ssize byte_count )
{
if ( destination == NULL )
{
return NULL;
}
u8* dest_ptr = rcast( u8*, destination);
u8 const* src_ptr = rcast( u8 const*, source);
if ( dest_ptr == src_ptr )
return dest_ptr;
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 ( to_uptr(src_ptr) % size_of( ssize ) == to_uptr(dest_ptr) % size_of( ssize ) )
{
while ( pcast( uptr, dest_ptr) % size_of( ssize ) )
{
if ( ! byte_count-- )
return destination;
*dest_ptr++ = *src_ptr++;
}
while ( byte_count >= size_of( ssize ) )
{
* 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 ( ; byte_count; byte_count-- )
*dest_ptr++ = *src_ptr++;
}
else
{
if ( ( to_uptr(src_ptr) % size_of( ssize ) ) == ( to_uptr(dest_ptr) % size_of( ssize ) ) )
{
while ( to_uptr( dest_ptr + byte_count ) % size_of( ssize ) )
{
if ( ! byte_count-- )
return destination;
dest_ptr[ byte_count ] = src_ptr[ byte_count ];
}
while ( byte_count >= size_of( ssize ) )
{
byte_count -= size_of( ssize );
* rcast(ssize*, dest_ptr + byte_count ) = * rcast( ssize const*, src_ptr + byte_count );
}
}
while ( byte_count )
byte_count--, dest_ptr[ byte_count ] = src_ptr[ byte_count ];
}
return destination;
}
inline
void* mem_set( void* destination, u8 fill_byte, ssize byte_count )
{
if ( destination == NULL )
{
return NULL;
}
ssize align_offset;
u8* dest_ptr = rcast( u8*, destination);
u32 fill_word = ( ( u32 )-1 ) / 255 * fill_byte;
if ( byte_count == 0 )
return destination;
dest_ptr[ 0 ] = dest_ptr[ byte_count - 1 ] = fill_byte;
if ( byte_count < 3 )
return destination;
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;
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 fill_doubleword = ( scast( u64, fill_word) << 32 ) | fill_word;
while ( byte_count > 31 )
{
* 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;
byte_count -= 32;
dest_ptr += 32;
}
}
return destination;
}
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 );
}
inline
void* alloc( AllocatorInfo a, ssize size ) {
return alloc_align( a, size, GEN_DEFAULT_MEMORY_ALIGNMENT );
}
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 );
}
inline
void free_all( AllocatorInfo a ) {
a.Proc( a.Data, EAllocation_FREE_ALL, 0, 0, nullptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS );
}
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 );
}
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 );
}
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 )
{
allocator_free( a, old_memory );
return nullptr;
}
if ( new_size < old_size )
new_size = old_size;
if ( old_size == new_size )
{
return old_memory;
}
else
{
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 ) );
allocator_free( a, old_memory );
return new_memory;
}
}
inline
void zero_size( void* ptr, ssize size ) {
mem_set( ptr, 0, size );
}
#pragma endregion Memory
#pragma region String Ops
const char* char_first_occurence( const char* str, 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 );
s32 digit_to_int( char c );
s32 hex_digit_to_int( char c );
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
void c_str_to_lower( char* str );
void c_str_to_upper( char* str );
GEN_API s64 c_str_to_i64( const char* str, char** end_ptr, s32 base );
GEN_API void i64_to_str( s64 value, char* string, s32 base );
GEN_API void u64_to_str( u64 value, char* string, s32 base );
GEN_API f64 c_str_to_f64( const char* str, char** end_ptr );
inline
const char* char_first_occurence( const char* s, char c )
{
char ch = c;
for ( ; *s != ch; s++ )
{
if ( *s == '\0' )
return NULL;
}
return s;
}
inline
b32 char_is_alpha( char c )
{
if ( ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) )
return true;
return false;
}
inline
b32 char_is_alphanumeric( char c )
{
return char_is_alpha( c ) || char_is_digit( c );
}
inline
b32 char_is_digit( char c )
{
if ( c >= '0' && c <= '9' )
return true;
return false;
}
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;
}
inline
b32 char_is_space( char c )
{
if ( c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v' )
return true;
return false;
}
inline
char char_to_lower( char c )
{
if ( c >= 'A' && c <= 'Z' )
return 'a' + ( c - 'A' );
return c;
}
inline char char_to_upper( char c )
{
if ( c >= 'a' && c <= 'z' )
return 'A' + ( c - 'a' );
return c;
}
inline
s32 digit_to_int( char c )
{
return char_is_digit( c ) ? c - '0' : c - 'W';
}
inline
s32 hex_digit_to_int( char c )
{
if ( char_is_digit( c ) )
return digit_to_int( c );
else if ( is_between( c, 'a', 'f' ) )
return c - 'a' + 10;
else if ( is_between( c, 'A', 'F' ) )
return c - 'A' + 10;
return -1;
}
inline
s32 c_str_compare( const char* s1, const char* s2 )
{
while ( *s1 && ( *s1 == *s2 ) )
{
s1++, s2++;
}
return *( u8* )s1 - *( u8* )s2;
}
inline
s32 c_str_compare_len( const char* s1, const char* s2, ssize len )
{
for ( ; len > 0; s1++, s2++, len-- )
{
if ( *s1 != *s2 )
return ( ( s1 < s2 ) ? -1 : +1 );
else if ( *s1 == '\0' )
return 0;
}
return 0;
}
inline
char* c_str_copy( char* dest, const char* source, ssize len )
{
GEN_ASSERT_NOT_NULL( dest );
if ( source )
{
char* str = dest;
while ( len > 0 && *source )
{
*str++ = *source++;
len--;
}
while ( len > 0 )
{
*str++ = '\0';
len--;
}
}
return dest;
}
inline
ssize c_str_copy_nulpad( char* dest, const char* source, ssize len )
{
ssize result = 0;
GEN_ASSERT_NOT_NULL( dest );
if ( source )
{
const char* source_start = source;
char* str = dest;
while ( len > 0 && *source )
{
*str++ = *source++;
len--;
}
while ( len > 0 )
{
*str++ = '\0';
len--;
}
result = source - source_start;
}
return result;
}
inline
ssize c_str_len( const char* str )
{
if ( str == NULL )
{
return 0;
}
const char* p = str;
while ( *str )
str++;
return str - p;
}
inline
ssize c_str_len_capped( const char* str, ssize max_len )
{
const char* end = rcast(const char*, mem_find( str, 0, max_len ));
if ( end )
return end - str;
return max_len;
}
inline
char* c_str_reverse( char* str )
{
ssize len = c_str_len( str );
char* a = str + 0;
char* b = str + len - 1;
len /= 2;
while ( len-- )
{
swap( *a, *b );
a++, b--;
}
return str;
}
inline
char const* c_str_skip( char const* str, char c )
{
while ( *str && *str != c )
{
++str;
}
return str;
}
inline
char const* c_str_skip_any( char const* str, char const* char_list )
{
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 = c_str_skip( str, char_list[ i ] );
closest_ptr = min( closest_ptr, p );
}
return closest_ptr;
}
inline
char const* c_str_trim( char const* str, b32 catch_newline )
{
while ( *str && char_is_space( *str ) && ( ! catch_newline || ( catch_newline && *str != '\n' ) ) )
{
++str;
}
return str;
}
inline
void c_str_to_lower( char* str )
{
if ( ! str )
return;
while ( *str )
{
*str = char_to_lower( *str );
str++;
}
}
inline
void c_str_to_upper( char* str )
{
if ( ! str )
return;
while ( *str )
{
*str = char_to_upper( *str );
str++;
}
}
#pragma endregion String Ops
#pragma region Printing
typedef struct FileInfo FileInfo;
#ifndef GEN_PRINTF_MAXLEN
# define GEN_PRINTF_MAXLEN kilobytes(128)
#endif
typedef char PrintF_Buffer[GEN_PRINTF_MAXLEN];
// NOTE: A locally persisting buffer is used internally
GEN_API char* c_str_fmt_buf ( char const* fmt, ... );
GEN_API char* c_str_fmt_buf_va ( char const* fmt, va_list va );
GEN_API ssize c_str_fmt ( char* str, ssize n, char const* fmt, ... );
GEN_API ssize c_str_fmt_va ( char* str, ssize n, char const* fmt, va_list va );
GEN_API ssize c_str_fmt_out_va ( char const* fmt, va_list va );
GEN_API ssize c_str_fmt_out_err ( char const* fmt, ... );
GEN_API ssize c_str_fmt_out_err_va( char const* fmt, va_list va );
GEN_API ssize c_str_fmt_file ( FileInfo* f, char const* fmt, ... );
GEN_API ssize c_str_fmt_file_va ( FileInfo* f, char const* fmt, va_list va );
constexpr
char const* Msg_Invalid_Value = "INVALID VALUE PROVIDED";
inline
ssize log_fmt(char const* fmt, ...)
{
ssize res;
va_list va;
va_start(va, fmt);
res = c_str_fmt_out_va(fmt, va);
va_end(va);
return res;
}
#pragma endregion Printing
#pragma region Containers
template<class TType> struct RemoveConst { typedef TType Type; };
template<class TType> struct RemoveConst<const TType> { typedef TType Type; };
template<class TType> struct RemoveConst<const TType[]> { typedef TType Type[]; };
template<class TType, usize Size> struct RemoveConst<const TType[Size]> { typedef TType Type[Size]; };
template<class TType> using TRemoveConst = typename RemoveConst<TType>::Type;
template <class TType> struct RemovePtr { typedef TType Type; };
template <class TType> struct RemovePtr<TType*> { typedef TType Type; };
template <class TType> using TRemovePtr = typename RemovePtr<TType>::Type;
#pragma region Array
#define Array(Type) Array<Type>
// #define array_init(Type, ...) array_init <Type>(__VA_ARGS__)
// #define array_init_reserve(Type, ...) array_init_reserve<Type>(__VA_ARGS__)
struct ArrayHeader;
#if GEN_COMPILER_CPP
template<class Type> struct Array;
# define get_array_underlying_type(array) typename TRemovePtr<typeof(array)>:: DataType
#endif
usize array_grow_formula(ssize value);
template<class Type> Array<Type> array_init (AllocatorInfo allocator);
template<class Type> Array<Type> array_init_reserve (AllocatorInfo allocator, ssize capacity);
template<class Type> bool array_append_array (Array<Type>* array, Array<Type> other);
template<class Type> bool array_append (Array<Type>* array, Type value);
template<class Type> bool array_append_items (Array<Type>* array, Type* items, usize item_num);
template<class Type> bool array_append_at (Array<Type>* array, Type item, usize idx);
template<class Type> bool array_append_items_at(Array<Type>* array, Type* items, usize item_num, usize idx);
template<class Type> Type* array_back (Array<Type> array);
template<class Type> void array_clear (Array<Type> array);
template<class Type> bool array_fill (Array<Type> array, usize begin, usize end, Type value);
template<class Type> void array_free (Array<Type>* array);
template<class Type> bool arary_grow (Array<Type>* array, usize min_capacity);
template<class Type> usize array_num (Array<Type> array);
template<class Type> void arary_pop (Array<Type> array);
template<class Type> void arary_remove_at (Array<Type> array, usize idx);
template<class Type> bool arary_reserve (Array<Type>* array, usize new_capacity);
template<class Type> bool arary_resize (Array<Type>* array, usize num);
template<class Type> bool arary_set_capacity (Array<Type>* array, usize new_capacity);
template<class Type> ArrayHeader* arary_get_header (Array<Type> array);
struct ArrayHeader {
AllocatorInfo Allocator;
usize Capacity;
usize Num;
};
#if GEN_COMPILER_CPP
template<class Type>
struct Array
{
Type* Data;
#pragma region Member Mapping
forceinline static Array init(AllocatorInfo allocator) { return array_init<Type>(allocator); }
forceinline static Array init_reserve(AllocatorInfo allocator, ssize capacity) { return array_init_reserve<Type>(allocator, capacity); }
forceinline static usize grow_formula(ssize value) { return array_grow_formula<Type>(value); }
forceinline bool append(Array other) { return array_append_array<Type>(this, other); }
forceinline bool append(Type value) { return array_append<Type>(this, value); }
forceinline bool append(Type* items, usize item_num) { return array_append_items<Type>(this, items, item_num); }
forceinline bool append_at(Type item, usize idx) { return array_append_at<Type>(this, item, idx); }
forceinline bool append_at(Type* items, usize item_num, usize idx) { return array_append_items_at<Type>(this, items, item_num, idx); }
forceinline Type* back() { return array_back<Type>(* this); }
forceinline void clear() { array_clear<Type>(* this); }
forceinline bool fill(usize begin, usize end, Type value) { return array_fill<Type>(* this, begin, end, value); }
forceinline void free() { array_free<Type>(this); }
forceinline ArrayHeader* get_header() { return array_get_header<Type>(* this); }
forceinline bool grow(usize min_capacity) { return array_grow<Type>(this, min_capacity); }
forceinline usize num() { return array_num<Type>(*this); }
forceinline void pop() { array_pop<Type>(* this); }
forceinline void remove_at(usize idx) { array_remove_at<Type>(* this, idx); }
forceinline bool reserve(usize new_capacity) { return array_reserve<Type>(this, new_capacity); }
forceinline bool resize(usize num) { return array_resize<Type>(this, num); }
forceinline bool set_capacity(usize new_capacity) { return array_set_capacity<Type>(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<class Type> bool append(Array<Type>& array, Array<Type> other) { return append( & array, other ); }
template<class Type> bool append(Array<Type>& array, Type value) { return append( & array, value ); }
template<class Type> bool append(Array<Type>& array, Type* items, usize item_num) { return append( & array, items, item_num ); }
template<class Type> bool append_at(Array<Type>& array, Type item, usize idx) { return append_at( & array, item, idx ); }
template<class Type> bool append_at(Array<Type>& array, Type* items, usize item_num, usize idx) { return append_at( & array, items, item_num, idx ); }
template<class Type> void free(Array<Type>& array) { return free( & array ); }
template<class Type> bool grow(Array<Type>& array, usize min_capacity) { return grow( & array, min_capacity); }
template<class Type> bool reserve(Array<Type>& array, usize new_capacity) { return reserve( & array, new_capacity); }
template<class Type> bool resize(Array<Type>& array, usize num) { return resize( & array, num); }
template<class Type> bool set_capacity(Array<Type>& array, usize new_capacity) { return set_capacity( & array, new_capacity); }
template<class Type> forceinline Type* begin(Array<Type>& array) { return array; }
template<class Type> forceinline Type* end(Array<Type>& array) { return array + array_get_header(array)->Num; }
template<class Type> forceinline Type* next(Array<Type>& array, Type* entry) { return entry + 1; }
#endif
template<class Type> forceinline Type* array_begin(Array<Type> array) { return array; }
template<class Type> forceinline Type* array_end(Array<Type> array) { return array + array_get_header(array)->Num; }
template<class Type> forceinline Type* array_next(Array<Type> array, Type* entry) { return ++ entry; }
template<class Type> inline
Array<Type> array_init(AllocatorInfo allocator) {
return array_init_reserve<Type>(allocator, array_grow_formula(0));
}
template<class Type> inline
Array<Type> 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)};
}
forceinline
usize array_grow_formula(ssize value) {
return 2 * value + 8;
}
template<class Type> inline
bool array_append_array(Array<Type>* array, Array<Type> other) {
return array_append_items(array, (Type*)other, array_num(other));
}
template<class Type> inline
bool array_append(Array<Type>* array, Type value)
{
GEN_ASSERT( array != nullptr);
GEN_ASSERT(* array != nullptr);
ArrayHeader* header = array_get_header(* array);
if (header->Num == header->Capacity)
{
if ( ! array_grow(array, header->Capacity))
return false;
header = array_get_header(* array);
}
(*array)[ header->Num] = value;
header->Num++;
return true;
}
template<class Type> inline
bool array_append_items(Array<Type>* 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)
{
if ( ! array_grow(array, header->Capacity + item_num))
return false;
header = array_get_header(* array);
}
mem_copy((Type*)array + header->Num, items, item_num * sizeof(Type));
header->Num += item_num;
return true;
}
template<class Type> inline
bool array_append_at(Array<Type>* array, Type item, usize idx)
{
GEN_ASSERT( array != nullptr);
GEN_ASSERT(* array != nullptr);
ArrayHeader* header = array_get_header(* array);
ssize slot = idx;
if (slot >= (ssize)(header->Num))
slot = header->Num - 1;
if (slot < 0)
slot = 0;
if (header->Capacity < header->Num + 1)
{
if ( ! array_grow(array, header->Capacity + 1))
return false;
header = array_get_header(* array);
}
Type* target = &(*array)[slot];
mem_move(target + 1, target, (header->Num - slot) * sizeof(Type));
header->Num++;
return true;
}
template<class Type> inline
bool array_append_items_at(Array<Type>* 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 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<class Type> inline
Type* array_back(Array<Type> array)
{
GEN_ASSERT(array != nullptr);
ArrayHeader* header = array_get_header(array);
if (header->Num <= 0)
return nullptr;
return & (array)[header->Num - 1];
}
template<class Type> inline
void array_clear(Array<Type> array) {
GEN_ASSERT(array != nullptr);
ArrayHeader* header = array_get_header(array);
header->Num = 0;
}
template<class Type> inline
bool array_fill(Array<Type> 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<class Type> forceinline
void array_free(Array<Type>* 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<class Type> forceinline
ArrayHeader* array_get_header(Array<Type> array) {
GEN_ASSERT(array != nullptr);
Type* Data = array;
using NonConstType = TRemoveConst<Type>;
return rcast(ArrayHeader*, const_cast<NonConstType*>(Data)) - 1;
}
template<class Type> forceinline
bool array_grow(Array<Type>* 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<class Type> forceinline
usize array_num(Array<Type> array) {
GEN_ASSERT(array != nullptr);
return array_get_header(array)->Num;
}
template<class Type> forceinline
void array_pop(Array<Type> array) {
GEN_ASSERT(array != nullptr);
ArrayHeader* header = array_get_header(array);
GEN_ASSERT(header->Num > 0);
header->Num--;
}
template<class Type> inline
void array_remove_at(Array<Type> 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<class Type> inline
bool array_reserve(Array<Type>* array, usize new_capacity)
{
GEN_ASSERT( array != nullptr);
GEN_ASSERT(* array != nullptr);
ArrayHeader* header = array_get_header(array);
if (header->Capacity < new_capacity)
return set_capacity(array, new_capacity);
return true;
}
template<class Type> inline
bool array_resize(Array<Type>* 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<class Type> inline
bool array_set_capacity(Array<Type>* 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.
// The cpp library expects the user to use the regular calls as they can resolve the type fine.
#define array_init(type, allocator) array_init <type> (allocator )
#define array_init_reserve(type, allocator, cap) array_init_reserve <type> (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<Type>
template<class Type> struct HashTable;
#ifndef get_hashtable_underlying_type
#define get_hashtable_underlying_type(table) typename TRemovePtr<typeof(table)>:: DataType
#endif
struct HashTableFindResult {
ssize HashIndex;
ssize PrevIndex;
ssize EntryIndex;
};
template<class Type>
struct HashTableEntry {
u64 Key;
ssize Next;
Type Value;
};
#define HashTableEntry(Type) HashTableEntry<Type>
template<class Type> HashTable<Type> hashtable_init (AllocatorInfo allocator);
template<class Type> HashTable<Type> hashtable_init_reserve(AllocatorInfo allocator, usize num);
template<class Type> void hashtable_clear (HashTable<Type> table);
template<class Type> void hashtable_destroy (HashTable<Type>* table);
template<class Type> Type* hashtable_get (HashTable<Type> table, u64 key);
template<class Type> void hashtable_grow (HashTable<Type>* table);
template<class Type> void hashtable_rehash (HashTable<Type>* table, ssize new_num);
template<class Type> void hashtable_rehash_fast (HashTable<Type> table);
template<class Type> void hashtable_remove (HashTable<Type> table, u64 key);
template<class Type> void hashtable_remove_entry(HashTable<Type> table, ssize idx);
template<class Type> void hashtable_set (HashTable<Type>* table, u64 key, Type value);
template<class Type> ssize hashtable_slot (HashTable<Type> table, u64 key);
template<class Type> void hashtable_map (HashTable<Type> table, void (*map_proc)(u64 key, Type value));
template<class Type> void hashtable_map_mut (HashTable<Type> table, void (*map_proc)(u64 key, Type* value));
template<class Type> ssize hashtable__add_entry (HashTable<Type>* table, u64 key);
template<class Type> HashTableFindResult hashtable__find (HashTable<Type> table, u64 key);
template<class Type> bool hashtable__full (HashTable<Type> table);
static constexpr f32 HashTable_CriticalLoadScale = 0.7f;
template<typename Type>
struct HashTable
{
Array<ssize> Hashes;
Array<HashTableEntry<Type>> Entries;
#if ! GEN_C_LIKE_CPP
#pragma region Member Mapping
forceinline static HashTable init(AllocatorInfo allocator) { return hashtable_init<Type>(allocator); }
forceinline static HashTable init_reserve(AllocatorInfo allocator, usize num) { return hashtable_init_reserve<Type>(allocator, num); }
forceinline void clear() { clear<Type>(*this); }
forceinline void destroy() { destroy<Type>(*this); }
forceinline Type* get(u64 key) { return get<Type>(*this, key); }
forceinline void grow() { grow<Type>(*this); }
forceinline void rehash(ssize new_num) { rehash<Type>(*this, new_num); }
forceinline void rehash_fast() { rehash_fast<Type>(*this); }
forceinline void remove(u64 key) { remove<Type>(*this, key); }
forceinline void remove_entry(ssize idx) { remove_entry<Type>(*this, idx); }
forceinline void set(u64 key, Type value) { set<Type>(*this, key, value); }
forceinline ssize slot(u64 key) { return slot<Type>(*this, key); }
forceinline void map(void (*proc)(u64, Type)) { map<Type>(*this, proc); }
forceinline void map_mut(void (*proc)(u64, Type*)) { map_mut<Type>(*this, proc); }
#pragma endregion Member Mapping
#endif
using DataType = Type;
};
#if GEN_SUPPORT_CPP_REFERENCES
template<class Type> void destroy (HashTable<Type>& table) { destroy(& table); }
template<class Type> void grow (HashTable<Type>& table) { grow(& table); }
template<class Type> void rehash (HashTable<Type>& table, ssize new_num) { rehash(& table, new_num); }
template<class Type> void set (HashTable<Type>& table, u64 key, Type value) { set(& table, key, value); }
template<class Type> ssize add_entry(HashTable<Type>& table, u64 key) { add_entry(& table, key); }
#endif
template<typename Type> inline
HashTable<Type> hashtable_init(AllocatorInfo allocator) {
HashTable<Type> result = hashtable_init_reserve<Type>(allocator, 8);
return result;
}
template<typename Type> inline
HashTable<Type> hashtable_init_reserve(AllocatorInfo allocator, usize num)
{
HashTable<Type> result = { { nullptr }, { nullptr } };
result.Hashes = array_init_reserve<ssize>(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<HashTableEntry<Type>>(allocator, num);
return result;
}
template<typename Type> forceinline
void hashtable_clear(HashTable<Type> 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<typename Type> forceinline
void hashtable_destroy(HashTable<Type>* 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<typename Type> forceinline
Type* hashtable_get(HashTable<Type> 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<typename Type> forceinline
void hashtable_map(HashTable<Type> 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<typename Type> forceinline
void hashtable_map_mut(HashTable<Type> 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<typename Type> forceinline
void hashtable_grow(HashTable<Type>* 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<typename Type> inline
void hashtable_rehash(HashTable<Type>* 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<Type> new_ht = hashtable_init_reserve<Type>( array_get_header(table->Hashes)->Allocator, new_num);
for (ssize idx = 0; idx < ssize( array_num(table->Entries)); ++idx)
{
HashTableFindResult find_result;
HashTableEntry<Type>& 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<typename Type> inline
void hashtable_rehash_fast(HashTable<Type> 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<Type>* 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<typename Type> forceinline
void hashtable_remove(HashTable<Type> 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<typename Type> forceinline
void hashtable_remove_entry(HashTable<Type> table, ssize idx) {
GEN_ASSERT_NOT_NULL(table.Hashes);
GEN_ASSERT_NOT_NULL(table.Entries);
remove_at(table.Entries, idx);
}
template<typename Type> inline
void hashtable_set(HashTable<Type>* 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<typename Type> forceinline
ssize hashtable_slot(HashTable<Type> 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<typename Type> forceinline
ssize hashtable__add_entry(HashTable<Type>* table, u64 key) {
GEN_ASSERT_NOT_NULL(table);
GEN_ASSERT_NOT_NULL(table->Hashes);
GEN_ASSERT_NOT_NULL(table->Entries);
ssize idx;
HashTableEntry<Type> entry = { key, -1 };
idx = array_num(table->Entries);
array_append( table->Entries, entry);
return idx;
}
template<typename Type> inline
HashTableFindResult hashtable__find(HashTable<Type> 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<typename Type> forceinline
b32 hashtable_full(HashTable<Type> 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 <type >(allocator)
#define hashtable_init_reserve(type, allocator, num) hashtable_init_reserve<type >(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
GEN_API u32 crc32( void const* data, ssize len );
GEN_API u64 crc64( void const* data, ssize len );
#pragma endregion Hashing
#pragma region Strings
struct Str;
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_str( str ) * rcast( Str*, (str) - sizeof(ssize) )
#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)
{
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;
}
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.
#pragma region StrBuilder
struct StrBuilderHeader;
#if GEN_COMPILER_C
typedef char* StrBuilder;
#else
struct StrBuilder;
#endif
forceinline usize strbuilder_grow_formula(usize value);
GEN_API StrBuilder strbuilder_make_reserve (AllocatorInfo allocator, ssize capacity);
GEN_API StrBuilder strbuilder_make_length (AllocatorInfo allocator, char const* str, ssize length);
GEN_API bool strbuilder_make_space_for (StrBuilder* str, char const* to_append, ssize add_len);
GEN_API bool strbuilder_append_c_str_len (StrBuilder* str, char const* c_str_to_append, ssize length);
GEN_API void strbuilder_trim (StrBuilder str, char const* cut_set);
GEN_API StrBuilder strbuilder_visualize_whitespace(StrBuilder const str);
StrBuilder strbuilder_make_c_str (AllocatorInfo allocator, char const* str);
StrBuilder strbuilder_make_str (AllocatorInfo allocator, Str str);
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_append_char (StrBuilder* str, char c);
bool strbuilder_append_c_str (StrBuilder* str, char const* c_str_to_append);
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_space (StrBuilder str);
struct StrBuilderHeader {
AllocatorInfo Allocator;
ssize Capacity;
ssize Length;
};
#if GEN_COMPILER_CPP
struct StrBuilder
{
char* Data;
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;
}
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
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);
}
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); }
bool append_fmt(char const* fmt, ...) {
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(this, buf, res);
}
#pragma endregion Member Mapping
#endif
};
#endif
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)
{
strbuilder_append_c_str(& result, parts[idx]);
if (idx < num_parts - 1)
strbuilder_append_c_str(& result, glue);
}
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));
}
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));
}
inline
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;
}
forceinline
b32 strbuilder_starts_with_str(StrBuilder const str, Str substring) {
if (substring.Len > strbuilder_length(str))
return false;
b32 result = c_str_compare_len(str, substring.Ptr, substring.Len) == 0;
return result;
}
forceinline
b32 strbuilder_starts_with_string(StrBuilder const str, StrBuilder substring) {
if (strbuilder_length(substring) > strbuilder_length(str))
return false;
b32 result = c_str_compare_len(str, substring, strbuilder_length(substring) - 1) == 0;
return result;
}
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;
}
forceinline
void strbuilder_trim_space(StrBuilder str) {
strbuilder_trim(str, " \t\r\n\v\f");
}
#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
forceinline
Str str_duplicate(Str str, AllocatorInfo allocator) {
Str result = strbuilder_to_str( strbuilder_make_length(allocator, str.Ptr, str.Len));
return result;
}
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.
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
enum FileModeFlag
{
EFileMode_READ = bit( 0 ),
EFileMode_WRITE = bit( 1 ),
EFileMode_APPEND = bit( 2 ),
EFileMode_RW = bit( 3 ),
GEN_FILE_MODES = EFileMode_READ | EFileMode_WRITE | EFileMode_APPEND | EFileMode_RW,
};
// NOTE: Only used internally and for the file operations
enum SeekWhenceType
{
ESeekWhence_BEGIN = 0,
ESeekWhence_CURRENT = 1,
ESeekWhence_END = 2,
};
enum FileError
{
EFileError_NONE,
EFileError_INVALID,
EFileError_INVALID_FILENAME,
EFileError_EXISTS,
EFileError_NOT_EXISTS,
EFileError_PERMISSION,
EFileError_TRUNCATION_FAILURE,
EFileError_NOT_EMPTY,
EFileError_NAME_TOO_LONG,
EFileError_UNKNOWN,
};
union FileDescriptor
{
void* p;
sptr i;
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, 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 )
typedef GEN_FILE_OPEN_PROC( file_open_proc );
typedef GEN_FILE_READ_AT_PROC( FileReadProc );
typedef GEN_FILE_WRITE_AT_PROC( FileWriteProc );
typedef GEN_FILE_SEEK_PROC( FileSeekProc );
typedef GEN_FILE_CLOSE_PROC( FileCloseProc );
struct FileOperations
{
FileReadProc* read_at;
FileWriteProc* write_at;
FileSeekProc* seek;
FileCloseProc* close;
};
extern FileOperations const default_file_operations;
typedef u64 FileTime;
enum DirType
{
GEN_DIR_TYPE_FILE,
GEN_DIR_TYPE_FOLDER,
GEN_DIR_TYPE_UNKNOWN,
};
struct DirInfo;
struct DirEntry
{
char const* filename;
DirInfo* dir_info;
u8 type;
};
struct DirInfo
{
char const* fullpath;
DirEntry* entries; // zpl_array
// Internals
char** filenames; // zpl_array
StrBuilder buf;
};
struct FileInfo
{
FileOperations ops;
FileDescriptor fd;
b32 is_temp;
char const* filename;
FileTime last_write_time;
DirEntry* dir;
};
enum FileStandardType
{
EFileStandard_INPUT,
EFileStandard_OUTPUT,
EFileStandard_ERROR,
EFileStandard_COUNT,
};
/**
* Get standard file I/O.
* @param std Check zpl_file_standard_type
* @return File handle to standard I/O
*/
GEN_API FileInfo* file_get_standard( FileStandardType std );
/**
* Closes the file
* @param file
*/
GEN_API FileError file_close( 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
*/
GEN_API 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
*/
GEN_API 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
*/
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
*/
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
*/
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;
ssize size;
};
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
*/
GEN_API FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const* filepath );
/**
* Returns a size of the file
* @param file
* @return File size
*/
GEN_API 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
*/
s64 file_seek( FileInfo* file, s64 offset );
/**
* 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
*/
s64 file_tell( FileInfo* file );
/**
* 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
*/
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
*/
b32 file_write_at_check( FileInfo* file, void const* buffer, ssize size, s64 offset, ssize* 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 ),
EFileStream_UNDERLYING = GEN_U32_MAX,
};
/**
* Opens a new memory stream
* @param file
* @param allocator
*/
GEN_API 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
*/
GEN_API 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
*/
GEN_API 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;
if ( ! f->ops.read_at )
f->ops = default_file_operations;
f->ops.seek( f->fd, offset, ESeekWhence_BEGIN, &new_offset );
return new_offset;
}
inline
s64 file_seek_to_end( FileInfo* f )
{
s64 new_offset = 0;
if ( ! f->ops.read_at )
f->ops = default_file_operations;
f->ops.seek( f->fd, 0, ESeekWhence_END, &new_offset );
return new_offset;
}
inline
s64 file_tell( FileInfo* f )
{
s64 new_offset = 0;
if ( ! f->ops.read_at )
f->ops = default_file_operations;
f->ops.seek( f->fd, 0, ESeekWhence_CURRENT, &new_offset );
return new_offset;
}
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 ) );
file_seek( f, cur_offset + size );
return result;
}
inline
b32 file_read_at( FileInfo* f, void* buffer, ssize size, s64 offset )
{
return file_read_at_check( f, buffer, size, offset, NULL );
}
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 );
}
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 ) );
file_seek( f, cur_offset + size );
return result;
}
inline
b32 file_write_at( FileInfo* f, void const* buffer, ssize size, s64 offset )
{
return file_write_at_check( f, buffer, size, offset, NULL );
}
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;
return f->ops.write_at( f->fd, buffer, size, offset, bytes_written );
}
#pragma endregion File Handling
#pragma region Timing
#ifdef GEN_BENCHMARK
//! Return CPU timestamp.
GEN_API u64 read_cpu_time_stamp_counter( void );
//! Return relative time (in seconds) since the application start.
GEN_API f64 time_rel( void );
//! Return relative time since the application start.
GEN_API u64 time_rel_ms( void );
#endif
#pragma endregion Timing
#pragma region ADT
enum ADT_Type : u32
{
EADT_TYPE_UNINITIALISED, /* node was not initialised, this is a programming error! */
EADT_TYPE_ARRAY,
EADT_TYPE_OBJECT,
EADT_TYPE_STRING,
EADT_TYPE_MULTISTRING,
EADT_TYPE_INTEGER,
EADT_TYPE_REAL,
};
enum ADT_Props : u32
{
EADT_PROPS_NONE,
EADT_PROPS_NAN,
EADT_PROPS_NAN_NEG,
EADT_PROPS_INFINITY,
EADT_PROPS_INFINITY_NEG,
EADT_PROPS_FALSE,
EADT_PROPS_TRUE,
EADT_PROPS_NULL,
EADT_PROPS_IS_EXP,
EADT_PROPS_IS_HEX,
// Used internally so that people can fill in real numbers they plan to write.
EADT_PROPS_IS_PARSED_REAL,
};
enum ADT_NamingStyle : u32
{
EADT_NAME_STYLE_DOUBLE_QUOTE,
EADT_NAME_STYLE_SINGLE_QUOTE,
EADT_NAME_STYLE_NO_QUOTES,
};
enum ADT_AssignStyle : u32
{
EADT_ASSIGN_STYLE_COLON,
EADT_ASSIGN_STYLE_EQUALS,
EADT_ASSIGN_STYLE_LINE,
};
enum ADT_DelimStyle : u32
{
EADT_DELIM_STYLE_COMMA,
EADT_DELIM_STYLE_LINE,
EADT_DELIM_STYLE_NEWLINE,
};
enum ADT_Error : u32
{
EADT_ERROR_NONE,
EADT_ERROR_INTERNAL,
EADT_ERROR_ALREADY_CONVERTED,
EADT_ERROR_INVALID_TYPE,
EADT_ERROR_OUT_OF_MEMORY,
};
struct ADT_Node
{
char const* name;
struct ADT_Node* parent;
/* properties */
ADT_Type type : 4;
u8 props : 4;
#ifndef GEN_PARSER_DISABLE_ANALYSIS
u8 cfg_mode : 1;
u8 name_style : 2;
u8 assign_style : 2;
u8 delim_style : 2;
u8 delim_line_width : 4;
u8 assign_line_width : 4;
#endif
/* adt data */
union
{
char const* string;
Array(ADT_Node) nodes; ///< zpl_array
struct
{
union
{
f64 real;
s64 integer;
};
#ifndef GEN_PARSER_DISABLE_ANALYSIS
/* number analysis */
s32 base;
s32 base2;
u8 base2_offset : 4;
s8 exp : 4;
u8 neg_zero : 1;
u8 lead_digit : 1;
#endif
};
};
};
/* 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.
*/
/**
* @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
*/
GEN_API 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
*/
GEN_API 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
*/
GEN_API 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
*/
GEN_API 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
*/
GEN_API 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
*/
GEN_API 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
*/
GEN_API 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
*/
GEN_API 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
*/
GEN_API ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent );
/**
* @brief Swap two nodes.
*
* @param node
* @param other_node
* @return
*/
GEN_API void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node );
/**
* @brief Remove node from container.
*
* @param node
* @return
*/
GEN_API void adt_remove_node( ADT_Node* node );
/**
* @brief Initialise a node as an object
*
* @param obj
* @param name
* @param backing
* @return
*/
GEN_API 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
*/
GEN_API 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
*/
GEN_API 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
*/
GEN_API 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
*/
GEN_API 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*
*/
GEN_API 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*
*/
GEN_API 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*
*/
GEN_API 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*
*/
GEN_API 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*
*/
GEN_API 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*
*/
GEN_API 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*
*/
GEN_API 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
*/
GEN_API 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
*/
GEN_API 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
*/
GEN_API 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
*/
GEN_API ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_chars, char const* escape_symbol );
#pragma endregion ADT
#pragma region CSV
enum CSV_Error : u32
{
ECSV_Error__NONE,
ECSV_Error__INTERNAL,
ECSV_Error__UNEXPECTED_END_OF_INPUT,
ECSV_Error__MISMATCHED_ROWS,
};
typedef ADT_Node CSV_Object;
u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header );
GEN_API u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim );
void csv_free( CSV_Object* obj );
void csv_write( FileInfo* file, CSV_Object* obj );
StrBuilder csv_write_string( AllocatorInfo a, CSV_Object* obj );
GEN_API void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delim );
GEN_API StrBuilder csv_write_strbuilder_delimiter( AllocatorInfo a, CSV_Object* obj, char delim );
/* inline */
inline
u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header )
{
return csv_parse_delimiter( root, text, allocator, has_header, ',' );
}
inline
void csv_write( FileInfo* file, CSV_Object* obj )
{
csv_write_delimiter( file, obj, ',' );
}
inline
StrBuilder csv_write_string( AllocatorInfo a, CSV_Object* obj )
{
return csv_write_strbuilder_delimiter( a, obj, ',' );
}
#pragma endregion CSV
GEN_NS_END
// GEN_ROLL_OWN_DEPENDENCIES
#endif
GEN_NS_BEGIN
#pragma region Types
/*
________ __ __ ________
| \ | \ | \ | \
| ▓▓▓▓▓▓▓▓_______ __ __ ______ ____ _______ | ▓▓\ | ▓▓ \▓▓▓▓▓▓▓▓__ __ ______ ______ _______
| ▓▓__ | \| \ | \ \ \ / \ | ▓▓▓\| ▓▓ | ▓▓ | \ | \/ \ / \ / \
| ▓▓ \ | ▓▓▓▓▓▓▓\ ▓▓ | ▓▓ ▓▓▓▓▓▓\▓▓▓▓\ ▓▓▓▓▓▓▓ | ▓▓▓▓\ ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓
| ▓▓▓▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ | ▓▓ | ▓▓\▓▓ \ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓\▓▓ \
| ▓▓_____| ▓▓ | ▓▓ ▓▓__/ ▓▓ ▓▓ | ▓▓ | ▓▓_\▓▓▓▓▓▓\ | ▓▓ \▓▓▓▓ | ▓▓ | ▓▓__/ ▓▓ ▓▓__/ ▓▓ ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\
| ▓▓ \ ▓▓ | ▓▓\▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ \▓▓▓ | ▓▓ \▓▓ ▓▓ ▓▓ ▓▓\▓▓ \ ▓▓
\▓▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓\▓▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓ _\▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓▓▓▓▓▓
| \__| ▓▓ ▓▓
\▓▓ ▓▓ ▓▓
\▓▓▓▓▓▓ \▓▓
*/
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
#else
#define log_failure GEN_FATAL
#endif
enum AccessSpec : u32
{
AccessSpec_Default,
AccessSpec_Private,
AccessSpec_Protected,
AccessSpec_Public,
AccessSpec_Num_AccessSpec,
AccessSpec_Invalid,
AccessSpec_SizeDef = GEN_U32_MAX,
};
static_assert( size_of(AccessSpec) == size_of(u32), "AccessSpec not u32 size" );
inline
Str access_spec_to_str( AccessSpec type )
{
local_persist
Str lookup[ (u32)AccessSpec_Num_AccessSpec ] = {
{ "", sizeof( "" ) - 1 },
{ "private", sizeof("prviate") - 1 },
{ "private", sizeof("protected") - 1 },
{ "public", sizeof("public") - 1 },
};
Str invalid = { "Invalid", sizeof("Invalid") - 1 };
if ( type > AccessSpec_Public )
return invalid;
return lookup[ (u32)type ];
}
enum CodeFlag : u32
{
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 EnumDecl : u8
{
EnumDecl_Regular,
EnumDecl_Class,
EnumT_SizeDef = GEN_U8_MAX,
};
typedef u8 EnumT;
enum ModuleFlag : u32
{
ModuleFlag_None = 0,
ModuleFlag_Export = bit(0),
ModuleFlag_Import = bit(1),
Num_ModuleFlags,
ModuleFlag_Invalid,
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
Str lookup[ (u32)Num_ModuleFlags ] = {
{ "__none__", sizeof("__none__") - 1 },
{ "export", sizeof("export") - 1 },
{ "import", sizeof("import") - 1 },
};
local_persist
Str invalid_flag = { "invalid", sizeof("invalid") };
if ( flag > ModuleFlag_Import )
return invalid_flag;
return lookup[ (u32)flag ];
}
enum EPreprocessCond : u32
{
PreprocessCond_If,
PreprocessCond_IfDef,
PreprocessCond_IfNotDef,
PreprocessCond_ElIf,
EPreprocessCond_SizeDef = GEN_U32_MAX,
};
static_assert( size_of(EPreprocessCond) == size_of(u32), "EPreprocessCond not u32 size" );
enum ETypenameTag : u16
{
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_Parameters_Define,
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
};
inline Str codetype_to_str(CodeType type)
{
local_persist Str lookup[] = {
{ "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 },
{ "Parameters_Define", sizeof("Parameters_Define") - 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];
}
inline Str codetype_to_keyword_str(CodeType type)
{
local_persist Str lookup[] = {
{ "__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 },
{ "__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];
}
forceinline Str to_str(CodeType type)
{
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[] = {
{ "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];
}
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_Restrict,
Spec_RValue,
Spec_Static,
Spec_Thread_Local,
Spec_Virtual,
Spec_Const,
Spec_Final,
Spec_NoExceptions,
Spec_Override,
Spec_Pure,
Spec_Delete,
Spec_Volatile,
Spec_NumSpecifiers,
Spec_UnderlyingType = 0xffffffffu
};
inline Str spec_to_str(Specifier type)
{
local_persist Str lookup[] = {
{ "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 },
{ "restrict", sizeof("restrict") - 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 },
{ "= delete", sizeof("= delete") - 1 },
{ "volatile", sizeof("volatile") - 1 },
};
return lookup[type];
}
inline bool spec_is_trailing(Specifier specifier)
{
switch (specifier)
{
case Spec_Const:
case Spec_Final:
case Spec_NoExceptions:
case Spec_Override:
case Spec_Pure:
case Spec_Delete:
case Spec_Volatile:
return true;
default:
return false;
}
}
inline Specifier str_to_specifier(Str str)
{
local_persist u32 keymap[Spec_NumSpecifiers];
do_once_start for (u32 index = 0; index < Spec_NumSpecifiers; index++)
{
Str enum_str = spec_to_str((Specifier)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 < Spec_NumSpecifiers; index++)
{
if (keymap[index] == hash)
return (Specifier)index;
}
return Spec_Invalid;
}
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_Paren_Open,
Tok_Paren_Close,
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_Define_Param,
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_Expr,
Tok_Preprocess_Macro_Stmt,
Tok_Preprocess_Macro_Typename,
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_Restrict,
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 },
{ "__define_param__", sizeof("__define_param__") - 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_expression__", sizeof("__macro_expression__") - 1 },
{ "__macro_statment__", sizeof("__macro_statment__") - 1 },
{ "__macro_typename__", sizeof("__macro_typename__") - 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 },
{ "restrict", sizeof("restrict") - 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++)
{
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;
}
enum TokFlags : u32
{
TF_Operator = bit(0),
TF_Assign = bit(1),
TF_Identifier = bit(2),
TF_Preprocess = bit(3),
TF_Preprocess_Cond = bit(4),
TF_Attribute = bit(5),
TF_AccessOperator = bit(6),
TF_AccessSpecifier = bit(7),
TF_Specifier = bit(8),
TF_EndDefinition = bit(9), // Either ; or }
TF_Formatting = bit(10),
TF_Literal = bit(11),
TF_Macro_Functional = bit(12),
TF_Macro_Expects_Body = bit(13),
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
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_set( u32, tok.Flags, TF_AccessOperator );
}
forceinline
bool tok_is_access_specifier(Token tok) {
return bitfield_is_set( u32, tok.Flags, TF_AccessSpecifier );
}
forceinline
bool tok_is_attribute(Token tok) {
return bitfield_is_set( u32, tok.Flags, TF_Attribute );
}
forceinline
bool tok_is_operator(Token tok) {
return bitfield_is_set( u32, tok.Flags, TF_Operator );
}
forceinline
bool tok_is_preprocessor(Token tok) {
return bitfield_is_set( u32, tok.Flags, TF_Preprocess );
}
forceinline
bool tok_is_preprocess_cond(Token tok) {
return bitfield_is_set( u32, tok.Flags, TF_Preprocess_Cond );
}
forceinline
bool tok_is_specifier(Token tok) {
return bitfield_is_set( u32, tok.Flags, TF_Specifier );
}
forceinline
bool tok_is_end_definition(Token tok) {
return bitfield_is_set( 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;
};
enum MacroType : u16
{
MT_Expression, // A macro is assumed to be a expression if not resolved.
MT_Statement,
MT_Typename,
MT_Block_Start, // Not Supported yet
MT_Block_End, // Not Supported yet
MT_Case_Statement, // Not Supported yet
MT_UnderlyingType = GEN_U16_MAX,
};
forceinline
TokType macrotype_to_toktype( MacroType type ) {
switch ( type ) {
case MT_Statement : return Tok_Preprocess_Macro_Stmt;
case MT_Expression : return Tok_Preprocess_Macro_Expr;
case MT_Typename : return Tok_Preprocess_Macro_Typename;
}
// All others unsupported for now.
return Tok_Invalid;
}
inline
Str macrotype_to_str( MacroType type )
{
local_persist
Str lookup[] = {
{ "Statement", sizeof("Statement") - 1 },
{ "Expression", sizeof("Expression") - 1 },
{ "Typename", sizeof("Typename") - 1 },
{ "Block_Start", sizeof("Block_Start") - 1 },
{ "Block_End", sizeof("Block_End") - 1 },
{ "Case_Statement", sizeof("Case_Statement") - 1 },
};
local_persist
Str invalid = { "Invalid", sizeof("Invalid") };
if ( type > MT_Case_Statement )
return invalid;
return lookup[ type ];
}
enum EMacroFlags : u16
{
// Macro has parameters (args expected to be passed)
MF_Functional = bit(0),
// Expects to assign a braced scope to its body.
MF_Expects_Body = bit(1),
// lex__eat wil treat this macro as an identifier if the parser attempts to consume it as one.
// This is a kludge because we don't support push/pop macro pragmas rn.
MF_Allow_As_Identifier = bit(2),
// When parsing identifiers, it will allow the consumption of the macro parameters (as its expected to be a part of constructing the identifier)
// Example of a decarator macro from stb_sprintf.h:
// STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char* buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3);
// ^^ STB_SPRINTF_DECORATE is decorating sprintf
MF_Identifier_Decorator = bit(3),
// lex__eat wil treat this macro as an attribute if the parser attempts to consume it as one.
// This a kludge because unreal has a macro that behaves as both a 'statement' and an attribute (UE_DEPRECATED, PRAGMA_ENABLE_DEPRECATION_WARNINGS, etc)
// TODO(Ed): We can keep the MF_Allow_As_Attribute flag for macros, however, we need to add the ability of AST_Attributes to chain themselves.
// Its thats already a thing in the standard language anyway
// & it would allow UE_DEPRECATED, (UE_PROPERTY / UE_FUNCTION) to chain themselves as attributes of a resolved member function/variable definition
MF_Allow_As_Attribute = bit(4),
// When a macro is encountered after attributes and specifiers while parsing a function, or variable:
// It will consume the macro and treat it as resolving the definition.
// (MUST BE OF MT_Statement TYPE)
MF_Allow_As_Definition = bit(5),
// Created for Unreal's PURE_VIRTUAL
MF_Allow_As_Specifier = bit(6),
MF_Null = 0,
MF_UnderlyingType = GEN_U16_MAX,
};
typedef u16 MacroFlags;
struct Macro
{
StrCached Name;
MacroType Type;
MacroFlags Flags;
};
forceinline
b32 macro_is_functional( Macro macro ) {
return bitfield_is_set( b16, macro.Flags, MF_Functional );
}
forceinline
b32 macro_expects_body( Macro macro ) {
return bitfield_is_set( b16, macro.Flags, MF_Expects_Body );
}
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
forceinline b32 is_functional( Macro macro ) { return bitfield_is_set( b16, macro.Flags, MF_Functional ); }
forceinline b32 expects_body ( Macro macro ) { return bitfield_is_set( b16, macro.Flags, MF_Expects_Body ); }
#endif
typedef HashTable(Macro) MacroTable;
#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_DefineParams;
struct AST_Destructor;
struct AST_Enum;
struct AST_Exec;
struct AST_Extern;
struct AST_Include;
struct AST_Friend;
struct AST_Fn;
struct AST_Module;
struct AST_NS;
struct AST_Operator;
struct AST_OpCast;
struct AST_Params;
struct AST_Pragma;
struct AST_PreprocessCond;
struct AST_Specifiers;
#ifdef 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_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_DefineParams* CodeDefineParams;
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;
struct CodeAttributes;
struct CodeComment;
struct CodeClass;
struct CodeConstructor;
struct CodeDefine;
struct CodeDefineParams;
struct CodeDestructor;
struct CodeEnum;
struct CodeExec;
struct CodeExtern;
struct CodeInclude;
struct CodeFriend;
struct CodeFn;
struct CodeModule;
struct CodeNS;
struct CodeOperator;
struct CodeOpCast;
struct CodeParams;
struct CodePreprocessCond;
struct CodePragma;
struct CodeSpecifiers;
#endif
#ifdef 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_Lambda* CodeStmt_Lambda;
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_Lambda;
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 CodeTypename;
struct CodeTypedef;
struct CodeUnion;
struct CodeUsing;
struct CodeVar;
#endif
#if GEN_COMPILER_CPP
template< class Type> forceinline Type tmpl_cast( Code self ) { return * rcast( Type*, & self ); }
#endif
#pragma region Code C-Interface
void code_append (Code code, Code other );
GEN_API Str code_debug_str (Code code);
GEN_API Code code_duplicate (Code code);
Code* code_entry (Code code, u32 idx );
bool code_has_entries (Code code);
bool code_is_body (Code code);
GEN_API bool code_is_equal (Code code, Code other);
bool code_is_valid (Code code);
void code_set_global (Code code);
GEN_API StrBuilder code_to_strbuilder (Code self );
GEN_API void code_to_strbuilder_ref(Code self, StrBuilder* result );
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).
*/
struct Code
{
AST* ast;
# 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_ref(* 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 CodeClass() const;
operator CodeConstructor() const;
operator CodeDefine() const;
operator CodeDefineParams() const;
operator CodeDestructor() const;
operator CodeExec() const;
operator CodeEnum() const;
operator CodeExtern() const;
operator CodeInclude() const;
operator CodeFriend() const;
operator CodeFn() const;
operator CodeModule() const;
operator CodeNS() const;
operator CodeOperator() const;
operator CodeOpCast() const;
operator CodeParams() const;
operator CodePragma() const;
operator CodePreprocessCond() const;
operator CodeSpecifiers() const;
operator CodeStruct() const;
operator CodeTemplate() const;
operator CodeTypename() const;
operator CodeTypedef() const;
operator CodeUnion() const;
operator CodeUsing() const;
operator CodeVar() const;
#undef operator
};
#endif
#pragma region Statics
// Used to identify ASTs that should always be duplicated. (Global constant ASTs)
GEN_API extern Code Code_Global;
// Used to identify invalid generated code.
GEN_API extern Code Code_Invalid;
#pragma endregion Statics
struct Code_POD
{
AST* ast;
};
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.
TODO(Ed): Eventually haven't a transparent AST like this will longer be viable once statements & expressions are in (most likely....)
*/
struct AST
{
union {
struct
{
Code InlineCmt; // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable
Code Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable // TODO(Ed): Parameters can have attributes
Code Specs; // Class, Destructor, Function, Operator, Struct, 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 {
Code Macro; // Parameter
Code BitfieldSize; // Variable (Class/Struct Data Member)
Code Params; // Constructor, Define, Function, Operator, Template, Typename
Code UnderlyingTypeMacro; // Enum
};
union {
Code ArrExpr; // Typename
Code Body; // Class, Constructor, Define, Destructor, Enum, Friend, Function, Namespace, Struct, Union
Code Declaration; // Friend, Template
Code Value; // Parameter, Variable
};
union {
Code NextVar; // Variable
Code SuffixSpecs; // Typename, Function (Thanks Unreal)
Code PostNameMacro; // Only used with parameters for specifically UE_REQUIRES (Thanks Unreal)
};
};
StrCached Content; // Attributes, Comment, Execution, Include
struct {
Specifier ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers
Code NextSpecs; // Specifiers; If ArrSpecs is full, then NextSpecs is used.
};
};
StrCached Name;
union {
Code Prev;
Code Front;
Code Last;
};
union {
Code Next;
Code Back;
};
Token* Token; // Reference to starting token, only available 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" );
#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 NullCode (NullCode_ImplicitCaster{})
#else
#define NullCode nullptr
#endif
/*
______ __ ______ __ ______
/ \ | \ | \ | \ / \
| ▓▓▓▓▓▓\ ______ ____| ▓▓ ______ \▓▓▓▓▓▓_______ _| ▓▓_ ______ ______ | ▓▓▓▓▓▓\ ______ _______ ______
| ▓▓ \▓▓/ \ / ▓▓/ \ | ▓▓ | \| ▓▓ \ / \ / \| ▓▓_ \▓▓| \ / \/ \
| ▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\ | ▓▓ | ▓▓▓▓▓▓▓\\▓▓▓▓▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓ \ \▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\
| ▓▓ __| ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ __| ▓▓ ▓▓ ▓▓ \▓▓ ▓▓▓▓ / ▓▓ ▓▓ | ▓▓ ▓▓
| ▓▓__/ \ ▓▓__/ ▓▓ ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ _| ▓▓_| ▓▓ | ▓▓ | ▓▓| \ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ | ▓▓▓▓▓▓▓ ▓▓_____| ▓▓▓▓▓▓▓▓
\▓▓ ▓▓\▓▓ ▓▓\▓▓ ▓▓\▓▓ \ | ▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \\▓▓ \
\▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓
*/
#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 );
void body_to_strbuilder_ref ( CodeBody body, StrBuilder* result );
GEN_API void body_to_strbuilder_export( CodeBody body, StrBuilder* result );
Code begin_CodeBody( CodeBody body);
Code end_CodeBody ( CodeBody body );
Code next_CodeBody ( CodeBody body, Code entry_iter );
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 );
void define_params_append (CodeDefineParams appendee, CodeDefineParams other );
CodeDefineParams define_params_get (CodeDefineParams params, s32 idx);
bool define_params_has_entries (CodeDefineParams params );
StrBuilder define_params_to_strbuilder (CodeDefineParams params );
GEN_API void define_params_to_strbuilder_ref(CodeDefineParams params, StrBuilder* result );
CodeDefineParams begin_CodeDefineParams(CodeDefineParams params);
CodeDefineParams end_CodeDefineParams (CodeDefineParams params);
CodeDefineParams next_CodeDefineParams (CodeDefineParams params, CodeDefineParams entry_iter);
void params_append (CodeParams appendee, CodeParams other );
CodeParams params_get (CodeParams params, s32 idx);
bool params_has_entries (CodeParams params );
StrBuilder params_to_strbuilder (CodeParams params );
GEN_API void params_to_strbuilder_ref(CodeParams params, StrBuilder* result );
CodeParams begin_CodeParams(CodeParams params);
CodeParams end_CodeParams (CodeParams params);
CodeParams next_CodeParams (CodeParams params, CodeParams entry_iter);
bool specifiers_append (CodeSpecifiers specifiers, Specifier spec);
bool specifiers_has (CodeSpecifiers specifiers, Specifier spec);
s32 specifiers_index_of (CodeSpecifiers specifiers, Specifier spec);
s32 specifiers_remove (CodeSpecifiers specifiers, Specifier to_remove );
StrBuilder specifiers_to_strbuilder (CodeSpecifiers specifiers);
GEN_API void specifiers_to_strbuilder_ref(CodeSpecifiers specifiers, StrBuilder* result);
Specifier* begin_CodeSpecifiers(CodeSpecifiers specifiers);
Specifier* end_CodeSpecifiers (CodeSpecifiers specifiers);
Specifier* next_CodeSpecifiers (CodeSpecifiers specifiers, Specifier* spec_iter);
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);
StrBuilder attributes_to_strbuilder (CodeAttributes attributes);
void attributes_to_strbuilder_ref(CodeAttributes attributes, StrBuilder* result);
StrBuilder comment_to_strbuilder (CodeComment comment );
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 );
StrBuilder exec_to_strbuilder (CodeExec exec);
void exec_to_strbuilder_ref(CodeExec exec, StrBuilder* result);
void extern_to_strbuilder(CodeExtern self, StrBuilder* result);
StrBuilder include_to_strbuilder (CodeInclude self);
void include_to_strbuilder_ref(CodeInclude self, StrBuilder* result);
StrBuilder friend_to_strbuilder (CodeFriend self);
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);
StrBuilder module_to_strbuilder (CodeModule self);
GEN_API void module_to_strbuilder_ref(CodeModule self, StrBuilder* result);
StrBuilder namespace_to_strbuilder (CodeNS self);
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 );
StrBuilder pragma_to_strbuilder (CodePragma self);
void pragma_to_strbuilder_ref(CodePragma self, StrBuilder* result);
GEN_API StrBuilder preprocess_to_strbuilder (CodePreprocessCond cond);
void preprocess_to_strbuilder_if (CodePreprocessCond cond, StrBuilder* result );
void preprocess_to_strbuilder_ifdef (CodePreprocessCond cond, StrBuilder* result );
void preprocess_to_strbuilder_ifndef(CodePreprocessCond cond, StrBuilder* result );
void preprocess_to_strbuilder_elif (CodePreprocessCond cond, StrBuilder* result );
void preprocess_to_strbuilder_else (CodePreprocessCond cond, StrBuilder* result );
void preprocess_to_strbuilder_endif (CodePreprocessCond cond, StrBuilder* result );
StrBuilder template_to_strbuilder (CodeTemplate self);
GEN_API void template_to_strbuilder_ref(CodeTemplate self, StrBuilder* result);
StrBuilder typedef_to_strbuilder (CodeTypedef self);
GEN_API void typedef_to_strbuilder_ref(CodeTypedef self, StrBuilder* result );
StrBuilder typename_to_strbuilder (CodeTypename self);
GEN_API void typename_to_strbuilder_ref(CodeTypename 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);
StrBuilder using_to_strbuilder (CodeUsing op_cast );
GEN_API void using_to_strbuilder_ref(CodeUsing op_cast, StrBuilder* result );
void using_to_strbuilder_ns (CodeUsing op_cast, StrBuilder* result );
StrBuilder var_to_strbuilder (CodeVar self);
GEN_API void var_to_strbuilder_ref(CodeVar self, StrBuilder* result);
// TODO(Ed): Move C-Interface inlines here...
#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); }
#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 );
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 CodeParams
{
#if ! GEN_C_LIKE_CPP
Using_Code( CodeParams );
forceinline void append( CodeParams other ) { return params_append(* this, other); }
forceinline CodeParams get( s32 idx ) { return params_get( * this, idx); }
forceinline bool has_entries() { return params_has_entries(* this); }
forceinline StrBuilder to_strbuilder() { return params_to_strbuilder(* this); }
forceinline void to_strbuilder( StrBuilder& result ) { return params_to_strbuilder_ref(*this, & result); }
#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;
}
CodeParams& operator++();
AST_Params* ast;
};
struct CodeDefineParams
{
#if ! GEN_C_LIKE_CPP
Using_Code( CodeDefineParams );
forceinline void append( CodeDefineParams other ) { return params_append( cast(CodeParams, * this), cast(CodeParams, other)); }
forceinline CodeDefineParams get( s32 idx ) { return (CodeDefineParams) (Code) params_get( cast(CodeParams, * this), idx); }
forceinline bool has_entries() { return params_has_entries( cast(CodeParams, * this)); }
forceinline StrBuilder to_strbuilder() { return define_params_to_strbuilder(* this); }
forceinline void to_strbuilder( StrBuilder& result ) { return define_params_to_strbuilder_ref(* this, & result); }
#endif
Using_CodeOps( CodeDefineParams );
forceinline CodeDefineParams begin() { return (CodeDefineParams) (Code) begin_CodeParams( cast(CodeParams, * this)); }
forceinline CodeDefineParams end() { return (CodeDefineParams) (Code) end_CodeParams( cast(CodeParams, * this)); }
forceinline operator Code() { return { (AST*)ast }; }
forceinline CodeDefineParams operator *() { return * this; } // Required to support for-range iteration.
forceinline AST_DefineParams* operator->() {
GEN_ASSERT(ast);
return ast;
}
forceinline CodeDefineParams& operator++();
AST_DefineParams* ast;
};
struct CodeSpecifiers
{
#if ! GEN_C_LIKE_CPP
Using_Code( CodeSpecifiers );
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;
}
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;
};
#ifdef 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;
};
#ifdef 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 );
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;
};
#undef Define_CodeType
#undef Using_Code
#undef Using_CodeOps
#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 CodeDefineParams () const { return cast(CodeDefineParams, 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 CodeDefineParams () 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 (CodeDefineParams appendee, CodeDefineParams other ) { params_append(cast(CodeParams, appendee), cast(CodeParams, other)); }
forceinline CodeDefineParams get (CodeDefineParams params, s32 idx) { return (CodeDefineParams) (Code) params_get(cast(CodeParams, params), idx); }
forceinline bool has_entries (CodeDefineParams params ) { return params_has_entries(cast(CodeParams, params)); }
forceinline StrBuilder to_strbuilder(CodeDefineParams params ) { return define_params_to_strbuilder(params); }
forceinline void to_strbuilder(CodeDefineParams params, StrBuilder& result ) { return define_params_to_strbuilder_ref(params, & result); }
forceinline void append (CodeParams appendee, CodeParams other ) { return params_append(appendee, other); }
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.
*/
struct AST_Body
{
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");
// TODO(Ed): Support chaining attributes (Use parameter linkage pattern)
struct AST_Attributes
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
StrCached Content;
};
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");
#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(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
StrCached Content;
};
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");
struct AST_Class
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
CodeComment InlineCmt; // Only supported by forward declarations
CodeAttributes Attributes;
CodeSpecifiers Specs; // Support for final
CodeTypename ParentType;
char _PAD_PARAMS_[ sizeof(AST*) ];
CodeBody Body;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
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");
struct AST_Constructor
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
CodeComment InlineCmt; // Only supported by forward declarations
char _PAD_PROPERTIES_ [ sizeof(AST*) * 1 ];
CodeSpecifiers Specs;
Code InitializerList;
CodeParams Params;
Code Body;
char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 2 ];
};
};
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");
struct AST_Define
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
char _PAD_PROPERTIES_ [ sizeof(AST*) * 4 ];
CodeDefineParams Params;
Code Body; // Should be completely serialized for now to a: StrCached Content.
char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 1 ];
};
};
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");
struct AST_DefineParams
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
CodeDefineParams Last;
CodeDefineParams Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
s32 NumEntries;
};
static_assert( sizeof(AST_DefineParams) == sizeof(AST), "ERROR: AST_DefineParams is not the same size as AST");
struct AST_Destructor
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
CodeComment InlineCmt;
char _PAD_PROPERTIES_ [ sizeof(AST*) * 1 ];
CodeSpecifiers Specs;
char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 2 ];
Code Body;
char _PAD_PROPERTIES_3_ [ 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_Destructor) == sizeof(AST), "ERROR: AST_Destructor is not the same size as AST");
struct AST_Enum
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
CodeComment InlineCmt;
CodeAttributes Attributes;
char _PAD_SPEC_ [ sizeof(AST*) ];
CodeTypename UnderlyingType;
Code UnderlyingTypeMacro;
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_Enum) == sizeof(AST), "ERROR: AST_Enum is not the same size as AST");
struct AST_Exec
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
StrCached Content;
};
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");
#ifdef 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(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
char _PAD_PROPERTIES_[ sizeof(AST*) * 5 ];
CodeBody Body;
char _PAD_PROPERTIES_2_[ 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_Extern) == sizeof(AST), "ERROR: AST_Extern is not the same size as AST");
struct AST_Include
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
StrCached Content;
};
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");
struct AST_Friend
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
CodeComment InlineCmt;
char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ];
Code Declaration;
char _PAD_PROPERTIES_2_[ 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_Friend) == sizeof(AST), "ERROR: AST_Friend is not the same size as AST");
struct AST_Fn
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeSpecifiers Specs;
CodeTypename ReturnType;
CodeParams Params;
CodeBody Body;
Code SuffixSpecs; // Thanks Unreal
};
};
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");
struct AST_Module
{
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");
struct AST_NS
{
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*) ];
};
};
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");
struct AST_Operator
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeSpecifiers Specs;
CodeTypename ReturnType;
CodeParams Params;
CodeBody Body;
char _PAD_PROPERTIES_ [ sizeof(AST*) ];
};
};
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
Operator Op;
};
static_assert( sizeof(AST_Operator) == sizeof(AST), "ERROR: AST_Operator is not the same size as AST");
struct AST_OpCast
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
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*) ];
};
};
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");
struct AST_Params
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
// TODO(Ed): Support attributes for parameters (Some prefix macros can be converted to that...)
char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ];
CodeTypename ValueType;
Code Macro;
Code Value;
Code PostNameMacro; // Thanks Unreal
// char _PAD_PROPERTIES_3_[sizeof( AST* )];
};
};
StrCached Name;
CodeParams Last;
CodeParams Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
s32 NumEntries;
};
static_assert( sizeof(AST_Params) == sizeof(AST), "ERROR: AST_Params is not the same size as AST");
struct AST_Pragma
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
StrCached Content;
};
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");
struct AST_PreprocessCond
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
StrCached Content;
};
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");
struct AST_Specifiers
{
Specifier ArrSpecs[ AST_ArrSpecs_Cap ];
CodeSpecifiers NextSpecs;
StrCached Name;
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");
#ifdef 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(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeSpecifiers Specs; // Support for final
CodeTypename ParentType;
char _PAD_PARAMS_[ sizeof(AST*) ];
CodeBody Body;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
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");
struct AST_Template
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ];
CodeParams Params;
Code Declaration;
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_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(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
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
};
};
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
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(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
CodeComment InlineCmt;
char _PAD_PROPERTIES_[ sizeof(AST*) * 2 ];
Code UnderlyingType;
char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ];
};
};
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");
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(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeSpecifiers Specs;
CodeTypename ValueType;
Code BitfieldSize;
Code Value;
CodeVar NextVar;
};
};
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");
#pragma endregion AST Types
#pragma endregion AST
#pragma region Gen Interface
/*
/ \ | \ | \ / \
| ▓▓▓▓▓▓\ ______ _______ \▓▓▓▓▓▓_______ _| ▓▓_ ______ ______ | ▓▓▓▓▓▓\ ______ _______ ______
| ▓▓ __\▓▓/ \| \ | ▓▓ | \| ▓▓ \ / \ / \| ▓▓_ \▓▓| \ / \/ \
| ▓▓| \ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓\ | ▓▓ | ▓▓▓▓▓▓▓\\▓▓▓▓▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓ \ \▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\
| ▓▓ \▓▓▓▓ ▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ __| ▓▓ ▓▓ ▓▓ \▓▓ ▓▓▓▓ / ▓▓ ▓▓ | ▓▓ ▓▓
| ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ _| ▓▓_| ▓▓ | ▓▓ | ▓▓| \ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ | ▓▓▓▓▓▓▓ ▓▓_____| ▓▓▓▓▓▓▓▓
\▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ | ▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \\▓▓ \
\▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓
*/
#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.
// Initalization config
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_LexerTokens;
u32 SizePer_StringArena;
u32 InitSize_StrCacheTable;
u32 InitSize_MacrosTable;
// 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.
MacroTable Macros;
// 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;
StringTable token_fmt_map;
// Array(Token) LexerTokens;
Array(Pool) CodePools;
Array(Arena) StringArenas;
StringTable StrCache;
// TODO(Ed): This needs to be just handled by a parser context
Array(Token) Lexer_Tokens;
// TODO(Ed): Active parse context vs a parse result need to be separated conceptually
ParseContext parser;
// TODO(Ed): Formatting - This will eventually be in a separate struct when in the process of serialization of the builder.
s32 temp_serialize_indent;
};
// TODO(Ed): Eventually this library should opt out of an implicit context for baseline implementation
// This would automatically make it viable for multi-threaded purposes among other things
// An implicit context interface will be provided instead as wrapper procedures as convience.
GEN_API extern Context* _ctx;
// 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.
GEN_API void deinit(Context* ctx);
// Retrieves the active context (not usually needed, but here in case...)
GEN_API Context* get_context();
// Clears the allocations, but doesn't free the memoery, then calls init() again.
// Ease of use.
GEN_API void reset(Context* ctx);
GEN_API void set_context(Context* ctx);
// Mostly intended for the parser
GEN_API Macro* lookup_macro( Str Name );
// Alternative way to add a preprocess define entry for the lexer & parser to utilize
// if the user doesn't want to use def_define
// Macros are tracked by name so if the name already exists the entry will be overwritten.
GEN_API void register_macro( Macro macro );
// Ease of use batch registration
GEN_API void register_macros( s32 num, ... );
GEN_API void register_macros_arr( s32 num, Macro* macros );
#if GEN_COMPILER_CPP
forceinline void register_macros( s32 num, Macro* macros ) { return register_macros_arr(num, macros); }
#endif
// Used internally to retrive or make string allocations.
// Strings are stored in a series of string arenas of fixed size (SizePer_StringArena)
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.
*/
GEN_API Code make_code();
// Set these before calling gen's init() procedure.
#pragma region Upfront
GEN_API CodeAttributes def_attributes( Str content );
GEN_API CodeComment def_comment ( Str content );
struct Opts_def_struct {
CodeBody body;
CodeTypename parent;
AccessSpec parent_access;
CodeAttributes attributes;
CodeTypename* interfaces;
s32 num_interfaces;
CodeSpecifiers specifiers; // Only used for final specifier for now.
ModuleFlag mflags;
};
GEN_API CodeClass def_class( Str name, Opts_def_struct opts GEN_PARAM_DEFAULT );
struct Opts_def_constructor {
CodeParams params;
Code initializer_list;
Code body;
};
GEN_API CodeConstructor def_constructor( Opts_def_constructor opts GEN_PARAM_DEFAULT );
struct Opts_def_define {
CodeDefineParams params;
Str content;
MacroFlags flags;
b32 dont_register_to_preprocess_macros;
};
GEN_API CodeDefine def_define( Str name, MacroType type, Opts_def_define opts GEN_PARAM_DEFAULT );
struct Opts_def_destructor {
Code body;
CodeSpecifiers specifiers;
};
GEN_API CodeDestructor def_destructor( Opts_def_destructor opts GEN_PARAM_DEFAULT );
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 );
GEN_API CodeExec def_execution ( Str content );
GEN_API CodeExtern def_extern_link( Str name, CodeBody body );
GEN_API CodeFriend def_friend ( Code code );
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 );
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 );
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 );
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 );
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 );
GEN_API CodePreprocessCond def_preprocess_cond( EPreprocessCond type, Str content );
GEN_API CodeSpecifiers def_specifier( Specifier specifier );
GEN_API CodeStruct def_struct( Str name, Opts_def_struct opts GEN_PARAM_DEFAULT );
struct Opts_def_template { ModuleFlag mflags; };
GEN_API CodeTemplate def_template( CodeParams params, Code definition, Opts_def_template opts GEN_PARAM_DEFAULT );
struct Opts_def_type {
ETypenameTag type_tag;
Code array_expr;
CodeSpecifiers specifiers;
CodeAttributes attributes;
};
GEN_API CodeTypename def_type( Str name, Opts_def_type opts GEN_PARAM_DEFAULT );
struct Opts_def_typedef {
CodeAttributes attributes;
ModuleFlag mflags;
};
GEN_API CodeTypedef def_typedef( Str name, Code type, Opts_def_typedef opts GEN_PARAM_DEFAULT );
struct Opts_def_union {
CodeAttributes attributes;
ModuleFlag mflags;
};
GEN_API CodeUnion def_union( Str name, CodeBody body, Opts_def_union opts GEN_PARAM_DEFAULT );
struct Opts_def_using {
CodeAttributes attributes;
ModuleFlag mflags;
};
GEN_API CodeUsing def_using( Str name, CodeTypename type, Opts_def_using opts GEN_PARAM_DEFAULT );
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( 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.
GEN_API CodeBody def_class_body ( s32 num, ... );
GEN_API CodeBody def_class_body_arr ( s32 num, Code* codes );
GEN_API CodeDefineParams def_define_params ( s32 num, ... );
GEN_API CodeDefineParams def_define_params_arr ( s32 num, CodeDefineParams* codes );
GEN_API CodeBody def_enum_body ( s32 num, ... );
GEN_API CodeBody def_enum_body_arr ( s32 num, Code* codes );
GEN_API CodeBody def_export_body ( s32 num, ... );
GEN_API CodeBody def_export_body_arr ( s32 num, Code* codes);
GEN_API CodeBody def_extern_link_body ( s32 num, ... );
GEN_API CodeBody def_extern_link_body_arr ( s32 num, Code* codes );
GEN_API CodeBody def_function_body ( s32 num, ... );
GEN_API CodeBody def_function_body_arr ( s32 num, Code* codes );
GEN_API CodeBody def_global_body ( s32 num, ... );
GEN_API CodeBody def_global_body_arr ( s32 num, Code* codes );
GEN_API CodeBody def_namespace_body ( s32 num, ... );
GEN_API CodeBody def_namespace_body_arr ( s32 num, Code* codes );
GEN_API CodeParams def_params ( s32 num, ... );
GEN_API CodeParams def_params_arr ( s32 num, CodeParams* params );
GEN_API CodeSpecifiers def_specifiers ( s32 num, ... );
GEN_API CodeSpecifiers def_specifiers_arr ( s32 num, Specifier* specs );
GEN_API CodeBody def_struct_body ( s32 num, ... );
GEN_API CodeBody def_struct_body_arr ( s32 num, Code* codes );
GEN_API CodeBody def_union_body ( s32 num, ... );
GEN_API CodeBody def_union_body_arr ( s32 num, Code* codes );
#if GEN_COMPILER_CPP
forceinline CodeBody def_class_body ( s32 num, Code* codes ) { return def_class_body_arr(num, codes); }
forceinline CodeDefineParams def_define_params ( s32 num, CodeDefineParams* codes ) { return def_define_params_arr(num, codes); }
forceinline CodeBody def_enum_body ( s32 num, Code* codes ) { return def_enum_body_arr(num, codes); }
forceinline CodeBody def_export_body ( s32 num, Code* codes) { return def_export_body_arr(num, codes); }
forceinline CodeBody def_extern_link_body( s32 num, Code* codes ) { return def_extern_link_body_arr(num, codes); }
forceinline CodeBody def_function_body ( s32 num, Code* codes ) { return def_function_body_arr(num, codes); }
forceinline CodeBody def_global_body ( s32 num, Code* codes ) { return def_global_body_arr(num, codes); }
forceinline CodeBody def_namespace_body ( s32 num, Code* codes ) { return def_namespace_body_arr(num, codes); }
forceinline CodeParams def_params ( s32 num, CodeParams* params ) { return def_params_arr(num, params); }
forceinline CodeSpecifiers def_specifiers ( s32 num, Specifier* specs ) { return def_specifiers_arr(num, specs); }
forceinline CodeBody def_struct_body ( s32 num, Code* codes ) { return def_struct_body_arr(num, codes); }
forceinline CodeBody def_union_body ( s32 num, Code* codes ) { return def_union_body_arr(num, codes); }
#endif
#pragma endregion Upfront
#pragma region Parsing
#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<Token> Tokens;
Array<Error> 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 CodeDefine parse_define ( Str define_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
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.
Str token_fmt_impl( ssize, ... );
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.
# if GEN_COMPILER_C
# define name( Id_ ) (Str){ stringize(Id_), sizeof(stringize( Id_ )) - 1 }
# else
# define name( Id_ ) Str { stringize(Id_), sizeof(stringize( Id_ )) - 1 }
# endif
#endif
#ifndef code
// Same as name just used to indicate intention of literal for code instead of names.
# if GEN_COMPILER_C
# define code( ... ) (Str){ stringize( __VA_ARGS__ ), sizeof(stringize(__VA_ARGS__)) - 1 }
# else
# define code( ... ) Str { stringize( __VA_ARGS__ ), sizeof(stringize(__VA_ARGS__)) - 1 }
# endif
#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 <type> <name> <name>;
Will have a token_fmt arguments populated with:
"type", str_for_type,
"name", str_for_name,
and:
stringize( typedef <type> <name> <name>; )
-----------------------------------------------------------
So the full call for this example would be:
token_fmt(
"type", str_for_type
, "name", str_for_name
, stringize(
typedef <type> <name> <name>
));
!----------------------------------------------------------
! 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 Constants
// Predefined typename codes. Are set to readonly and are setup during gen::init()
GEN_API extern Macro enum_underlying_macro;
GEN_API extern Code access_public;
GEN_API extern Code access_protected;
GEN_API extern Code access_private;
GEN_API extern CodeAttributes attrib_api_export;
GEN_API extern CodeAttributes attrib_api_import;
GEN_API extern Code module_global_fragment;
GEN_API extern Code module_private_fragment;
GEN_API extern Code fmt_newline;
GEN_API extern CodePragma pragma_once;
GEN_API extern CodeParams param_varadic;
GEN_API extern CodePreprocessCond preprocess_else;
GEN_API extern CodePreprocessCond preprocess_endif;
GEN_API extern CodeSpecifiers spec_const;
GEN_API extern CodeSpecifiers spec_consteval;
GEN_API extern CodeSpecifiers spec_constexpr;
GEN_API extern CodeSpecifiers spec_constinit;
GEN_API extern CodeSpecifiers spec_extern_linkage;
GEN_API extern CodeSpecifiers spec_final;
GEN_API extern CodeSpecifiers spec_forceinline;
GEN_API extern CodeSpecifiers spec_global;
GEN_API extern CodeSpecifiers spec_inline;
GEN_API extern CodeSpecifiers spec_internal_linkage;
GEN_API extern CodeSpecifiers spec_local_persist;
GEN_API extern CodeSpecifiers spec_mutable;
GEN_API extern CodeSpecifiers spec_neverinline;
GEN_API extern CodeSpecifiers spec_noexcept;
GEN_API extern CodeSpecifiers spec_override;
GEN_API extern CodeSpecifiers spec_ptr;
GEN_API extern CodeSpecifiers spec_pure;
GEN_API extern CodeSpecifiers spec_ref;
GEN_API extern CodeSpecifiers spec_register;
GEN_API extern CodeSpecifiers spec_rvalue;
GEN_API extern CodeSpecifiers spec_static_member;
GEN_API extern CodeSpecifiers spec_thread_local;
GEN_API extern CodeSpecifiers spec_virtual;
GEN_API extern CodeSpecifiers spec_volatile;
GEN_API extern CodeTypename t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance)
GEN_API extern CodeTypename t_auto;
GEN_API extern CodeTypename t_void;
GEN_API extern CodeTypename t_int;
GEN_API extern CodeTypename t_bool;
GEN_API extern CodeTypename t_char;
GEN_API extern CodeTypename t_wchar_t;
GEN_API extern CodeTypename t_class;
GEN_API extern CodeTypename t_typename;
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
GEN_API extern CodeTypename t_b32;
GEN_API extern CodeTypename t_s8;
GEN_API extern CodeTypename t_s16;
GEN_API extern CodeTypename t_s32;
GEN_API extern CodeTypename t_s64;
GEN_API extern CodeTypename t_u8;
GEN_API extern CodeTypename t_u16;
GEN_API extern CodeTypename t_u32;
GEN_API extern CodeTypename t_u64;
GEN_API extern CodeTypename t_ssize;
GEN_API extern CodeTypename t_usize;
GEN_API extern CodeTypename t_f32;
GEN_API extern CodeTypename t_f64;
#endif
#pragma endregion Constants
#pragma region Inlines
#pragma region Serialization
inline
StrBuilder attributes_to_strbuilder(CodeAttributes attributes) {
GEN_ASSERT(attributes);
char* raw = ccast(char*, str_duplicate( attributes->Content, get_context()->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);
}
inline
StrBuilder comment_to_strbuilder(CodeComment comment) {
GEN_ASSERT(comment);
char* raw = ccast(char*, str_duplicate( comment->Content, get_context()->Allocator_Temp ).Ptr);
StrBuilder result = { raw };
return result;
}
inline
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_ref(curr, result);
// strbuilder_append_fmt( result, "%SB", code_to_strbuilder(curr) );
curr = curr->Next;
}
}
inline
void comment_to_strbuilder_ref(CodeComment comment, StrBuilder* result) {
GEN_ASSERT(comment);
GEN_ASSERT(result);
strbuilder_append_str(result, comment->Content);
}
inline
StrBuilder define_to_strbuilder(CodeDefine define)
{
GEN_ASSERT(define);
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 512 );
define_to_strbuilder_ref(define, & result);
return result;
}
inline
StrBuilder define_params_to_strbuilder(CodeDefineParams params)
{
GEN_ASSERT(params);
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 );
define_params_to_strbuilder_ref( params, & result );
return result;
}
inline
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;
}
inline
void exec_to_strbuilder_ref(CodeExec exec, StrBuilder* result) {
GEN_ASSERT(exec);
GEN_ASSERT(result);
strbuilder_append_str(result, exec->Content);
}
inline
void extern_to_strbuilder(CodeExtern self, StrBuilder* result )
{
GEN_ASSERT(self);
GEN_ASSERT(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 );
}
inline
StrBuilder friend_to_strbuilder(CodeFriend self)
{
GEN_ASSERT(self);
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 256 );
friend_to_strbuilder_ref( self, & result );
return result;
}
inline
void friend_to_strbuilder_ref(CodeFriend self, StrBuilder* result )
{
GEN_ASSERT(self);
GEN_ASSERT(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"));
}
inline
StrBuilder include_to_strbuilder(CodeInclude include)
{
GEN_ASSERT(include);
return strbuilder_fmt_buf( _ctx->Allocator_Temp, "#include %S\n", include->Content );
}
inline
void include_to_strbuilder_ref( CodeInclude include, StrBuilder* result )
{
GEN_ASSERT(include);
GEN_ASSERT(result);
strbuilder_append_fmt( result, "#include %S\n", include->Content );
}
inline
StrBuilder module_to_strbuilder(CodeModule self)
{
GEN_ASSERT(self);
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 64 );
module_to_strbuilder_ref( self, & result );
return result;
}
inline
StrBuilder namespace_to_strbuilder(CodeNS self)
{
GEN_ASSERT(self);
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 512 );
namespace_to_strbuilder_ref( self, & result );
return result;
}
inline
void namespace_to_strbuilder_ref(CodeNS self, StrBuilder* result )
{
GEN_ASSERT(self);
GEN_ASSERT(result);
if ( bitfield_is_set( 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) );
}
inline
StrBuilder params_to_strbuilder(CodeParams self)
{
GEN_ASSERT(self);
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 );
params_to_strbuilder_ref( self, & result );
return result;
}
inline
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;
}
inline
void pragma_to_strbuilder_ref(CodePragma self, StrBuilder* result )
{
GEN_ASSERT(self);
GEN_ASSERT(result);
strbuilder_append_fmt( result, "#pragma %S\n", self->Content );
}
inline
void preprocess_to_strbuilder_if(CodePreprocessCond cond, StrBuilder* result )
{
GEN_ASSERT(cond);
GEN_ASSERT(result);
strbuilder_append_fmt( result, "#if %S", cond->Content );
}
inline
void preprocess_to_strbuilder_ifdef(CodePreprocessCond cond, StrBuilder* result )
{
GEN_ASSERT(cond);
GEN_ASSERT(result);
strbuilder_append_fmt( result, "#ifdef %S\n", cond->Content );
}
inline
void preprocess_to_strbuilder_ifndef(CodePreprocessCond cond, StrBuilder* result )
{
GEN_ASSERT(cond);
GEN_ASSERT(result);
strbuilder_append_fmt( result, "#ifndef %S", cond->Content );
}
inline
void preprocess_to_strbuilder_elif(CodePreprocessCond cond, StrBuilder* result )
{
GEN_ASSERT(cond);
GEN_ASSERT(result);
strbuilder_append_fmt( result, "#elif %S\n", cond->Content );
}
inline
void preprocess_to_strbuilder_else(CodePreprocessCond cond, StrBuilder* result )
{
GEN_ASSERT(cond);
GEN_ASSERT(result);
strbuilder_append_str( result, txt("#else\n") );
}
inline
void preprocess_to_strbuilder_endif(CodePreprocessCond cond, StrBuilder* result )
{
GEN_ASSERT(cond);
GEN_ASSERT(result);
strbuilder_append_str( result, txt("#endif\n") );
}
inline
StrBuilder specifiers_to_strbuilder(CodeSpecifiers self)
{
GEN_ASSERT(self);
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 64 );
specifiers_to_strbuilder_ref( self, & result );
return result;
}
inline
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;
}
inline
StrBuilder typedef_to_strbuilder(CodeTypedef self)
{
GEN_ASSERT(self);
StrBuilder result = strbuilder_make_reserve( _ctx->Allocator_Temp, 128 );
typedef_to_strbuilder_ref( self, & result );
return result;
}
inline
StrBuilder typename_to_strbuilder(CodeTypename self)
{
GEN_ASSERT(self);
StrBuilder result = strbuilder_make_str( _ctx->Allocator_Temp, txt("") );
typename_to_strbuilder_ref( self, & result );
return result;
}
inline
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;
}
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 $S; %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( get_context()->Allocator_Temp, 256 );
var_to_strbuilder_ref( self, & result );
return result;
}
#pragma endregion Serialization
#pragma region Code
inline
void code_append( Code self, Code other )
{
GEN_ASSERT(self);
GEN_ASSERT(other);
GEN_ASSERT_MSG(self != other, "Attempted to recursively append Code AST to itself.");
if ( other->Parent != nullptr )
other = code_duplicate(other);
other->Parent = self;
if ( self->Front == nullptr )
{
self->Front = other;
self->Back = other;
self->NumEntries++;
return;
}
Code
Current = self->Back;
Current->Next = other;
other->Prev = Current;
self->Back = other;
self->NumEntries++;
}
inline
bool code_is_body(Code self)
{
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);
current = & ( * current )->Next;
idx--;
}
return rcast( Code*, current);
}
forceinline
bool code_is_valid(Code self)
{
GEN_ASSERT(self);
return self != nullptr && self->Type != CT_Invalid;
}
forceinline
bool code_has_entries(Code self)
{
GEN_ASSERT(self);
return self->NumEntries > 0;
}
forceinline
void code_set_global(Code self)
{
if ( self == nullptr )
{
log_failure("Code::set_global: Cannot set code as global, AST is null!");
return;
}
self->Parent = Code_Global;
}
#if GEN_COMPILER_CPP
forceinline
Code& Code::operator ++()
{
if ( ast )
ast = ast->Next.ast;
return * this;
}
#endif
forceinline
Str code_type_str(Code self)
{
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.
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->Next != nullptr )
{
possible_slot = cast(CodeTypename, possible_slot->Next);
}
possible_slot->Next = cast(Code, type);
}
#pragma endregion CodeClass
#pragma region CodeParams
inline
void params_append( CodeParams appendee, CodeParams other )
{
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 != nullptr )
entry = code_duplicate( entry );
entry->Parent = self;
if ( self->Last == nullptr )
{
self->Last = entry;
self->Next = entry;
self->NumEntries++;
return;
}
self->Last->Next = entry;
self->Last = entry;
self->NumEntries++;
}
inline
CodeParams params_get(CodeParams self, s32 idx )
{
GEN_ASSERT(self);
CodeParams param = self;
do
{
if ( ++ param != nullptr )
return NullCode;
param = cast(CodeParams, cast(Code, param)->Next);
}
while ( --idx );
return param;
}
forceinline
bool params_has_entries(CodeParams self)
{
GEN_ASSERT(self);
return self->NumEntries > 0;
}
#if GEN_COMPILER_CPP
forceinline
CodeParams& CodeParams::operator ++()
{
* this = ast->Next;
return * this;
}
#endif
forceinline
CodeParams begin_CodeParams(CodeParams params)
{
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 CodeDefineParams
forceinline void define_params_append (CodeDefineParams appendee, CodeDefineParams other ) { params_append( cast(CodeParams, appendee), cast(CodeParams, other) ); }
forceinline CodeDefineParams define_params_get (CodeDefineParams self, s32 idx ) { return (CodeDefineParams) (Code) params_get( cast(CodeParams, self), idx); }
forceinline bool define_params_has_entries(CodeDefineParams self) { return params_has_entries( cast(CodeParams, self)); }
forceinline CodeDefineParams begin_CodeDefineParams(CodeDefineParams params) { return (CodeDefineParams) (Code) begin_CodeParams( cast(CodeParams, (Code)params)); }
forceinline CodeDefineParams end_CodeDefineParams (CodeDefineParams params) { return (CodeDefineParams) (Code) end_CodeParams ( cast(CodeParams, (Code)params)); }
forceinline CodeDefineParams next_CodeDefineParams (CodeDefineParams params, CodeDefineParams entry_iter) { return (CodeDefineParams) (Code) next_CodeParams ( cast(CodeParams, (Code)params), cast(CodeParams, (Code)entry_iter)); }
#if GEN_COMPILER_CPP
forceinline
CodeDefineParams& CodeDefineParams::operator ++()
{
* this = ast->Next;
return * this;
}
#endif
#pragma endregion CodeDefineParams
#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
bool specifiers_has(CodeSpecifiers self, Specifier spec)
{
GEN_ASSERT(self != nullptr);
for ( s32 idx = 0; idx < self->NumEntries; idx++ ) {
if ( self->ArrSpecs[ idx ] == spec )
return true;
}
return false;
}
inline
s32 specifiers_index_of(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.
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->Next != nullptr )
{
possible_slot = cast(CodeTypename, possible_slot->Next);
}
possible_slot->Next = cast(Code, type);
}
#pragma endregion Code
#pragma region Interface
inline
CodeBody def_body( CodeType type )
{
switch ( type )
{
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", codetype_to_str(type).Ptr );
return (CodeBody)Code_Invalid;
}
Code
result = make_code();
result->Type = type;
return (CodeBody)result;
}
inline
Str token_fmt_impl( ssize num, ... )
{
local_persist thread_local
char buf[GEN_PRINTF_MAXLEN] = { 0 };
mem_set( buf, 0, GEN_PRINTF_MAXLEN );
va_list va;
va_start(va, num );
ssize result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va);
va_end(va);
Str str = { buf, result };
return str;
}
#pragma endregion Interface
#pragma region generated code inline implementation
inline Code& Code::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline Code::operator bool()
{
return ast != nullptr;
}
inline CodeBody& CodeBody::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeBody::operator bool()
{
return ast != nullptr;
}
inline CodeAttributes& CodeAttributes::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeAttributes::operator bool()
{
return ast != nullptr;
}
inline CodeAttributes::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Attributes* CodeAttributes::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeComment& CodeComment::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeComment::operator bool()
{
return ast != nullptr;
}
inline CodeComment::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Comment* CodeComment::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeConstructor& CodeConstructor::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeConstructor::operator bool()
{
return ast != nullptr;
}
inline CodeConstructor::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Constructor* CodeConstructor::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeClass& CodeClass::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeClass::operator bool()
{
return ast != nullptr;
}
inline CodeDefine& CodeDefine::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeDefine::operator bool()
{
return ast != nullptr;
}
inline CodeDefine::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Define* CodeDefine::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeDefineParams& CodeDefineParams::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeDefineParams::operator bool()
{
return ast != nullptr;
}
inline CodeDestructor& CodeDestructor::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeDestructor::operator bool()
{
return ast != nullptr;
}
inline CodeDestructor::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Destructor* CodeDestructor::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeEnum& CodeEnum::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeEnum::operator bool()
{
return ast != nullptr;
}
inline CodeEnum::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Enum* CodeEnum::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeExec& CodeExec::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeExec::operator bool()
{
return ast != nullptr;
}
inline CodeExec::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Exec* CodeExec::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeExtern& CodeExtern::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeExtern::operator bool()
{
return ast != nullptr;
}
inline CodeExtern::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Extern* CodeExtern::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeFriend& CodeFriend::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeFriend::operator bool()
{
return ast != nullptr;
}
inline CodeFriend::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Friend* CodeFriend::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeFn& CodeFn::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeFn::operator bool()
{
return ast != nullptr;
}
inline CodeFn::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Fn* CodeFn::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeInclude& CodeInclude::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeInclude::operator bool()
{
return ast != nullptr;
}
inline CodeInclude::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Include* CodeInclude::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeModule& CodeModule::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeModule::operator bool()
{
return ast != nullptr;
}
inline CodeModule::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Module* CodeModule::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeNS& CodeNS::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeNS::operator bool()
{
return ast != nullptr;
}
inline CodeNS::operator Code()
{
return *rcast(Code*, this);
}
inline AST_NS* CodeNS::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeOperator& CodeOperator::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeOperator::operator bool()
{
return ast != nullptr;
}
inline CodeOperator::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Operator* CodeOperator::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeOpCast& CodeOpCast::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeOpCast::operator bool()
{
return ast != nullptr;
}
inline CodeOpCast::operator Code()
{
return *rcast(Code*, this);
}
inline AST_OpCast* CodeOpCast::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeParams& CodeParams::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeParams::operator bool()
{
return ast != nullptr;
}
inline CodePragma& CodePragma::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodePragma::operator bool()
{
return ast != nullptr;
}
inline CodePragma::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Pragma* CodePragma::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodePreprocessCond& CodePreprocessCond::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodePreprocessCond::operator bool()
{
return ast != nullptr;
}
inline CodePreprocessCond::operator Code()
{
return *rcast(Code*, this);
}
inline AST_PreprocessCond* CodePreprocessCond::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeSpecifiers& CodeSpecifiers::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeSpecifiers::operator bool()
{
return ast != nullptr;
}
inline CodeStruct& CodeStruct::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeStruct::operator bool()
{
return ast != nullptr;
}
inline CodeTemplate& CodeTemplate::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeTemplate::operator bool()
{
return ast != nullptr;
}
inline CodeTemplate::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Template* CodeTemplate::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeTypename& CodeTypename::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeTypename::operator bool()
{
return ast != nullptr;
}
inline CodeTypename::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Typename* CodeTypename::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeTypedef& CodeTypedef::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeTypedef::operator bool()
{
return ast != nullptr;
}
inline CodeTypedef::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Typedef* CodeTypedef::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeUnion& CodeUnion::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeUnion::operator bool()
{
return ast != nullptr;
}
inline CodeUnion::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Union* CodeUnion::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeUsing& CodeUsing::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeUsing::operator bool()
{
return ast != nullptr;
}
inline CodeUsing::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Using* CodeUsing::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
inline CodeVar& CodeVar::operator=(Code other)
{
if (other.ast != nullptr && other->Parent != nullptr)
{
ast = rcast(decltype(ast), code_duplicate(other).ast);
ast->Parent = { nullptr };
}
ast = rcast(decltype(ast), other.ast);
return *this;
}
inline CodeVar::operator bool()
{
return ast != nullptr;
}
inline CodeVar::operator Code()
{
return *rcast(Code*, this);
}
inline AST_Var* CodeVar::operator->()
{
if (ast == nullptr)
{
log_failure("Attempt to dereference a nullptr!\n");
return nullptr;
}
return ast;
}
#pragma endregion generated code inline implementation
#pragma region generated AST/Code cast implementation
GEN_OPTIMIZE_MAPPINGS_BEGIN
forceinline Code::operator CodeBody() const
{
return { (AST_Body*)ast };
}
forceinline Code::operator CodeAttributes() const
{
return { (AST_Attributes*)ast };
}
forceinline Code::operator CodeComment() const
{
return { (AST_Comment*)ast };
}
forceinline Code::operator CodeConstructor() const
{
return { (AST_Constructor*)ast };
}
forceinline Code::operator CodeClass() const
{
return { (AST_Class*)ast };
}
forceinline Code::operator CodeDefine() const
{
return { (AST_Define*)ast };
}
forceinline Code::operator CodeDefineParams() const
{
return { (AST_DefineParams*)ast };
}
forceinline Code::operator CodeDestructor() const
{
return { (AST_Destructor*)ast };
}
forceinline Code::operator CodeEnum() const
{
return { (AST_Enum*)ast };
}
forceinline Code::operator CodeExec() const
{
return { (AST_Exec*)ast };
}
forceinline Code::operator CodeExtern() const
{
return { (AST_Extern*)ast };
}