mirror of
https://github.com/Ed94/gencpp.git
synced 2024-12-22 15:54:45 -08:00
WIP: Design is almost done, impl this weekend.
This commit is contained in:
parent
d93fd462e1
commit
a4cb0c12ef
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -7,6 +7,7 @@
|
|||||||
"utility": "cpp",
|
"utility": "cpp",
|
||||||
"xtr1common": "cpp",
|
"xtr1common": "cpp",
|
||||||
"xutility": "cpp",
|
"xutility": "cpp",
|
||||||
"initializer_list": "cpp"
|
"initializer_list": "cpp",
|
||||||
|
"table.h": "c"
|
||||||
}
|
}
|
||||||
}
|
}
|
44
Readme.md
44
Readme.md
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
An attempt at simple staged metaprogramming for c/c++.
|
An attempt at simple staged metaprogramming for c/c++.
|
||||||
|
|
||||||
This library is intended for small-to midsize projects.
|
This library is intended for small-to midsized projects.
|
||||||
|
|
||||||
### TOC
|
### TOC
|
||||||
|
|
||||||
@ -174,20 +174,27 @@ The construction will fail and return InvalidCode otherwise.
|
|||||||
|
|
||||||
Interface :
|
Interface :
|
||||||
|
|
||||||
* def_forward_decl
|
|
||||||
* def_class
|
* def_class
|
||||||
|
* def_class_body
|
||||||
|
* def_class_fwd
|
||||||
|
* def_enum
|
||||||
|
* def_enum_class
|
||||||
|
* def_enum_body
|
||||||
* def_global_body
|
* def_global_body
|
||||||
* def_proc
|
|
||||||
* def_proc_body
|
|
||||||
* def_namespace
|
* def_namespace
|
||||||
* def_namespace_body
|
* def_namespace_body
|
||||||
|
* def_operator
|
||||||
|
* def_operator_fwd
|
||||||
* def_param
|
* def_param
|
||||||
* def_params
|
* def_params
|
||||||
* def_operator
|
* def_proc
|
||||||
|
* def_proc_body
|
||||||
|
* def_proc_fwd
|
||||||
* def_specifier
|
* def_specifier
|
||||||
* def_specifiers
|
* def_specifiers
|
||||||
* def_struct
|
* def_struct
|
||||||
* def_struct_body
|
* def_struct_body
|
||||||
|
* def_struct_fwd
|
||||||
* def_variable
|
* def_variable
|
||||||
* def_type
|
* def_type
|
||||||
* def_using
|
* def_using
|
||||||
@ -206,19 +213,20 @@ Code ASTs may be explictly validated at anytime using Code's check() member func
|
|||||||
|
|
||||||
Interface :
|
Interface :
|
||||||
|
|
||||||
* make_forward_decl
|
|
||||||
* make_class
|
* make_class
|
||||||
|
* make_enum
|
||||||
|
* make_enum_class
|
||||||
|
* make_fwd
|
||||||
* make_global_body
|
* make_global_body
|
||||||
* make_proc
|
|
||||||
* make_namespace
|
* make_namespace
|
||||||
* make_params
|
|
||||||
* make_operator
|
* make_operator
|
||||||
|
* make_params
|
||||||
|
* make_proc
|
||||||
* make_specifiers
|
* make_specifiers
|
||||||
* make_struct
|
* make_struct
|
||||||
* make_variable
|
* make_variable
|
||||||
* make_type
|
* make_type
|
||||||
* make_using
|
* make_using
|
||||||
* make_using_namespace
|
|
||||||
|
|
||||||
### Parse construction
|
### Parse construction
|
||||||
|
|
||||||
@ -226,19 +234,29 @@ A string provided to the API is parsed for the intended language construct.
|
|||||||
|
|
||||||
Interface :
|
Interface :
|
||||||
|
|
||||||
* parse_forward_decl
|
|
||||||
* parse_class
|
* parse_class
|
||||||
* parse_glboal_body
|
* parse_classes
|
||||||
* parse_proc
|
* parse_class_fwd
|
||||||
|
* parse_classes_fwd
|
||||||
|
* parse_enum
|
||||||
|
* parse_enums
|
||||||
|
* parse_global_body
|
||||||
* parse_namespace
|
* parse_namespace
|
||||||
|
* parse_namespaces
|
||||||
* parse_params
|
* parse_params
|
||||||
|
* parse_proc
|
||||||
|
* parse_procs
|
||||||
* parse_operator
|
* parse_operator
|
||||||
|
* parse_operators
|
||||||
* parse_specifiers
|
* parse_specifiers
|
||||||
* parse_struct
|
* parse_struct
|
||||||
|
* parse_strucs
|
||||||
* parse_variable
|
* parse_variable
|
||||||
|
* parse_variables
|
||||||
* parse_type
|
* parse_type
|
||||||
|
* parse_types
|
||||||
* parse_using
|
* parse_using
|
||||||
* parse_using
|
* parse_usings
|
||||||
|
|
||||||
The parse API treats any execution scope definitions with no validation and are turned into untyped Code ASTs.
|
The parse API treats any execution scope definitions with no validation and are turned into untyped Code ASTs.
|
||||||
This includes the assignmetn of variables; due to the library not yet supporting c/c++ expression parsing.
|
This includes the assignmetn of variables; due to the library not yet supporting c/c++ expression parsing.
|
||||||
|
@ -124,5 +124,7 @@ sw token_fmt_va( char* buf, uw buf_size, char const* fmt, s32 num_tokens, va_lis
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tokmap_clear( & tok_map );
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -73,17 +73,17 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define bit( Value_ ) ( 1 << Value_ )
|
#define bit( Value_ ) ( 1 << Value_ )
|
||||||
#define bitfield_is_equal( Field_, Mask_ ) ( ( Mask_ & Field_ ) == Mask_ )
|
#define bitfield_is_equal( Field_, Mask_ ) ( ( (Mask_) & (Field_) ) == (Mask_) )
|
||||||
#define ct constexpr
|
#define ct constexpr
|
||||||
#define forceinline ZPL_ALWAYS_INLINE
|
#define forceinline ZPL_ALWAYS_INLINE
|
||||||
#define print_nl( _) zpl_printf("\n")
|
#define print_nl( _) zpl_printf("\n")
|
||||||
#define ccast( Type_, Value_ ) * const_cast< Type_* >( & Value_ )
|
#define ccast( Type_, Value_ ) * const_cast< Type_* >( & (Value_) )
|
||||||
#define scast( Type_, Value_ ) static_cast< Type_ >( Value_ )
|
#define scast( Type_, Value_ ) static_cast< Type_ >( Value_ )
|
||||||
#define rcast( Type_, Value_ ) reinterpret_cast< Type_ >( Value_ )
|
#define rcast( Type_, Value_ ) reinterpret_cast< Type_ >( Value_ )
|
||||||
#define pcast( Type_, Value_ ) ( * (Type_*)( & Value_ ) )
|
#define pcast( Type_, Value_ ) ( * (Type_*)( & (Value_) ) )
|
||||||
#define txt_impl( Value_ ) #Value_
|
#define txt_impl( Value_ ) #Value_
|
||||||
#define txt( Value_ ) txt_impl( Value_ )
|
#define txt( Value_ ) txt_impl( Value_ )
|
||||||
#define txt_with_length( Value_ ) txt_impl( Value_ ), sizeof( txt_impl( Value_) )
|
#define txt_with_length( Value_ ) txt_impl( Value_ ), sizeof( txt_impl( Value_ ) )
|
||||||
|
|
||||||
#define do_once() \
|
#define do_once() \
|
||||||
do \
|
do \
|
||||||
@ -131,6 +131,8 @@ namespace Memory
|
|||||||
void cleanup();
|
void cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sw token_fmt_va( char* buf, uw buf_size, char const* fmt, s32 num_tokens, va_list va );
|
||||||
|
|
||||||
inline
|
inline
|
||||||
char const* token_fmt( char const* fmt, sw num_tokens, ... )
|
char const* token_fmt( char const* fmt, sw num_tokens, ... )
|
||||||
{
|
{
|
||||||
@ -185,3 +187,4 @@ sw fatal(char const *fmt, ...)
|
|||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
411
project/gen.cpp
411
project/gen.cpp
@ -4,40 +4,57 @@
|
|||||||
#ifdef gen_time
|
#ifdef gen_time
|
||||||
namespace gen
|
namespace gen
|
||||||
{
|
{
|
||||||
|
ZPL_TABLE_DEFINE( StringTable, str_tbl_, string );
|
||||||
|
ZPL_TABLE_DEFINE( TypeTable, type_tbl_ , Code );
|
||||||
|
|
||||||
namespace StaticData
|
namespace StaticData
|
||||||
{
|
{
|
||||||
static array(CodePOD) CodePool = nullptr;
|
static array(CodePOD) CodePool = nullptr;
|
||||||
|
|
||||||
|
static array(arena) StringArenas = nullptr;
|
||||||
|
|
||||||
|
static StringTable StringMap;
|
||||||
|
static TypeTable TypeMap;
|
||||||
|
|
||||||
|
static sw InitSize_CodePool = megabytes(64);
|
||||||
|
static sw InitSize_StringArena = megabytes(32);
|
||||||
|
static sw InitSize_StringTable = megabytes(4);
|
||||||
|
static sw InitSize_TypeTable = megabytes(4);
|
||||||
|
|
||||||
|
static allocator Allocator_CodePool = zpl_heap();
|
||||||
|
static allocator Allocator_StringArena = zpl_heap();
|
||||||
|
static allocator Allocator_StringTable = zpl_heap();
|
||||||
|
static allocator Allocator_TypeTable = zpl_heap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma region CONSTANTS
|
#pragma region CONSTANTS
|
||||||
# ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
# ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||||
const Code t_void;
|
Code t_void;
|
||||||
|
|
||||||
const Code t_bool;
|
Code t_bool;
|
||||||
const Code t_char;
|
Code t_char;
|
||||||
const Code t_char_wide;
|
Code t_char_wide;
|
||||||
|
|
||||||
const Code t_s8;
|
Code t_s8;
|
||||||
const Code t_s16;
|
Code t_s16;
|
||||||
const Code t_s32;
|
Code t_s32;
|
||||||
const Code t_s64;
|
Code t_s64;
|
||||||
|
|
||||||
const Code t_u8;
|
Code t_u8;
|
||||||
const Code t_u16;
|
Code t_u16;
|
||||||
const Code t_u32;
|
Code t_u32;
|
||||||
const Code t_u64;
|
Code t_u64;
|
||||||
|
|
||||||
const Code t_sw;
|
Code t_sw;
|
||||||
const Code t_uw;
|
Code t_uw;
|
||||||
|
|
||||||
const Code t_f32;
|
Code t_f32;
|
||||||
const Code t_f64;
|
Code t_f64;
|
||||||
|
|
||||||
const Code spec_constexpr;
|
|
||||||
const Code spec_inline;
|
|
||||||
# endif
|
# endif
|
||||||
#pragma endregion CONSTANTS
|
|
||||||
|
|
||||||
|
Code spec_constexpr;
|
||||||
|
Code spec_inline;
|
||||||
|
#pragma endregion CONSTANTS
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Used internally to retireve a Code object form the CodePool.
|
Used internally to retireve a Code object form the CodePool.
|
||||||
@ -66,10 +83,9 @@ namespace gen
|
|||||||
t_bool_write = ccast( Code, t_void );
|
t_bool_write = ccast( Code, t_void );
|
||||||
t_bool_write = def_type( txt(void) );
|
t_bool_write = def_type( txt(void) );
|
||||||
|
|
||||||
# define def_constant_code_type( Type_ ) \
|
# define def_constant_code_type( Type_ ) \
|
||||||
Code& \
|
Code& \
|
||||||
t_##Type_##_write = ccast( Code, t_##Type_ ); \
|
t_##Type_ = def_type( txt(Type_) )
|
||||||
t_##Type_##_write = def_type( txt(Type_) ) \
|
|
||||||
|
|
||||||
def_constant_code_type( bool );
|
def_constant_code_type( bool );
|
||||||
def_constant_code_type( char );
|
def_constant_code_type( char );
|
||||||
@ -109,80 +125,92 @@ namespace gen
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Code decl_type( Code type, char const* name, Code specifiers )
|
void clear_code_pool()
|
||||||
{
|
{
|
||||||
using namespace ECode;
|
array_clear( StaticData::CodePool );
|
||||||
|
|
||||||
if ( type->Type != Specifiers )
|
sw size = array_capacity( StaticData::CodePool );
|
||||||
{
|
|
||||||
log_failure( "gen::decl_type: type is not a Typename");
|
|
||||||
return InvalidCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( type->Type != Typename )
|
zpl_memset( StaticData::CodePool, 0, size );
|
||||||
{
|
|
||||||
log_failure( "gen::decl_type: specifiers is not a 'Specfiers' type");
|
|
||||||
return InvalidCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
Code
|
|
||||||
result = make_code();
|
|
||||||
result->Type = Decl_Type;
|
|
||||||
result->Name = string_make( g_allocator, name );
|
|
||||||
|
|
||||||
array_init( result->Entries, g_allocator );
|
|
||||||
result->add( specifiers );
|
|
||||||
result->add( type );
|
|
||||||
result.lock();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Code decl_proc( char const* name
|
allocator get_string_allocator( s32 str_length )
|
||||||
, Code specifiers
|
|
||||||
, Code params
|
|
||||||
, Code ret_type
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
using namespace ECode;
|
using namespace StaticData;
|
||||||
|
|
||||||
if ( specifiers->Type != Specifiers )
|
if ( StringArenas->total_allocated + str_length > StringArenas->total_size )
|
||||||
{
|
{
|
||||||
log_failure( "gen::decl_fn: specifiers was not a `Specifiers` type" );
|
arena new_arena;
|
||||||
return InvalidCode;
|
arena_init_from_allocator( & new_arena, Allocator_StringArena, InitSize_StringArena );
|
||||||
|
|
||||||
|
array_append( StringArenas, new_arena );
|
||||||
|
|
||||||
|
return arena_allocator( StringArenas );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( params->Type != Parameters )
|
return arena_allocator( StringArenas );
|
||||||
{
|
|
||||||
log_failure( "gen::decl_fn: params was not a `Parameters` type" );
|
|
||||||
return InvalidCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ret_type->Type != Typename )
|
|
||||||
{
|
|
||||||
log_failure( "gen::decl_fn: ret_type was not a Typename" );
|
|
||||||
return InvalidCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
Code
|
|
||||||
result = make_code();
|
|
||||||
result->Type = Decl_Function;
|
|
||||||
result->Name = string_make( g_allocator, name );
|
|
||||||
|
|
||||||
array_init( result->Entries, g_allocator );
|
|
||||||
|
|
||||||
if ( specifiers )
|
|
||||||
result->add( specifiers );
|
|
||||||
|
|
||||||
result->add( ret_type );
|
|
||||||
|
|
||||||
if ( params )
|
|
||||||
result->add( params );
|
|
||||||
|
|
||||||
result.lock();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Will either make or retrive a code string.
|
||||||
|
string code_string( char const* cstr, s32 length )
|
||||||
|
{
|
||||||
|
s32 hash_length = length > kilobytes(1) ? kilobytes(1) : length;
|
||||||
|
|
||||||
|
u32 key = crc32( cstr, hash_length );
|
||||||
|
|
||||||
|
string* result = str_tbl_get( & StaticData::StringMap, key );
|
||||||
|
|
||||||
|
if ( result )
|
||||||
|
{
|
||||||
|
return * result;
|
||||||
|
}
|
||||||
|
|
||||||
|
str_tbl_set( & StaticData::StringMap, key, * result );
|
||||||
|
|
||||||
|
return * result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_init_reserve_code_pool( sw size )
|
||||||
|
{
|
||||||
|
StaticData::InitSize_CodePool = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_init_reserve_string_arena( sw size )
|
||||||
|
{
|
||||||
|
StaticData::InitSize_StringArena = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_init_reserve_string_table( sw size )
|
||||||
|
{
|
||||||
|
StaticData::InitSize_StringTable = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_init_reserve_type_table( sw size )
|
||||||
|
{
|
||||||
|
StaticData::InitSize_TypeTable = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_allocator_code_pool( allocator pool_allocator )
|
||||||
|
{
|
||||||
|
StaticData::Allocator_CodePool = pool_allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_allocator_string_arena( allocator string_allocator )
|
||||||
|
{
|
||||||
|
StaticData::Allocator_StringArena = string_allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_allocator_string_table( allocator string_allocator )
|
||||||
|
{
|
||||||
|
StaticData::Allocator_StringArena = string_allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_allocator_type_table( allocator type_reg_allocator )
|
||||||
|
{
|
||||||
|
StaticData::Allocator_TypeTable = type_reg_allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
# pragma region Upfront Constructors
|
||||||
Code def_params( s32 num, ... )
|
Code def_params( s32 num, ... )
|
||||||
{
|
{
|
||||||
using namespace ECode;
|
using namespace ECode;
|
||||||
@ -271,7 +299,7 @@ namespace gen
|
|||||||
|
|
||||||
switch ( body->Type )
|
switch ( body->Type )
|
||||||
{
|
{
|
||||||
case Function_Body:
|
case Proc_Body:
|
||||||
case Untyped:
|
case Untyped:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -285,7 +313,7 @@ namespace gen
|
|||||||
Code
|
Code
|
||||||
result = make_code();
|
result = make_code();
|
||||||
result->Name = string_make( g_allocator, name );
|
result->Name = string_make( g_allocator, name );
|
||||||
result->Type = Function;
|
result->Type = Proc;
|
||||||
|
|
||||||
array_init( result->Entries, g_allocator );
|
array_init( result->Entries, g_allocator );
|
||||||
|
|
||||||
@ -331,8 +359,7 @@ namespace gen
|
|||||||
|
|
||||||
switch ( entry->Type )
|
switch ( entry->Type )
|
||||||
{
|
{
|
||||||
case Decl_Function:
|
case Proc_Forward:
|
||||||
case Decl_Type:
|
|
||||||
case Namespace:
|
case Namespace:
|
||||||
case Namespace_Body:
|
case Namespace_Body:
|
||||||
case Parameters:
|
case Parameters:
|
||||||
@ -387,8 +414,7 @@ namespace gen
|
|||||||
|
|
||||||
switch ( entry->Type )
|
switch ( entry->Type )
|
||||||
{
|
{
|
||||||
case Decl_Function:
|
case Proc_Forward:
|
||||||
case Decl_Type:
|
|
||||||
case Namespace:
|
case Namespace:
|
||||||
case Namespace_Body:
|
case Namespace_Body:
|
||||||
case Parameters:
|
case Parameters:
|
||||||
@ -630,7 +656,7 @@ namespace gen
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Code def_type( char const* name )
|
Code def_type( char const* name, Code specifiers )
|
||||||
{
|
{
|
||||||
Code
|
Code
|
||||||
result = make_code();
|
result = make_code();
|
||||||
@ -654,57 +680,9 @@ namespace gen
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
# pragma endregion Upfront Constructors
|
||||||
|
|
||||||
Code untyped_str(char const* fmt)
|
# pragma region Incremetnal Constructors
|
||||||
{
|
|
||||||
Code
|
|
||||||
result = make_code();
|
|
||||||
result->Name = string_make( g_allocator, fmt );
|
|
||||||
result->Type = ECode::Untyped;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Code untyped_fmt(char const* fmt, ...)
|
|
||||||
{
|
|
||||||
local_persist thread_local
|
|
||||||
char buf[ZPL_PRINTF_MAXLEN] = { 0 };
|
|
||||||
|
|
||||||
va_list va;
|
|
||||||
va_start(va, fmt);
|
|
||||||
zpl_snprintf_va(buf, ZPL_PRINTF_MAXLEN, fmt, va);
|
|
||||||
va_end(va);
|
|
||||||
|
|
||||||
Code
|
|
||||||
result = make_code();
|
|
||||||
result->Name = string_make( g_allocator, fmt );
|
|
||||||
result->Type = ECode::Untyped;
|
|
||||||
result->Content = string_make( g_allocator, buf );
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Code untyped_token_fmt( char const* fmt, s32 num_tokens, ... )
|
|
||||||
{
|
|
||||||
local_persist thread_local
|
|
||||||
char buf[ZPL_PRINTF_MAXLEN] = { 0 };
|
|
||||||
|
|
||||||
va_list va;
|
|
||||||
va_start(va, fmt);
|
|
||||||
token_fmt_va(buf, ZPL_PRINTF_MAXLEN, fmt, num_tokens, va);
|
|
||||||
va_end(va);
|
|
||||||
|
|
||||||
Code
|
|
||||||
result = make_code();
|
|
||||||
result->Name = string_make( g_allocator, fmt );
|
|
||||||
result->Type = ECode::Untyped;
|
|
||||||
result->Content = string_make( g_allocator, buf );
|
|
||||||
|
|
||||||
result.lock();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Code make_proc( char const* name
|
Code make_proc( char const* name
|
||||||
, Code specifiers
|
, Code specifiers
|
||||||
, Code params
|
, Code params
|
||||||
@ -734,7 +712,7 @@ namespace gen
|
|||||||
Code
|
Code
|
||||||
result = make_code();
|
result = make_code();
|
||||||
result->Name = string_make( g_allocator, name );
|
result->Name = string_make( g_allocator, name );
|
||||||
result->Type = Function;
|
result->Type = Proc;
|
||||||
|
|
||||||
array_init( result->Entries, g_allocator );
|
array_init( result->Entries, g_allocator );
|
||||||
|
|
||||||
@ -788,12 +766,12 @@ namespace gen
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Code make_unit( char const* name )
|
Code make_global_body( char const* name = "", s32 num = 0, ... )
|
||||||
{
|
{
|
||||||
Code
|
Code
|
||||||
result = make_code();
|
result = make_code();
|
||||||
result->Type = ECode::Unit;
|
result->Type = ECode::Global_Body;
|
||||||
result->Name = string_make( g_allocator, name );
|
result->Name = string_make( g_allocator, "");
|
||||||
|
|
||||||
array_init( result->Entries, g_allocator );
|
array_init( result->Entries, g_allocator );
|
||||||
|
|
||||||
@ -802,7 +780,9 @@ namespace gen
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
# pragma endregion Incremetnal Constructions
|
||||||
|
|
||||||
|
# pragma region Parsing Constructors
|
||||||
Code parse_proc( char const* def, s32 length )
|
Code parse_proc( char const* def, s32 length )
|
||||||
{
|
{
|
||||||
if ( def == nullptr )
|
if ( def == nullptr )
|
||||||
@ -856,7 +836,7 @@ namespace gen
|
|||||||
while ( left && char_is_space( * scanner ) ) \
|
while ( left && char_is_space( * scanner ) ) \
|
||||||
{ \
|
{ \
|
||||||
left--; \
|
left--; \
|
||||||
scanner++ ;
|
scanner++ ; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define Get
|
#define Get
|
||||||
@ -947,7 +927,7 @@ namespace gen
|
|||||||
Code
|
Code
|
||||||
result = make_code();
|
result = make_code();
|
||||||
result->Name = string_make( g_allocator, name );
|
result->Name = string_make( g_allocator, name );
|
||||||
result->Type = ECode::Function;
|
result->Type = ECode::Proc;
|
||||||
|
|
||||||
array_init( result->Entries, g_allocator );
|
array_init( result->Entries, g_allocator );
|
||||||
|
|
||||||
@ -985,8 +965,124 @@ namespace gen
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
# pragma endregion Parsing Constructors
|
||||||
|
|
||||||
|
# pragma region Untyped Constructors
|
||||||
|
Code untyped_str(char const* fmt)
|
||||||
|
{
|
||||||
|
Code
|
||||||
|
result = make_code();
|
||||||
|
result->Name = string_make( g_allocator, fmt );
|
||||||
|
result->Type = ECode::Untyped;
|
||||||
|
result->Content = result->Name;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Code untyped_fmt(char const* fmt, ...)
|
||||||
|
{
|
||||||
|
local_persist thread_local
|
||||||
|
char buf[ZPL_PRINTF_MAXLEN] = { 0 };
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
zpl_snprintf_va(buf, ZPL_PRINTF_MAXLEN, fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
Code
|
||||||
|
result = make_code();
|
||||||
|
result->Name = string_make( g_allocator, fmt );
|
||||||
|
result->Type = ECode::Untyped;
|
||||||
|
result->Content = string_make( g_allocator, buf );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Code untyped_token_fmt( char const* fmt, s32 num_tokens, ... )
|
||||||
|
{
|
||||||
|
local_persist thread_local
|
||||||
|
char buf[ZPL_PRINTF_MAXLEN] = { 0 };
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
token_fmt_va(buf, ZPL_PRINTF_MAXLEN, fmt, num_tokens, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
Code
|
||||||
|
result = make_code();
|
||||||
|
result->Name = string_make( g_allocator, fmt );
|
||||||
|
result->Type = ECode::Untyped;
|
||||||
|
result->Content = string_make( g_allocator, buf );
|
||||||
|
|
||||||
|
result.lock();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
# pragma endregion Untyped Constructors
|
||||||
|
|
||||||
|
# pragma region AST
|
||||||
|
bool AST::add( AST* other )
|
||||||
|
{
|
||||||
|
switch ( Type )
|
||||||
|
{
|
||||||
|
using namespace ECode;
|
||||||
|
|
||||||
|
case Untyped:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Global_Body:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Proc:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Proc_Body:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Proc_Forward:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Namespace:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Namespace_Body:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Parameters:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Specifiers:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Struct:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Struct_Body:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Variable:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Typedef:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Typename:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Using:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
array_append( Entries, other );
|
||||||
|
|
||||||
|
other->Parent = this;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AST::check()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
string AST::to_string() const
|
string AST::to_string() const
|
||||||
{
|
{
|
||||||
@ -1007,7 +1103,7 @@ namespace gen
|
|||||||
result = string_append_length( result, Content, string_length(Content) );
|
result = string_append_length( result, Content, string_length(Content) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Decl_Function:
|
case Proc_Forward:
|
||||||
{
|
{
|
||||||
u32 index = 0;
|
u32 index = 0;
|
||||||
u32 left = array_count( Entries );
|
u32 left = array_count( Entries );
|
||||||
@ -1040,14 +1136,7 @@ namespace gen
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Decl_Type:
|
case Proc:
|
||||||
if ( Entries[0]->Type == Specifiers )
|
|
||||||
result = string_append_fmt( result, "%s\n", Entries[0]->to_string());
|
|
||||||
|
|
||||||
result = string_append_fmt( result, "%s %s;\n", Entries[1]->to_string(), Name );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Function:
|
|
||||||
{
|
{
|
||||||
u32 index = 0;
|
u32 index = 0;
|
||||||
u32 left = array_count( Entries );
|
u32 left = array_count( Entries );
|
||||||
@ -1080,7 +1169,7 @@ namespace gen
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Function_Body:
|
case Proc_Body:
|
||||||
fatal("NOT SUPPORTED YET");
|
fatal("NOT SUPPORTED YET");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1138,9 +1227,10 @@ namespace gen
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
# pragma endregion AST
|
||||||
|
|
||||||
|
|
||||||
|
# pragma region Builder
|
||||||
void Builder::print( Code code )
|
void Builder::print( Code code )
|
||||||
{
|
{
|
||||||
Buffer = string_append_fmt( Buffer, "%s\n\n", code->to_string() );
|
Buffer = string_append_fmt( Buffer, "%s\n\n", code->to_string() );
|
||||||
@ -1171,5 +1261,6 @@ namespace gen
|
|||||||
// file_seek( & File, 0 );
|
// file_seek( & File, 0 );
|
||||||
file_close( & File );
|
file_close( & File );
|
||||||
}
|
}
|
||||||
|
# pragma endregion Builder
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
570
project/gen.hpp
570
project/gen.hpp
@ -13,17 +13,14 @@
|
|||||||
* Expression validation : Execution expressions are defined using the untyped string API.
|
* Expression validation : Execution expressions are defined using the untyped string API.
|
||||||
There is no parse API for validating expression (possibly will add in the future)
|
There is no parse API for validating expression (possibly will add in the future)
|
||||||
* Complete file parser DSL : This isn't like the unreal header tool.
|
* Complete file parser DSL : This isn't like the unreal header tool.
|
||||||
Code injection to file or based off a file contents is not supported by the api.
|
Code injection to file or based off a file contents is not supported by the api. However nothing is stopping you using the library for that purpose.
|
||||||
However nothing is stopping you using the library for that purpose.
|
|
||||||
* Modern c++ (STL library) features
|
* Modern c++ (STL library) features
|
||||||
|
|
||||||
As mentioned in [Usage](#Usage), the user is provided Code objects by calling the interface procedures to generate them or find existing matches.
|
|
||||||
|
|
||||||
The AST is managed by the library and provided the user via its interface prodedures.
|
The AST is managed by the library and provided the user via its interface prodedures.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
* The allocator definitions used are exposed to the user incase they want to dictate memory usage*
|
* The allocator definitions used are exposed to the user incase they want to dictate memory usage
|
||||||
* ASTs are wrapped for the user in a Code struct which essentially a warpper for a AST* type.
|
* ASTs are wrapped for the user in a Code struct which essentially a warpper for a AST* type.
|
||||||
* Both AST and Code have member symbols but their data layout is enforced to be POD types.
|
* Both AST and Code have member symbols but their data layout is enforced to be POD types.
|
||||||
|
|
||||||
@ -58,22 +55,30 @@
|
|||||||
|
|
||||||
Interface :
|
Interface :
|
||||||
|
|
||||||
* def_forward_decl
|
|
||||||
* def_class
|
* def_class
|
||||||
|
* def_class_body
|
||||||
|
* def_class_fwd
|
||||||
|
* def_enum
|
||||||
|
* def_enum_class
|
||||||
|
* def_enum_body
|
||||||
* def_global_body
|
* def_global_body
|
||||||
* def_proc
|
|
||||||
* def_proc_body
|
|
||||||
* def_namespace
|
* def_namespace
|
||||||
* def_namespace_body
|
* def_namespace_body
|
||||||
|
* def_operator
|
||||||
|
* def_operator_fwd
|
||||||
* def_param
|
* def_param
|
||||||
* def_params
|
* def_params
|
||||||
* def_operator
|
* def_proc
|
||||||
|
* def_proc_body
|
||||||
|
* def_proc_fwd
|
||||||
* def_specifier
|
* def_specifier
|
||||||
* def_specifiers
|
* def_specifiers
|
||||||
* def_struct
|
* def_struct
|
||||||
* def_struct_body
|
* def_struct_body
|
||||||
|
* def_struct_fwd
|
||||||
* def_variable
|
* def_variable
|
||||||
* def_type
|
* def_type
|
||||||
|
* def_typedef
|
||||||
* def_using
|
* def_using
|
||||||
* def_using_namespace
|
* def_using_namespace
|
||||||
|
|
||||||
@ -82,27 +87,27 @@
|
|||||||
A Code ast is provided but only completed upfront if all components are provided.
|
A Code ast is provided but only completed upfront if all components are provided.
|
||||||
Components are then added using the AST API for adding ASTs:
|
Components are then added using the AST API for adding ASTs:
|
||||||
|
|
||||||
* code.add( AST* ) // Adds AST with validation.
|
* code.add( AST* ) // Adds AST with validation.
|
||||||
* code.add_entry( AST* ) // Adds AST entry without validation.
|
* code.add_entry( AST* ) // Adds AST entry without validation.
|
||||||
* code.add_content( AST* ) // Adds AST string content without validation.
|
|
||||||
|
|
||||||
Code ASTs may be explictly validated at anytime using Code's check() member function.
|
Code ASTs may be explictly validated at anytime using Code's check() member function.
|
||||||
|
|
||||||
Interface :
|
Interface :
|
||||||
|
|
||||||
* make_forward_decl
|
|
||||||
* make_class
|
* make_class
|
||||||
|
* make_enum
|
||||||
|
* make_enum_class
|
||||||
* make_global_body
|
* make_global_body
|
||||||
* make_proc
|
|
||||||
* make_namespace
|
* make_namespace
|
||||||
* make_params
|
|
||||||
* make_operator
|
* make_operator
|
||||||
|
* make_params
|
||||||
|
* make_proc
|
||||||
* make_specifiers
|
* make_specifiers
|
||||||
* make_struct
|
* make_struct
|
||||||
* make_variable
|
* make_variable
|
||||||
* make_type
|
* make_type
|
||||||
|
* make_typedef
|
||||||
* make_using
|
* make_using
|
||||||
* make_using_namespace
|
|
||||||
|
|
||||||
### Parse construction
|
### Parse construction
|
||||||
|
|
||||||
@ -110,23 +115,33 @@
|
|||||||
|
|
||||||
Interface :
|
Interface :
|
||||||
|
|
||||||
* parse_forward_decl
|
|
||||||
* parse_class
|
* parse_class
|
||||||
* parse_glboal_body
|
* parse_classes
|
||||||
* parse_proc
|
* parse_enum
|
||||||
|
* parse_enums
|
||||||
|
* parse_global_body
|
||||||
* parse_namespace
|
* parse_namespace
|
||||||
* parse_params
|
* parse_namespaces
|
||||||
* parse_operator
|
* parse_operator
|
||||||
* parse_specifiers
|
* parse_operators
|
||||||
|
* parse_proc
|
||||||
|
* parse_procs
|
||||||
* parse_struct
|
* parse_struct
|
||||||
|
* parse_strucs
|
||||||
* parse_variable
|
* parse_variable
|
||||||
|
* parse_variables
|
||||||
* parse_type
|
* parse_type
|
||||||
|
* parse_typedef
|
||||||
|
* parse_typedefs
|
||||||
* parse_using
|
* parse_using
|
||||||
* parse_using
|
* parse_usings
|
||||||
|
|
||||||
The parse API treats any execution scope definitions with no validation and are turned into untyped Code ASTs.
|
The parse API treats any execution scope definitions with no validation and are turned into untyped Code ASTs.
|
||||||
This includes the assignmetn of variables; due to the library not yet supporting c/c++ expression parsing.
|
This includes the assignmetn of variables; due to the library not yet supporting c/c++ expression parsing.
|
||||||
|
|
||||||
|
The plural variants provide an array of codes, its up to the user to add them to a body AST
|
||||||
|
(they are not auto-added to a body)
|
||||||
|
|
||||||
### Untyped constructions
|
### Untyped constructions
|
||||||
|
|
||||||
Code ASTs are constructed using unvalidated strings.
|
Code ASTs are constructed using unvalidated strings.
|
||||||
@ -158,7 +173,7 @@
|
|||||||
// #define GEN_DEFINE_DSL
|
// #define GEN_DEFINE_DSL
|
||||||
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||||
// #define GEN_BAN_CPP_TEMPLATES
|
// #define GEN_BAN_CPP_TEMPLATES
|
||||||
// #define GEN_USE_FATAL
|
#define GEN_USE_FATAL
|
||||||
|
|
||||||
#ifdef gen_time
|
#ifdef gen_time
|
||||||
namespace gen
|
namespace gen
|
||||||
@ -179,41 +194,52 @@ namespace gen
|
|||||||
{
|
{
|
||||||
enum Type : u8
|
enum Type : u8
|
||||||
{
|
{
|
||||||
Invalid, // Used only with improperly created Code nodes
|
Invalid,
|
||||||
Untyped, // User provided raw string
|
Untyped,
|
||||||
Decl_Function, // <specifier> <type> <name> ( <params> )
|
Access_Public,
|
||||||
Decl_Type, // <type> <name>;
|
Access_Private,
|
||||||
Function, // <type> <name>( <parameters> )
|
Access_Protected,
|
||||||
Function_Body, // { <body> }
|
Class,
|
||||||
Namespace, // Define a namespace
|
Enum,
|
||||||
Namespace_Body, // { <body> }
|
Enum_Body,
|
||||||
Parameters, // <type> <param> ...
|
Global_Body,
|
||||||
Specifiers, // Used with functions, structs, variables
|
Namespace,
|
||||||
Struct, // struct <specifier> <name> <parent>
|
Namespace_Body,
|
||||||
Struct_Body, // {<body> }
|
Parameters,
|
||||||
Variable, // <type> <name>
|
Proc,
|
||||||
Typedef, // typedef <type> <alias>
|
Proc_Body,
|
||||||
Typename, // Typename, used with other types
|
Proc_Forward,
|
||||||
Using, // using <name> = <type>
|
Specifiers,
|
||||||
Unit, // Represents a file.
|
Struct,
|
||||||
|
Struct_Body,
|
||||||
|
Variable,
|
||||||
|
Typedef,
|
||||||
|
Typename,
|
||||||
|
Using,
|
||||||
|
|
||||||
Num_Types
|
Num_Types
|
||||||
};
|
};
|
||||||
|
|
||||||
inline
|
local_persist
|
||||||
char const* str( Type type )
|
char const* str( Type type )
|
||||||
{
|
{
|
||||||
static
|
static
|
||||||
char const* lookup[Num_Types] = {
|
char const* lookup[Num_Types] = {
|
||||||
"Invalid",
|
"Invalid",
|
||||||
"Untyped",
|
"Untyped",
|
||||||
"Decl_Function",
|
"Access_Public",
|
||||||
"Decl_Type",
|
"Access_Private",
|
||||||
"Function",
|
"Access_Protected",
|
||||||
"Function_Body",
|
"Class",
|
||||||
|
"Enum",
|
||||||
|
"Enum_Body",
|
||||||
|
"Global_Body",
|
||||||
"Namespace",
|
"Namespace",
|
||||||
"Namespace_Body",
|
"Namespace_Body",
|
||||||
"Parameters",
|
"Parameters",
|
||||||
|
"Proc",
|
||||||
|
"Proc_Body",
|
||||||
|
"Proc_Forward",
|
||||||
"Specifiers",
|
"Specifiers",
|
||||||
"Struct",
|
"Struct",
|
||||||
"Struct_Body",
|
"Struct_Body",
|
||||||
@ -221,7 +247,6 @@ namespace gen
|
|||||||
"Typedef",
|
"Typedef",
|
||||||
"Typename",
|
"Typename",
|
||||||
"Using",
|
"Using",
|
||||||
"Unit",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return lookup[ type ];
|
return lookup[ type ];
|
||||||
@ -245,7 +270,7 @@ namespace gen
|
|||||||
inline
|
inline
|
||||||
char const* str( Type op )
|
char const* str( Type op )
|
||||||
{
|
{
|
||||||
static
|
local_persist
|
||||||
char const* lookup[ Num_Ops ] = {
|
char const* lookup[ Num_Ops ] = {
|
||||||
"+",
|
"+",
|
||||||
"-",
|
"-",
|
||||||
@ -262,43 +287,48 @@ namespace gen
|
|||||||
{
|
{
|
||||||
enum Type : u8
|
enum Type : u8
|
||||||
{
|
{
|
||||||
Attribute, // [ <attributes ]
|
Attribute,
|
||||||
Alignas, // alignas(#)
|
Alignas,
|
||||||
Constexpr, // constexpr
|
Constexpr,
|
||||||
Const, // const
|
Const,
|
||||||
Inline, // inline
|
Inline,
|
||||||
RValue, //
|
Pointer,
|
||||||
|
Reference,
|
||||||
|
RValue,
|
||||||
|
|
||||||
C_Linkage, // extern "C"
|
C_Linkage,
|
||||||
API_Import, // Vendor specific way dynamic import symbol
|
API_Import,
|
||||||
API_Export, // Vendor specific way to dynamic export
|
API_Export,
|
||||||
External_Linkage, // extern
|
External_Linkage,
|
||||||
Internal_Linkage, // static (within unit file)
|
Internal_Linkage,
|
||||||
Static_Member, // static (within sturct/class)
|
Static_Member,
|
||||||
Local_Persist, // static (within function)
|
Local_Persist,
|
||||||
Thread_Local, // thread_local
|
Thread_Local,
|
||||||
|
|
||||||
|
Invalid,
|
||||||
Num_Specifiers,
|
Num_Specifiers,
|
||||||
Invalid
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Specifier to string
|
// Specifier to string
|
||||||
inline
|
inline
|
||||||
char const* to_str( Type specifier )
|
char const* to_str( Type specifier )
|
||||||
{
|
{
|
||||||
static
|
local_persist
|
||||||
char const* lookup[ Num_Specifiers ] = {
|
char const* lookup[ Num_Specifiers ] = {
|
||||||
"alignas",
|
"alignas",
|
||||||
"constexpr",
|
"constexpr",
|
||||||
"const",
|
"const",
|
||||||
"inline",
|
"inline",
|
||||||
|
"*",
|
||||||
|
"&",
|
||||||
|
"&&",
|
||||||
|
|
||||||
"extern \"C\"",
|
"extern \"C\"",
|
||||||
|
|
||||||
#if defined(ZPL_SYSTEM_WINDOWS) && 0// API_Import and API_Export strings
|
#if defined(ZPL_SYSTEM_WINDOWS)
|
||||||
"__declspec(dllexport)",
|
"__declspec(dllexport)",
|
||||||
"__declspec(dllimport)",
|
"__declspec(dllimport)",
|
||||||
#elif defined(ZPL_SYSTEM_MACOS) || 1
|
#elif defined(ZPL_SYSTEM_MACOS)
|
||||||
"__attribute__ ((visibility (\"default\")))",
|
"__attribute__ ((visibility (\"default\")))",
|
||||||
"__attribute__ ((visibility (\"default\")))",
|
"__attribute__ ((visibility (\"default\")))",
|
||||||
#endif
|
#endif
|
||||||
@ -315,14 +345,14 @@ namespace gen
|
|||||||
|
|
||||||
Type to_type( char const* str, s32 length )
|
Type to_type( char const* str, s32 length )
|
||||||
{
|
{
|
||||||
static
|
local_persist
|
||||||
u32 keymap[ Num_Specifiers ];
|
u32 keymap[ Num_Specifiers ];
|
||||||
do_once_start
|
do_once_start
|
||||||
for ( u32 index = 0; index < Num_Specifiers; index++ )
|
for ( u32 index = 0; index < Num_Specifiers; index++ )
|
||||||
{
|
{
|
||||||
char const* enum_str = to_str( (Type)index );
|
char const* enum_str = to_str( (Type)index );
|
||||||
|
|
||||||
keymap[index] = crc32( enum_str, strnlen(enum_str, 42) );
|
keymap[index] = crc32( enum_str, zpl_strnlen(enum_str, 42) );
|
||||||
}
|
}
|
||||||
do_once_end
|
do_once_end
|
||||||
|
|
||||||
@ -339,6 +369,7 @@ namespace gen
|
|||||||
}
|
}
|
||||||
using SpecifierT = ESpecifier::Type;
|
using SpecifierT = ESpecifier::Type;
|
||||||
|
|
||||||
|
#pragma region Data Structures
|
||||||
// TODO: If perf needs it, convert layout an SOA format.
|
// TODO: If perf needs it, convert layout an SOA format.
|
||||||
/*
|
/*
|
||||||
Simple AST POD with functionality to seralize into C++ syntax.
|
Simple AST POD with functionality to seralize into C++ syntax.
|
||||||
@ -349,32 +380,46 @@ namespace gen
|
|||||||
*/
|
*/
|
||||||
struct AST
|
struct AST
|
||||||
{
|
{
|
||||||
#pragma region Member API
|
#pragma region Member Procedures
|
||||||
|
bool add( AST* other );
|
||||||
|
|
||||||
forceinline
|
forceinline
|
||||||
void add( AST* other )
|
void add_entry( AST* other )
|
||||||
{
|
{
|
||||||
array_append( Entries, other );
|
array_append( Entries, other );
|
||||||
|
|
||||||
other->Parent = this;
|
other->Parent = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forceinline
|
||||||
|
AST* body()
|
||||||
|
{
|
||||||
|
return Entries[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
forceinline
|
||||||
|
bool check();
|
||||||
|
|
||||||
forceinline
|
forceinline
|
||||||
bool has_entries() const
|
bool has_entries() const
|
||||||
{
|
{
|
||||||
static bool lookup[ ECode::Num_Types] = {
|
static bool lookup[ ECode::Num_Types] = {
|
||||||
false, // Invalid
|
false, // Invalid
|
||||||
false, // Untyped
|
false, // Untyped
|
||||||
true, // Decl_Function
|
false,
|
||||||
true, // Decl_Type
|
false,
|
||||||
true, // Function
|
false,
|
||||||
|
true, // Global_Body
|
||||||
true, // Parameters
|
true, // Parameters
|
||||||
|
true, // Proc
|
||||||
|
true, // Proc_Body
|
||||||
|
true, // Proc_Forward
|
||||||
false, // Specifies
|
false, // Specifies
|
||||||
true, // Struct
|
true, // Struct
|
||||||
true, // Struct_Body
|
true, // Struct_Body
|
||||||
true, // Variable
|
true, // Variable
|
||||||
true, // Typedef
|
true, // Typedef
|
||||||
true, // Typename
|
true, // Typename
|
||||||
true, // Using
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return lookup[Type];
|
return lookup[Type];
|
||||||
@ -394,7 +439,7 @@ namespace gen
|
|||||||
|
|
||||||
string to_string() const;
|
string to_string() const;
|
||||||
|
|
||||||
#pragma endregion Member API
|
#pragma endregion Member Procedures
|
||||||
|
|
||||||
#define Using_Code_POD \
|
#define Using_Code_POD \
|
||||||
CodeT Type; \
|
CodeT Type; \
|
||||||
@ -434,20 +479,32 @@ namespace gen
|
|||||||
Code body()
|
Code body()
|
||||||
{
|
{
|
||||||
if ( ast->Type == ECode::Invalid )
|
if ( ast->Type == ECode::Invalid )
|
||||||
fatal("Code::body: Type is invalid, cannot get");
|
{
|
||||||
|
log_failure("Code::body: Type is invalid, cannot get");
|
||||||
|
return InvalidCode;
|
||||||
|
}
|
||||||
|
|
||||||
if ( ast->Entries == nullptr || array_count(ast->Entries) == 0 )
|
if ( ast->Entries == nullptr || array_count(ast->Entries) == 0 )
|
||||||
fatal("Code::body: Entries of ast not properly setup.");
|
{
|
||||||
|
log_failure("Code::body: Entries of ast not properly setup.");
|
||||||
|
return InvalidCode;
|
||||||
|
}
|
||||||
|
|
||||||
return pcast( Code, ast->Entries[0]);
|
#ifdef GEN_ENFORCE_READONLY_AST
|
||||||
|
if ( ast->Readonly )
|
||||||
|
{
|
||||||
|
log_failure("Attempted to a body AST from a readonly AST!");
|
||||||
|
return InvalidCode;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return * (Code*)( ast->body() );
|
||||||
}
|
}
|
||||||
|
|
||||||
forceinline
|
forceinline
|
||||||
void lock()
|
void lock()
|
||||||
{
|
{
|
||||||
#ifdef GEN_ENFORCE_READONLY_AST
|
|
||||||
ast->Readonly = true;
|
ast->Readonly = true;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
forceinline
|
forceinline
|
||||||
@ -468,6 +525,20 @@ namespace gen
|
|||||||
|
|
||||||
Code& operator =( Code other )
|
Code& operator =( Code other )
|
||||||
{
|
{
|
||||||
|
if ( ast == nullptr )
|
||||||
|
{
|
||||||
|
log_failure("Attempt to set with a null AST!");
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef GEN_ENFORCE_READONLY_AST
|
||||||
|
if ( ast->Readonly )
|
||||||
|
{
|
||||||
|
log_failure("Attempted to set a readonly AST!");
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ast = other.ast;
|
ast = other.ast;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
@ -476,12 +547,18 @@ namespace gen
|
|||||||
forceinline
|
forceinline
|
||||||
AST* operator ->()
|
AST* operator ->()
|
||||||
{
|
{
|
||||||
#ifdef GEN_ENFORCE_READONLY_AST
|
|
||||||
if ( ast == nullptr )
|
if ( ast == nullptr )
|
||||||
fatal("Attempt to dereference a nullptr!");
|
{
|
||||||
|
log_failure("Attempt to dereference a nullptr!");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef GEN_ENFORCE_READONLY_AST
|
||||||
if ( ast->Readonly )
|
if ( ast->Readonly )
|
||||||
fatal("Attempted to access a member from a readonly ast!");
|
{
|
||||||
|
log_failure("Attempted to access a member from a readonly AST!");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return ast;
|
return ast;
|
||||||
@ -495,6 +572,10 @@ namespace gen
|
|||||||
// Used internally for the most part to identify invaidly generated code.
|
// Used internally for the most part to identify invaidly generated code.
|
||||||
extern const Code InvalidCode;
|
extern const Code InvalidCode;
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
ZPL_TABLE_DECLARE( ZPL_EXTERN, StringTable, str_tbl_, string );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Type registy: Used to store Typename ASTs. Types are registered by their string literal value.
|
Type registy: Used to store Typename ASTs. Types are registered by their string literal value.
|
||||||
|
|
||||||
@ -502,47 +583,56 @@ namespace gen
|
|||||||
Strings made with the Typename ASTs are stored in thier own arena allocator.
|
Strings made with the Typename ASTs are stored in thier own arena allocator.
|
||||||
TODO: Implement and replace usage of def_type.
|
TODO: Implement and replace usage of def_type.
|
||||||
*/
|
*/
|
||||||
ZPL_TABLE_DECLARE( ZPL_EXTERN, TypeRegistry, type_reg_, Code );
|
ZPL_TABLE_DECLARE( ZPL_EXTERN, TypeTable, type_tbl_, Code );
|
||||||
|
#pragma endregion Data Structures
|
||||||
|
|
||||||
#pragma region gen API
|
#pragma region Gen Interface
|
||||||
/*
|
/*
|
||||||
Initialize the library.
|
Initialize the library.
|
||||||
This currently just initializes the CodePool.
|
This currently just initializes the CodePool.
|
||||||
*/
|
*/
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
#pragma region Upfront
|
// Use this only if you know you generated the code you needed to a file
|
||||||
/*
|
// And rather get rid of current code asts instead of growing the pool memory.
|
||||||
Foward Declare a type:
|
void clear_code_pool();
|
||||||
<specifiers> <type> <name>;
|
|
||||||
*/
|
|
||||||
Code def_fwd_type( Code type, char const* name, Code specifiers = UnusedCode );
|
|
||||||
|
|
||||||
/*
|
// Set these before calling gen's init() procedure.
|
||||||
Foward Declare a function:
|
|
||||||
<specifiers> <name> ( <params> );
|
void set_init_reserve_code_pool ( sw size );
|
||||||
*/
|
void set_init_reserve_string_arena( sw size );
|
||||||
Code def_fwd_proc( char const* name
|
void set_init_reserve_string_table( sw size );
|
||||||
|
void set_init_reserve_type_table ( sw size );
|
||||||
|
|
||||||
|
void set_allocator_code_pool ( allocator pool_allocator );
|
||||||
|
void set_allocator_string_arena( allocator string_allocator );
|
||||||
|
void set_allocator_string_table( allocator string_allocator );
|
||||||
|
void set_allocator_type_table ( allocator type_reg_allocator );
|
||||||
|
|
||||||
|
# pragma region Upfront
|
||||||
|
Code def_class ( char const* name, Code body, Code parent = UnusedCode, Code specifiers = UnusedCode );
|
||||||
|
Code def_class_body( s32 num, ... );
|
||||||
|
Code def_class_fwd ( char const* name );
|
||||||
|
|
||||||
|
Code def_enum( char const* name, Code type, Code body );
|
||||||
|
|
||||||
|
Code def_global_body( s32 num, ... );
|
||||||
|
|
||||||
|
Code def_namespace ( char const* name, Code body );
|
||||||
|
Code def_namespace_body( s32 num, ... );
|
||||||
|
|
||||||
|
Code def_operator( OperatorT op
|
||||||
, Code specifiers
|
, Code specifiers
|
||||||
, Code params
|
, Code params
|
||||||
, Code ret_type
|
, Code ret_type
|
||||||
|
, Code body
|
||||||
);
|
);
|
||||||
|
Code def_operator_fwd( OperatorT op, Code specifiers, Code params, Code ret_type );
|
||||||
|
|
||||||
/*
|
Code def_param( Code type, char const* name );
|
||||||
Define an expression:
|
Code def_params( s32 num, ... );
|
||||||
< c/c++ expression >
|
Code def_params( s32 num, Code* params );
|
||||||
|
|
||||||
TODO: Evalute if you want to validiate at the execution layer during gen_time (dosen't seem necessary)
|
|
||||||
*/
|
|
||||||
// Code def_expression( Code value );
|
|
||||||
|
|
||||||
/*
|
|
||||||
Define a function:
|
|
||||||
<specifiers> <name> ( <params> )
|
|
||||||
{
|
|
||||||
<body>
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
Code def_proc( char const* name
|
Code def_proc( char const* name
|
||||||
, Code specifiers
|
, Code specifiers
|
||||||
, Code params
|
, Code params
|
||||||
@ -550,197 +640,101 @@ namespace gen
|
|||||||
, Code body
|
, Code body
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
|
||||||
Define a fucntion body:
|
|
||||||
{
|
|
||||||
<entry>
|
|
||||||
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
There will be an empty line separation between entires
|
|
||||||
*/
|
|
||||||
Code def_proc_body( s32 num, ... );
|
Code def_proc_body( s32 num, ... );
|
||||||
Code def_proc_body( s32 num, Code* codes );
|
Code def_proc_body( s32 num, Code* codes );
|
||||||
|
|
||||||
/*
|
Code def_proc_fwd( char const* name
|
||||||
Define a namespace;
|
, Code specifiers
|
||||||
namespace <name>
|
, Code params
|
||||||
{
|
, Code ret_type
|
||||||
<body>
|
);
|
||||||
}
|
|
||||||
*/
|
|
||||||
Code def_namespace( char const* name, Code body );
|
|
||||||
|
|
||||||
/*
|
Code def_specifier( SpecifierT* specifier );
|
||||||
Define a namespace body:
|
|
||||||
{
|
|
||||||
<entry>
|
|
||||||
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
There will be an empty line separation between entires
|
|
||||||
*/
|
|
||||||
Code def_namespace_body( s32 num, ... );
|
|
||||||
|
|
||||||
/*
|
|
||||||
Define a set of parameters for a function:
|
|
||||||
<name> <type>, ...
|
|
||||||
*/
|
|
||||||
Code def_params( s32 num, ... );
|
|
||||||
Code def_params( s32 num, char const** params );
|
|
||||||
|
|
||||||
/*
|
|
||||||
Define an operator definition.
|
|
||||||
*/
|
|
||||||
Code def_operator( OperatorT op, Code specifiers, Code params, Code ret_type, Code body );
|
|
||||||
|
|
||||||
/*
|
|
||||||
Define a set of specifiers for a function, struct, type, or varaible
|
|
||||||
|
|
||||||
Note:
|
|
||||||
If alignas is specified the procedure expects the next argument to be the alignment value.
|
|
||||||
If attribute is specified the procedure expects the next argument to be its content as a string.
|
|
||||||
*/
|
|
||||||
Code def_specifiers( s32 num , ... );
|
Code def_specifiers( s32 num , ... );
|
||||||
Code def_specifiers( s32 num, SpecifierT* specs );
|
Code def_specifiers( s32 num, SpecifierT* specs );
|
||||||
|
|
||||||
/*
|
|
||||||
Define a struct:
|
|
||||||
struct <specifiers> <name> : <parent>
|
|
||||||
{
|
|
||||||
<body>
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
Code def_struct( char const* name, Code body, Code parent = UnusedCode, Code specifiers = UnusedCode );
|
Code def_struct( char const* name, Code body, Code parent = UnusedCode, Code specifiers = UnusedCode );
|
||||||
|
|
||||||
/*
|
|
||||||
Define a struct's body:
|
|
||||||
{
|
|
||||||
<entry>
|
|
||||||
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
There will be an empty line separation between entires
|
|
||||||
*/
|
|
||||||
Code def_struct_body( s32 num, ... );
|
Code def_struct_body( s32 num, ... );
|
||||||
Code def_struct_body( s32 num, Code* codes );
|
Code def_struct_body( s32 num, Code* codes );
|
||||||
|
|
||||||
/*
|
Code def_sturct_fwd();
|
||||||
Define a variable:
|
|
||||||
<specifiers> <type> <name> = <value>;
|
|
||||||
*/
|
|
||||||
Code def_variable( Code type, char const* name, Code value = UnusedCode, Code specifiers = UnusedCode );
|
Code def_variable( Code type, char const* name, Code value = UnusedCode, Code specifiers = UnusedCode );
|
||||||
|
|
||||||
/*
|
Code def_type( char const* name, Code specifiers = UnusedCode );
|
||||||
Define a typename AST value.
|
|
||||||
Useless by itself, its intended to be used in conjunction with other Code.
|
|
||||||
|
|
||||||
Planned - Not yet Implemented:
|
Code def_using ( char const* name, Code type );
|
||||||
Typename Codes are not held in the CodePool, instead they are stored in a
|
|
||||||
type registry (hastable where the key is a crc hash of the name string).
|
|
||||||
|
|
||||||
If a key exists the existing code value will be provided.
|
|
||||||
*/
|
|
||||||
Code def_type( char const* name );
|
|
||||||
|
|
||||||
/*
|
|
||||||
Define a using typedef:
|
|
||||||
using <name> = <type>;
|
|
||||||
*/
|
|
||||||
Code def_using( char const* name, Code type );
|
|
||||||
|
|
||||||
/*
|
|
||||||
Define a using namespace:
|
|
||||||
using namespace <name>;
|
|
||||||
|
|
||||||
Can only be used in either a
|
|
||||||
*/
|
|
||||||
Code def_using_namespace( char const* name );
|
Code def_using_namespace( char const* name );
|
||||||
#pragma endregion Upfront
|
# pragma endregion Upfront
|
||||||
|
|
||||||
#pragma region Incremental
|
# pragma region Incremental
|
||||||
/*
|
Code make_class( char const* name, Code parent = UnusedCode, Code specifiers = UnusedCode );
|
||||||
Provides an incomplete procedure AST but sets the intended type.
|
|
||||||
Any adds will be type checked.
|
Code make_enum ( char const* name, Code type = UnusedCode, Code body = UnusedCode );
|
||||||
|
Code make_enum_class( char const* name, Code type = UnusedCode, Code body = UnusedCode );
|
||||||
|
|
||||||
|
Code make_global_body( char const* name = "", s32 num = 0, ... );
|
||||||
|
|
||||||
|
Code make_namespace( char const* name );
|
||||||
|
|
||||||
|
Code make_operator( OperatorT op
|
||||||
|
, Code specifiers = UnusedCode
|
||||||
|
, Code params = UnusedCode
|
||||||
|
, Code ret_type = UnusedCode
|
||||||
|
, Code body = UnusedCode
|
||||||
|
);
|
||||||
|
|
||||||
|
Code make_params( s32 num, ... );
|
||||||
|
|
||||||
Body is automatically made. Use body() to retrieve.
|
|
||||||
*/
|
|
||||||
Code make_proc( char const* name
|
Code make_proc( char const* name
|
||||||
, Code specifiers = UnusedCode
|
, Code specifiers = UnusedCode
|
||||||
, Code params = UnusedCode
|
, Code params = UnusedCode
|
||||||
, Code ret_type = UnusedCode
|
, Code ret_type = UnusedCode
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
Code make_specifiers( s32 num , ... );
|
||||||
Provides an incomplete struct AST but sets the intended type.
|
Code make_specifiers( s32 num, SpecifierT* specs );
|
||||||
Any adds will be type checked.
|
|
||||||
|
|
||||||
Body is automatically made. Use body() to retrieve.
|
|
||||||
*/
|
|
||||||
Code make_struct( char const* name, Code parent = UnusedCode, Code specifiers = UnusedCode );
|
Code make_struct( char const* name, Code parent = UnusedCode, Code specifiers = UnusedCode );
|
||||||
|
|
||||||
/*
|
Code make_variable( char const* name, Code type = UnusedCode, Code value = UnusedCode, Code specifiers = UnusedCode );
|
||||||
Creates a unit file.
|
|
||||||
|
|
||||||
These represent an encapsulation of a generated file
|
Code make_type( char const* name, Code specifiers = UnusedCode );
|
||||||
Used this if you need to pass around a group of Code entires at file scope level.
|
|
||||||
|
|
||||||
The name provided is the name of the file.
|
Code make_using( char const* name, Code type = UnusedCode, Code specifiers = UnusedCode );
|
||||||
*/
|
# pragma endregion Incremental
|
||||||
Code make_file_body( char const* name );
|
|
||||||
#pragma endregion Incremental
|
|
||||||
|
|
||||||
/*
|
# pragma region Parsing
|
||||||
*/
|
Code parse_class( char const* class_def, s32 length );
|
||||||
Code parse_variable( char const* var_def, s32 length );
|
s32 parse_classes( char const* class_defs, s32 length, Code* out_classes );
|
||||||
|
|
||||||
/*
|
Code parse_enum( char const* enum_def, s32 length);
|
||||||
*/
|
s32 parse_enums( char const* enum_defs, s32 length, Code* out_enums );
|
||||||
Code parse_using( char const* using_def, s32 length );
|
|
||||||
|
|
||||||
/*
|
Code parse_global_body( char const* body_def, s32 length );
|
||||||
|
|
||||||
*/
|
|
||||||
Code parse_operator( char const* operator_def, s32 length );
|
Code parse_operator( char const* operator_def, s32 length );
|
||||||
|
|
||||||
/*
|
|
||||||
Define a procedure by parsing a string.
|
|
||||||
|
|
||||||
Note: This parser only supports the language features the library supports
|
|
||||||
Any other features used and the lex or parse operation will fail.
|
|
||||||
|
|
||||||
This is not a full-on c/c++ parser, it literally only grabs
|
|
||||||
what it needs to reconstruct the Code AST for seralization in the
|
|
||||||
builder, nothing else.
|
|
||||||
*/
|
|
||||||
Code parse_proc( char const* proc_def, s32 length );
|
Code parse_proc( char const* proc_def, s32 length );
|
||||||
|
s32 parse_procs( char const* proc_defs, s32 length, Code* out_procs );
|
||||||
|
|
||||||
/*
|
|
||||||
Define a struct by parsing a string.
|
|
||||||
|
|
||||||
Note: This parser only supports the language features the library supports
|
|
||||||
Any other features used and the lex or parse operation will fail.
|
|
||||||
|
|
||||||
This is not a full-on c/c++ parser, it literally only grabs
|
|
||||||
what it needs to reconstruct the Code AST for seralization in the
|
|
||||||
builder, nothing else.
|
|
||||||
*/
|
|
||||||
Code parse_struct( char const* struct_def, s32 length );
|
Code parse_struct( char const* struct_def, s32 length );
|
||||||
|
s32 parse_structs( char const* struct_defs, s32 length, Code* out_struct_codes );
|
||||||
|
|
||||||
/*
|
Code parse_variable( char const* var_def, s32 length );
|
||||||
|
s32 parse_variables( char const* vars_def, s32 length, Code* out_var_codes );
|
||||||
|
|
||||||
*/
|
Code parse_type( char const* type_def, s32 length );
|
||||||
s32 parse_vars( char const* vars_def, s32 length, Code* out_vars_codes );
|
|
||||||
|
|
||||||
/*
|
Code parse_typedef( char const* typedef_def, s32 length );
|
||||||
|
s32 parse_typedef( char const* typedef_def, s32 length, Code* out_typedef_codes );
|
||||||
|
|
||||||
*/
|
Code parse_using ( char const* using_def, s32 length );
|
||||||
s32 parse_usings( char const* usings_def, s32 length, Code* out_usings_codes );
|
s32 parse_usings( char const* usings_def, s32 length, Code* out_using_codes );
|
||||||
|
# pragma endregion Parsing
|
||||||
|
|
||||||
#pragma region Untyped text
|
# pragma region Untyped text
|
||||||
/*
|
/*
|
||||||
Define an untyped code string.
|
Define an untyped code string.
|
||||||
|
|
||||||
@ -779,7 +773,7 @@ Code make_file_body( char const* name );
|
|||||||
Consider this an a preprocessor define.
|
Consider this an a preprocessor define.
|
||||||
*/
|
*/
|
||||||
Code untyped_token_fmt( char const* fmt, s32 num_tokens, ... );
|
Code untyped_token_fmt( char const* fmt, s32 num_tokens, ... );
|
||||||
#pragma endregion Untyped text
|
# pragma endregion Untyped text
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Used to generate the files.
|
Used to generate the files.
|
||||||
@ -806,7 +800,7 @@ Code make_file_body( char const* name );
|
|||||||
bool open( char const* path );
|
bool open( char const* path );
|
||||||
void write();
|
void write();
|
||||||
};
|
};
|
||||||
#pragma endregion gen API
|
#pragma endregion Gen Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma region MACROS
|
#pragma region MACROS
|
||||||
@ -839,7 +833,7 @@ Code make_file_body( char const* name );
|
|||||||
# define using_type( Name_, Type_ ) Code Name_ = gen::def_using( #Name_, t_##Type_ )
|
# define using_type( Name_, Type_ ) Code Name_ = gen::def_using( #Name_, t_##Type_ )
|
||||||
# define variable( Type_, Name_, ... ) Code Name_ = gen::def_variable( t_##Type_, #Name_, __VA_ARGS__ )
|
# define variable( Type_, Name_, ... ) Code Name_ = gen::def_variable( t_##Type_, #Name_, __VA_ARGS__ )
|
||||||
|
|
||||||
# define untyped( Value_ ) gen::untyped_str( txt(Value_) )
|
# define untyped( Value_ ) gen::untyped_str( txt_with_length(Value_) )
|
||||||
# define code_token( Fmt_, ... ) gen::untyped_token_fmt( Fmt_, VA_NARGS( __VA_ARGS__), __VA_ARGS__ )
|
# define code_token( Fmt_, ... ) gen::untyped_token_fmt( Fmt_, VA_NARGS( __VA_ARGS__), __VA_ARGS__ )
|
||||||
# define code_fmt( Fmt_, ... ) gen::untyped_fmt( Fmt_, __VA_ARGS__ )
|
# define code_fmt( Fmt_, ... ) gen::untyped_fmt( Fmt_, __VA_ARGS__ )
|
||||||
# define specifiers( ... ) gen::def_specifiers( VA_NARGS( __VA_ARGS__ ), __VA_ARGS__ )
|
# define specifiers( ... ) gen::def_specifiers( VA_NARGS( __VA_ARGS__ ), __VA_ARGS__ )
|
||||||
@ -849,19 +843,24 @@ Code make_file_body( char const* name );
|
|||||||
# define var( Type_, Name_, ... ) gen::def_variable( Type_, #Name_, __VA_ARGS__ )
|
# define var( Type_, Name_, ... ) gen::def_variable( Type_, #Name_, __VA_ARGS__ )
|
||||||
|
|
||||||
# define make( Type_, Name_, ... ) Code Name_ = make_##Type_( #Name_, __VA_ARGS__ );
|
# define make( Type_, Name_, ... ) Code Name_ = make_##Type_( #Name_, __VA_ARGS__ );
|
||||||
|
# define enum( Name_, Type_, Body_ ) gen::def_enum( #Name_, t_##Type_, Body_ )
|
||||||
# define proc( Name_, Specifiers_, RetType_, Parameters_, Body_ ) Name_ = gen::def_proc( #Name_, Specifiers_, Parameters_, RetType_, Body_ )
|
# define proc( Name_, Specifiers_, RetType_, Parameters_, Body_ ) Name_ = gen::def_proc( #Name_, Specifiers_, Parameters_, RetType_, Body_ )
|
||||||
# define proc_body( ... ) gen::def_proc_body( VA_NARGS( __VA_ARS__ ), __VA_ARGS__ )
|
# define proc_body( ... ) gen::def_proc_body( VA_NARGS( __VA_ARS__ ), __VA_ARGS__ )
|
||||||
# define params( ... ) gen::def_params( VA_NARGS( __VA_ARGS__ ) / 2, __VA_ARGS__ )
|
# define params( ... ) gen::def_params( VA_NARGS( __VA_ARGS__ ) / 2, __VA_ARGS__ )
|
||||||
# define struct( Name_, Parent_, Specifiers_, Body_ ) Name_ = gen::def_struct( #Name_, Body_, Parent_, Specifiers_ )
|
# define struct( Name_, Parent_, Specifiers_, Body_ ) Name_ = gen::def_struct( #Name_, Body_, Parent_, Specifiers_ )
|
||||||
# define struct_body( ... ) gen::def_struct_body( VA_NARGS( __VA_ARGS__ ), __VA_ARGS__ )
|
# define struct_body( ... ) gen::def_struct_body( VA_NARGS( __VA_ARGS__ ), __VA_ARGS__ )
|
||||||
|
|
||||||
# define add_var( Type_, Name_, ... ) add( gen::def_variable( t_##Type_, #Name_, __VA_ARGS__ ) )
|
# define add_var( Value_ ) add( gen::parse_variable( txt_with_length(Value_)) )
|
||||||
# define add_untyped( Value_ ) add( gen::untyped_str( txt( Value ) ) )
|
# define add_untyped( Value_ ) add( gen::untyped_str( txt_with_length( Value_ ) ) )
|
||||||
# define add_ret_type( ... )
|
# define add_type( Value_ ) add( gen::parse_type( txt_with_length(Value_)) )
|
||||||
# define add_params( ... )
|
# define add_params( Value_ ) add( gen::parse_params( txt_with_length(Value_) ))
|
||||||
|
|
||||||
|
# define enum_code( Def_ ) gen::parse_enum( txt( Def_ ), sizeof( txt( Def_ )) )
|
||||||
|
# define global_code( Def_ ) gen::parse_global_body( txt_with_length( Def_ ))
|
||||||
|
# define namespace_code( Def_ ) gen::parse_namespace( txt(Def_), sizeof( txt(Def_)) )
|
||||||
# define proc_code( Def_ ) gen::parse_proc( txt( Def_ ), sizeof( txt( Def_ )) )
|
# define proc_code( Def_ ) gen::parse_proc( txt( Def_ ), sizeof( txt( Def_ )) )
|
||||||
# define struct_code( Def_ ) gen::parse_struct( txt( Def_ ), sizeof( txt( Def_ )) )
|
# define struct_code( Def_ ) gen::parse_struct( txt( Def_ ), sizeof( txt( Def_ )) )
|
||||||
|
# define variable_code( Def_ ) gen::parse_variable( txt_with_length( Def_ ) )
|
||||||
#endif
|
#endif
|
||||||
#pragma endregion MACROS
|
#pragma endregion MACROS
|
||||||
|
|
||||||
@ -873,31 +872,38 @@ namespace gen
|
|||||||
// These are not set until gen::init is called.
|
// These are not set until gen::init is called.
|
||||||
// This just preloads a bunch of Code types into the code pool.
|
// This just preloads a bunch of Code types into the code pool.
|
||||||
|
|
||||||
extern const Code t_void;
|
extern Code t_void;
|
||||||
|
|
||||||
extern const Code t_bool;
|
extern Code t_bool;
|
||||||
extern const Code t_char;
|
extern Code t_char;
|
||||||
extern const Code t_wchar_t;
|
extern Code t_wchar_t;
|
||||||
|
|
||||||
extern const Code t_s8;
|
extern Code t_s8;
|
||||||
extern const Code t_s16;
|
extern Code t_s16;
|
||||||
extern const Code t_s32;
|
extern Code t_s32;
|
||||||
extern const Code t_s64;
|
extern Code t_s64;
|
||||||
|
|
||||||
extern const Code t_u8;
|
extern Code t_u8;
|
||||||
extern const Code t_u16;
|
extern Code t_u16;
|
||||||
extern const Code t_u32;
|
extern Code t_u32;
|
||||||
extern const Code t_u64;
|
extern Code t_u64;
|
||||||
|
|
||||||
extern const Code t_sw;
|
extern Code t_sw;
|
||||||
extern const Code t_uw;
|
extern Code t_uw;
|
||||||
|
|
||||||
extern const Code t_f32;
|
extern Code t_f32;
|
||||||
extern const Code t_f64;
|
extern Code t_f64;
|
||||||
|
|
||||||
extern const Code spec_constexpr;
|
extern Code spec_constexpr;
|
||||||
extern const Code spec_inline;
|
extern Code spec_inline;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace gen
|
||||||
|
{
|
||||||
|
extern Code access_public;
|
||||||
|
extern Code access_protected;
|
||||||
|
extern Code access_private;
|
||||||
|
}
|
||||||
#pragma endregion CONSTANTS
|
#pragma endregion CONSTANTS
|
||||||
#endif
|
#endif
|
||||||
|
543
project/gen.singleheader.c99.cpp
Normal file
543
project/gen.singleheader.c99.cpp
Normal file
@ -0,0 +1,543 @@
|
|||||||
|
/*
|
||||||
|
Will generate a c99 compliant version of the gen library
|
||||||
|
|
||||||
|
Note: This is done this way to test usage of library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define GEN_DEFINE_DSL
|
||||||
|
#include "gen.cpp"
|
||||||
|
|
||||||
|
using namespace gen;
|
||||||
|
|
||||||
|
ct char const* Header_Comment =
|
||||||
|
R"(/*
|
||||||
|
genc: A simple staged metaprogramming library for C99.
|
||||||
|
|
||||||
|
This library is intended for small-to midsize projects.
|
||||||
|
|
||||||
|
AST type checking supports only a small subset of c++.
|
||||||
|
See the 'ECode' namespace and 'gen API' region to see what is supported.
|
||||||
|
|
||||||
|
### *WHAT IS NOT PROVIDED*
|
||||||
|
|
||||||
|
* Macro or template generation : This library is to avoid those, adding support for them adds unnecessary complexity.
|
||||||
|
If you desire define them outside the gen_time scopes.
|
||||||
|
* Expression validation : Execution expressions are defined using the untyped string API.
|
||||||
|
There is no parse API for validating expression (possibly will add in the future)
|
||||||
|
* Complete file parser DSL : This isn't like the unreal header tool.
|
||||||
|
Code injection to file or based off a file contents is not supported by the api. However nothing is stopping you using the library for that purpose.
|
||||||
|
* Modern c++ (STL library) features
|
||||||
|
|
||||||
|
The AST is managed by the library and provided the user via its interface prodedures.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
* The allocator definitions used are exposed to the user incase they want to dictate memory usage
|
||||||
|
* ASTs are wrapped for the user in a Code struct which essentially a warpper for a AST* type.
|
||||||
|
* Both AST and Code have member symbols but their data layout is enforced to be POD types.
|
||||||
|
|
||||||
|
Data layout of AST struct:
|
||||||
|
|
||||||
|
genc_CodeT Type;
|
||||||
|
bool Readonly;
|
||||||
|
genc_AST* Parent;
|
||||||
|
genc_string Name ;
|
||||||
|
genc_string Comment;
|
||||||
|
union {
|
||||||
|
array(genc_AST*) Entries;
|
||||||
|
genc_string Content;
|
||||||
|
};
|
||||||
|
|
||||||
|
*`CodeT` is a typedef for `ECode::Type` which is the type of the enum.*
|
||||||
|
|
||||||
|
ASTs can be set to readonly by calling Code's lock() member function.
|
||||||
|
Adding comments is always available even if the AST is set to readonly.
|
||||||
|
|
||||||
|
### There are four sets of interfaces for Code AST generation the library provides
|
||||||
|
|
||||||
|
* Upfront
|
||||||
|
* Incremental
|
||||||
|
* Parsing
|
||||||
|
* Untyped
|
||||||
|
|
||||||
|
### Upfront Construction
|
||||||
|
|
||||||
|
All component ASTs must be previously constructed, and provided on creation of the code AST.
|
||||||
|
The construction will fail and return InvalidCode otherwise.
|
||||||
|
|
||||||
|
Interface :
|
||||||
|
|
||||||
|
* genc_def_class
|
||||||
|
* genc_def_class_body
|
||||||
|
* genc_def_class_fwd
|
||||||
|
* genc_def_enum
|
||||||
|
* genc_def_enum_class
|
||||||
|
* genc_def_enum_body
|
||||||
|
* genc_def_global_body
|
||||||
|
* genc_def_namespace
|
||||||
|
* genc_def_namespace_body
|
||||||
|
* genc_def_operator
|
||||||
|
* genc_def_param
|
||||||
|
* genc_def_params
|
||||||
|
* genc_def_proc
|
||||||
|
* genc_def_proc_body
|
||||||
|
* genc_def_proc_fwd
|
||||||
|
* genc_def_operator_fwd
|
||||||
|
* genc_def_specifier
|
||||||
|
* genc_def_specifiers
|
||||||
|
* genc_def_struct
|
||||||
|
* genc_def_struct_body
|
||||||
|
* genc_def_struct_fwd
|
||||||
|
* genc_def_variable
|
||||||
|
* genc_def_type
|
||||||
|
* genc_def_using
|
||||||
|
* genc_def_using_namespace
|
||||||
|
|
||||||
|
### Incremental construction
|
||||||
|
|
||||||
|
A Code ast is provided but only completed upfront if all components are provided.
|
||||||
|
Components are then added using the AST API for adding ASTs:
|
||||||
|
|
||||||
|
* genc_code_add( AST*, AST* other ) // Adds AST with validation.
|
||||||
|
* genc_code_add_entry( AST*, AST* other ) // Adds AST entry without validation.
|
||||||
|
|
||||||
|
Code ASTs may be explictly validated at anytime using Code's check() member function.
|
||||||
|
|
||||||
|
Interface :
|
||||||
|
|
||||||
|
* genc_make_class
|
||||||
|
* genc_make_enum
|
||||||
|
* genc_make_enum_class
|
||||||
|
* genc_make_fwd
|
||||||
|
* genc_make_global_body
|
||||||
|
* genc_make_namespace
|
||||||
|
* genc_make_operator
|
||||||
|
* genc_make_params
|
||||||
|
* genc_make_proc
|
||||||
|
* genc_make_specifiers
|
||||||
|
* genc_make_struct
|
||||||
|
* genc_make_variable
|
||||||
|
* genc_make_type
|
||||||
|
* genc_make_using
|
||||||
|
|
||||||
|
### Parse construction
|
||||||
|
|
||||||
|
A string provided to the API is parsed for the intended language construct.
|
||||||
|
|
||||||
|
Interface :
|
||||||
|
|
||||||
|
* genc_parse_class
|
||||||
|
* genc_parse_classes
|
||||||
|
* genc_parse_class_fwd
|
||||||
|
* genc_parse_classes_fwd
|
||||||
|
* genc_parse_enum
|
||||||
|
* genc_parse_enums
|
||||||
|
* genc_parse_global_body
|
||||||
|
* genc_parse_namespace
|
||||||
|
* genc_parse_namespaces
|
||||||
|
* genc_parse_params
|
||||||
|
* genc_parse_proc
|
||||||
|
* genc_parse_procs
|
||||||
|
* genc_parse_operator
|
||||||
|
* genc_parse_operators
|
||||||
|
* genc_parse_specifiers
|
||||||
|
* genc_parse_struct
|
||||||
|
* genc_parse_strucs
|
||||||
|
* genc_parse_variable
|
||||||
|
* genc_parse_variables
|
||||||
|
* genc_parse_type
|
||||||
|
* genc_parse_types
|
||||||
|
* genc_parse_using
|
||||||
|
* genc_parse_usings
|
||||||
|
|
||||||
|
The parse API treats any execution scope definitions with no validation and are turned into untyped Code ASTs.
|
||||||
|
This includes the assignmetn of variables; due to the library not yet supporting c/c++ expression parsing.
|
||||||
|
|
||||||
|
The plural variants provide an array of codes, its up to the user to add them to a body AST
|
||||||
|
(they are not auto-added to a body)
|
||||||
|
|
||||||
|
### Untyped constructions
|
||||||
|
|
||||||
|
Code ASTs are constructed using unvalidated strings.
|
||||||
|
|
||||||
|
Interface :
|
||||||
|
|
||||||
|
* genc_untyped_str
|
||||||
|
* genc_untyped_fmt
|
||||||
|
* genc_untyped_token_fmt
|
||||||
|
|
||||||
|
During serialization any untyped Code AST is has its string value directly injected inline of
|
||||||
|
whatever context the content existed as an entry within.
|
||||||
|
Even though thse are not validated from somewhat correct c/c++ syntax or components, it doesn't mean that
|
||||||
|
Untyped code can be added as any component of a Code AST:
|
||||||
|
|
||||||
|
* Untyped code cannot have children, thus there cannot be recursive injection this way.
|
||||||
|
* Untyped code can only be a child of a parent of body AST, or for values of an assignment.
|
||||||
|
|
||||||
|
These restrictions help prevent abuse of untyped code to some extent.
|
||||||
|
*/
|
||||||
|
)";
|
||||||
|
|
||||||
|
Code IfDef_GENC_IMPLEMENTATION;
|
||||||
|
Code EndIf_GENC_IMPLEMENTATION;
|
||||||
|
|
||||||
|
Code make_log_failure()
|
||||||
|
{
|
||||||
|
Code result = make_global_body();
|
||||||
|
{
|
||||||
|
result->add( untyped_str(
|
||||||
|
R"(#ifdef GEN_USE_FATAL)"
|
||||||
|
));
|
||||||
|
|
||||||
|
result->add( proc_code(
|
||||||
|
inline
|
||||||
|
sw genc_log_failure(char const *fmt, ...)
|
||||||
|
{
|
||||||
|
if ( genc_global_ShouldShowDebug == false )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sw res;
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
va_start(va, fmt);
|
||||||
|
res = zpl_printf_va(fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
result->add( untyped_str(
|
||||||
|
R"(#else)"
|
||||||
|
));
|
||||||
|
|
||||||
|
result->add( parse_proc(
|
||||||
|
R"(inline
|
||||||
|
sw genc_log_failure(char const *fmt, ...)
|
||||||
|
{
|
||||||
|
local_persist thread_local
|
||||||
|
char buf[ZPL_PRINTF_MAXLEN] = { 0 };
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
#if Build_Debug
|
||||||
|
va_start(va, fmt);
|
||||||
|
zpl_snprintf_va(buf, ZPL_PRINTF_MAXLEN, fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
assert_crash(buf);
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
va_start(va, fmt);
|
||||||
|
zpl_printf_err_va( fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
zpl_exit(1);
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
})"
|
||||||
|
, 372
|
||||||
|
));
|
||||||
|
|
||||||
|
result->add( untyped_str(
|
||||||
|
R"(#endif)"
|
||||||
|
));
|
||||||
|
|
||||||
|
result->check();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Code make_ECode()
|
||||||
|
{
|
||||||
|
Code ECode = make_global_body();
|
||||||
|
{
|
||||||
|
ECode->add( parse_enum(
|
||||||
|
R"(enum genc_ECode
|
||||||
|
{
|
||||||
|
Invalid,
|
||||||
|
Untyped,
|
||||||
|
Enum,
|
||||||
|
Enum_Body,
|
||||||
|
Global_Body,
|
||||||
|
Parameters,
|
||||||
|
Proc,
|
||||||
|
Proc_Body,
|
||||||
|
Proc_Forward,
|
||||||
|
Specifiers,
|
||||||
|
Struct,
|
||||||
|
Struct_Body,
|
||||||
|
Variable,
|
||||||
|
Typedef,
|
||||||
|
Typename,
|
||||||
|
|
||||||
|
Num_Types
|
||||||
|
};
|
||||||
|
typedef u32 genc_CodeT;)" + 1
|
||||||
|
, 280
|
||||||
|
));
|
||||||
|
|
||||||
|
ECode->add( proc_code(
|
||||||
|
inline
|
||||||
|
char const* genc_ecode_to_str( Type type )
|
||||||
|
{
|
||||||
|
genc_local_persist
|
||||||
|
char const* lookup[Num_Types] = {
|
||||||
|
"Invalid",
|
||||||
|
"Untyped",
|
||||||
|
"Access_Public",
|
||||||
|
"Access_Private",
|
||||||
|
"Access_Protected",
|
||||||
|
"Class",
|
||||||
|
"Enum",
|
||||||
|
"Enum_Body",
|
||||||
|
"Global_Body",
|
||||||
|
"Namespace",
|
||||||
|
"Namespace_Body",
|
||||||
|
"Parameters",
|
||||||
|
"Proc",
|
||||||
|
"Proc_Body",
|
||||||
|
"Proc_Forward",
|
||||||
|
"Specifiers",
|
||||||
|
"Struct",
|
||||||
|
"Struct_Body",
|
||||||
|
"Variable",
|
||||||
|
"Typedef",
|
||||||
|
"Typename",
|
||||||
|
"Using",
|
||||||
|
};
|
||||||
|
|
||||||
|
return lookup[ type ];
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
ECode->check();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ECode;
|
||||||
|
}
|
||||||
|
|
||||||
|
Code make_EOperator()
|
||||||
|
{
|
||||||
|
Code eoperator = make_global_body();
|
||||||
|
|
||||||
|
return eoperator;
|
||||||
|
}
|
||||||
|
|
||||||
|
Code make_ESpecifier()
|
||||||
|
{
|
||||||
|
Code especifier = make_global_body();
|
||||||
|
|
||||||
|
return especifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
Code make_Code()
|
||||||
|
{
|
||||||
|
Code code = make_global_body();
|
||||||
|
|
||||||
|
code->add( struct_code(
|
||||||
|
struct genc_AST
|
||||||
|
{
|
||||||
|
genc_CodeT Type;
|
||||||
|
bool Readonly;
|
||||||
|
genc_AST* Parent;
|
||||||
|
genc_string Name;
|
||||||
|
genc_string Comment;
|
||||||
|
union {
|
||||||
|
array(genc_AST*) Entries;
|
||||||
|
genc_string Content;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
typedef struct genc_AST genc_AST;
|
||||||
|
typedef genc_AST* Code;
|
||||||
|
));
|
||||||
|
|
||||||
|
code->add( proc_code(
|
||||||
|
bool genc_ast_add( genc_Code other );
|
||||||
|
));
|
||||||
|
|
||||||
|
code->add( proc_code(
|
||||||
|
genc_forceinline
|
||||||
|
void genc_ast_add_entry( genc_Code self, genc_Code other )
|
||||||
|
{
|
||||||
|
genc_array_append( self->Entries, other );
|
||||||
|
|
||||||
|
other->Parent = self;
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
code->add( untyped_str(
|
||||||
|
R"(#define genc_code_body( AST_ ) AST->Entries[0])", 47
|
||||||
|
));
|
||||||
|
|
||||||
|
code->add( proc_code(
|
||||||
|
genc_forceinline
|
||||||
|
bool genc_code_has_entries( Code self ) const
|
||||||
|
{
|
||||||
|
genc_local_persist
|
||||||
|
bool lookup[ genc_ECode::Num_Types] = {
|
||||||
|
false, // Invalid
|
||||||
|
false, // Untyped
|
||||||
|
true, // Global_Body
|
||||||
|
true, // Parameters
|
||||||
|
true, // Proc
|
||||||
|
true, // Proc_Body
|
||||||
|
true, // Proc_Foward
|
||||||
|
false, // Specifies
|
||||||
|
true, // Struct
|
||||||
|
true, // Struct_Body
|
||||||
|
true, // Variable
|
||||||
|
true, // Typedef
|
||||||
|
true, // Typename
|
||||||
|
};
|
||||||
|
|
||||||
|
return lookup[self->Type];
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
code->check();
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
Code make_static_Data()
|
||||||
|
{
|
||||||
|
Code
|
||||||
|
data = make_global_body();
|
||||||
|
data->add( IfDef_GENC_IMPLEMENTATION );
|
||||||
|
data->add( global_code(
|
||||||
|
static genc_array(genc_AST) genc_CodePool = nullptr;
|
||||||
|
|
||||||
|
static genc_array(genc_arena) genc_StringArenas = nullptr;
|
||||||
|
|
||||||
|
static genc_StringTable genc_StringMap;
|
||||||
|
static genc_TypeTable genc_TypeMap;
|
||||||
|
|
||||||
|
static sw genc_InitSize_CodePool = genc_megabytes(64);
|
||||||
|
static sw genc_InitSize_StringArena = genc_megabytes(32);
|
||||||
|
static sw genc_InitSize_StringTable = genc_megabytes(4);
|
||||||
|
static sw genc_InitSize_TypeTable = genc_megabytes(4);
|
||||||
|
|
||||||
|
static allocator genc_Allocator_CodePool = zpl_heap();
|
||||||
|
static allocator genc_Allocator_StringArena = zpl_heap();
|
||||||
|
static allocator genc_Allocator_StringTable = zpl_heap();
|
||||||
|
static allocator genc_Allocator_TypeTable = zpl_heap();
|
||||||
|
));
|
||||||
|
data->add( untyped_str( R"(#ifdef GENC_DEFINE_LIBRARY_CODE_CONSTANTS)"));
|
||||||
|
data->add( global_code(
|
||||||
|
Code t_void;
|
||||||
|
|
||||||
|
Code t_bool;
|
||||||
|
Code t_char;
|
||||||
|
Code t_char_wide;
|
||||||
|
|
||||||
|
Code t_s8;
|
||||||
|
Code t_s16;
|
||||||
|
Code t_s32;
|
||||||
|
Code t_s64;
|
||||||
|
|
||||||
|
Code t_u8;
|
||||||
|
Code t_u16;
|
||||||
|
Code t_u32;
|
||||||
|
Code t_u64;
|
||||||
|
|
||||||
|
Code t_sw;
|
||||||
|
Code t_uw;
|
||||||
|
|
||||||
|
Code t_f32;
|
||||||
|
Code t_f64;
|
||||||
|
));
|
||||||
|
data->add( untyped_str( R"(#endif)"));
|
||||||
|
data->add( global_code(
|
||||||
|
Code spec_inline;
|
||||||
|
Code spec_const;
|
||||||
|
));
|
||||||
|
data->add( EndIf_GENC_IMPLEMENTATION );
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Code make_make_code()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Code make_init()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Code make_mem_config_interface()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Code make_internal_funcs()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Code make_upfront()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Code make_incremental()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Code make_parsing()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Code make_untyped()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Code make_interface()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int gen_main()
|
||||||
|
{
|
||||||
|
Memory::setup();
|
||||||
|
gen::init();
|
||||||
|
|
||||||
|
IfDef_GENC_IMPLEMENTATION = untyped(
|
||||||
|
R"(#ifdef GENC_IMPLEMENTATION)"
|
||||||
|
);
|
||||||
|
|
||||||
|
EndIf_GENC_IMPLEMENTATION = untyped(
|
||||||
|
R"(#endif // GENC_IMPLEMENTATION)"
|
||||||
|
);
|
||||||
|
|
||||||
|
Code header_comment = untyped_str( Header_Comment, sizeof( Header_Comment ) );
|
||||||
|
Code log_failure = make_log_failure();
|
||||||
|
|
||||||
|
Code ecode = make_ECode();
|
||||||
|
Code eoperator = make_EOperator();
|
||||||
|
Code especifier = make_ESpecifier();
|
||||||
|
Code code = make_Code();
|
||||||
|
|
||||||
|
Builder
|
||||||
|
builder;
|
||||||
|
builder.open( "genc.h" );
|
||||||
|
|
||||||
|
builder.print( header_comment );
|
||||||
|
builder.print( log_failure );
|
||||||
|
builder.print( ecode );
|
||||||
|
builder.print( eoperator );
|
||||||
|
builder.print( especifier );
|
||||||
|
builder.print( code );
|
||||||
|
|
||||||
|
builder.write();
|
||||||
|
|
||||||
|
Memory::cleanup();
|
||||||
|
return 0;
|
||||||
|
}
|
55
project/gen.singleheader.c99.data
Normal file
55
project/gen.singleheader.c99.data
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# HEADER COMMENT
|
||||||
|
1, 166
|
||||||
|
|
||||||
|
# CODE TYPES
|
||||||
|
Invalid
|
||||||
|
Untyped
|
||||||
|
Enum
|
||||||
|
Enum_Body
|
||||||
|
Global_Body
|
||||||
|
Parameters
|
||||||
|
Proc
|
||||||
|
Proc_Body
|
||||||
|
Proc_Forward
|
||||||
|
Specifiers
|
||||||
|
Struct
|
||||||
|
Struct_Body
|
||||||
|
Variable
|
||||||
|
Typedef
|
||||||
|
Typename
|
||||||
|
Using
|
||||||
|
|
||||||
|
# CODE_HAS_ENTRIES
|
||||||
|
|
||||||
|
# SPECIFIER_TYPES
|
||||||
|
Attribute
|
||||||
|
Alignas
|
||||||
|
Constexpr
|
||||||
|
Const
|
||||||
|
Inline
|
||||||
|
Pointer
|
||||||
|
API_Import
|
||||||
|
API_Export
|
||||||
|
External_Linkage
|
||||||
|
Internal_Linkage
|
||||||
|
Local_Persist
|
||||||
|
Thread_Local
|
||||||
|
Invalid
|
||||||
|
|
||||||
|
# SPECIFIER_STRINGS
|
||||||
|
"alignas",
|
||||||
|
"const",
|
||||||
|
"inline",
|
||||||
|
"*",
|
||||||
|
#if defined(ZPL_SYSTEM_WINDOWS)
|
||||||
|
"__declspec(dllexport)",
|
||||||
|
"__declspec(dllimport)",
|
||||||
|
#elif defined(ZPL_SYSTEM_MACOS)
|
||||||
|
"__attribute__ ((visibility (\"default\")))",
|
||||||
|
"__attribute__ ((visibility (\"default\")))",
|
||||||
|
#endif
|
||||||
|
"extern",
|
||||||
|
"static",
|
||||||
|
"static",
|
||||||
|
"thread_local"
|
||||||
|
|
34
project/gen.singleheader.c99.refactor
Normal file
34
project/gen.singleheader.c99.refactor
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
__VERSION 1
|
||||||
|
|
||||||
|
word AST, genc_AST
|
||||||
|
word Code, genc_Code
|
||||||
|
|
||||||
|
word ECode, genc_ECode
|
||||||
|
word EOperator, genc_EOperator
|
||||||
|
word ESpecifier, genc_ESpecifier
|
||||||
|
word CodeT, genc_CodeT
|
||||||
|
|
||||||
|
word string, genc_string
|
||||||
|
word init, genc_init
|
||||||
|
|
||||||
|
namespace def_, genc_def_
|
||||||
|
namespace make_, genc_make_
|
||||||
|
namespace parse_, genc_parse_
|
||||||
|
namespace untyped_, genc_untyped_
|
||||||
|
namespace set_init_, genc_set_init_
|
||||||
|
namespace set_allocator_, genc_set_allocator_
|
||||||
|
|
||||||
|
word clean_code_pool, genc_clean_code_pool
|
||||||
|
|
||||||
|
word Builder, genc_Builder
|
||||||
|
|
||||||
|
word CodePool, genc_CodePool
|
||||||
|
word StringArenas, genc_StringArenas
|
||||||
|
word CodePOD, genc_AST
|
||||||
|
word StringMap, genc_StringMap
|
||||||
|
word TypeMap, genc_TypeMap
|
||||||
|
|
||||||
|
namespace InitSize_, genc_InitSize_
|
||||||
|
namespace Allocator_, genc_Allocator_
|
||||||
|
|
||||||
|
namespace spec_, genc_spec
|
0
project/gen.singleheader.cpp
Normal file
0
project/gen.singleheader.cpp
Normal file
4
singleheader/genc.refactor
Normal file
4
singleheader/genc.refactor
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// Removes the genc_ namespace if desired
|
||||||
|
|
||||||
|
namespace genc_
|
||||||
|
|
@ -16,7 +16,7 @@
|
|||||||
#ifndef GEN_DEFINE_DSL
|
#ifndef GEN_DEFINE_DSL
|
||||||
using namespace gen;
|
using namespace gen;
|
||||||
|
|
||||||
Code t_allocator = def_type( txt(allocator) );
|
Code t_allocator = def_type( txt(allocator) );
|
||||||
|
|
||||||
Code header;
|
Code header;
|
||||||
{
|
{
|
||||||
@ -64,7 +64,6 @@
|
|||||||
return ArrayBase;
|
return ArrayBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define gen_array( Type_ ) gen__array( #Type_, sizeof(Type_), a_base )
|
|
||||||
Code gen__array( char const* type_str, s32 type_size, Code parent )
|
Code gen__array( char const* type_str, s32 type_size, Code parent )
|
||||||
{
|
{
|
||||||
#ifndef GEN_DEFINE_DSL
|
#ifndef GEN_DEFINE_DSL
|
||||||
@ -155,6 +154,7 @@
|
|||||||
Code append = make_proc( "append" );
|
Code append = make_proc( "append" );
|
||||||
{
|
{
|
||||||
append->add( def_params( 1, type, "value") );
|
append->add( def_params( 1, type, "value") );
|
||||||
|
append->add( t_bool );
|
||||||
|
|
||||||
Code
|
Code
|
||||||
body = append.body();
|
body = append.body();
|
||||||
@ -172,6 +172,8 @@
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
)));
|
)));
|
||||||
|
|
||||||
|
append->check();
|
||||||
}
|
}
|
||||||
|
|
||||||
Code back;
|
Code back;
|
||||||
@ -295,7 +297,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
Code set_capacity = parse_proc( txt_with_length(
|
Code set_capacity = parse_proc( txt_with_length(
|
||||||
bool set_capacity( new_capacity )
|
bool set_capacity( sw new_capacity )
|
||||||
{
|
{
|
||||||
Header& header = get_header();
|
Header& header = get_header();
|
||||||
|
|
||||||
@ -305,7 +307,7 @@
|
|||||||
if ( capacity < header.Num )
|
if ( capacity < header.Num )
|
||||||
header.Num = capacity;
|
header.Num = capacity;
|
||||||
|
|
||||||
uw size = sizeof(Header) + sizeof(Type) * capacity;
|
sw size = sizeof(Header) + sizeof(Type) * capacity;
|
||||||
Header* new_header = rcast( Header* alloc( header.Allocator, size ));
|
Header* new_header = rcast( Header* alloc( header.Allocator, size ));
|
||||||
|
|
||||||
if ( new_header == nullptr )
|
if ( new_header == nullptr )
|
||||||
@ -591,18 +593,58 @@
|
|||||||
return array_def;
|
return array_def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ArrayRequest
|
||||||
|
{
|
||||||
|
char const* Name;
|
||||||
|
sw Size;
|
||||||
|
};
|
||||||
|
|
||||||
|
array(ArrayRequest) UserArrayGenQueue;
|
||||||
|
|
||||||
|
#define gen_array( Type_ ) add_gen_array_request( #Type_, sizeof(Type_) )
|
||||||
|
|
||||||
|
void add_gen_array_request( const char* type_str, sw type_size )
|
||||||
|
{
|
||||||
|
ArrayRequest request = { type_str, type_size };
|
||||||
|
|
||||||
|
array_append( UserArrayGenQueue, request );
|
||||||
|
}
|
||||||
|
|
||||||
u32 gen_array_file()
|
u32 gen_array_file()
|
||||||
{
|
{
|
||||||
Code a_base = gen__array_base();
|
Code a_base = gen__array_base();
|
||||||
|
|
||||||
Code a_u32 = gen_array( u32 );
|
add_gen_array_request( "u32", sizeof(u32) );
|
||||||
Code a_cstr = gen_array( char const* );
|
gen_array( char const* );
|
||||||
|
|
||||||
|
array(Code) array_asts;
|
||||||
|
array_init( array_asts, g_allocator );
|
||||||
|
|
||||||
|
sw left = array_count( UserArrayGenQueue );
|
||||||
|
sw index = 0;
|
||||||
|
while( left -- )
|
||||||
|
{
|
||||||
|
ArrayRequest request = UserArrayGenQueue[index];
|
||||||
|
|
||||||
|
Code result = gen__array( request.Name, request.Size, a_base );
|
||||||
|
|
||||||
|
array_append( array_asts, result );
|
||||||
|
}
|
||||||
|
|
||||||
Builder
|
Builder
|
||||||
arraygen;
|
arraygen;
|
||||||
arraygen.open( "Array.gen.hpp" );
|
arraygen.open( "Array.gen.hpp" );
|
||||||
arraygen.print( a_u32 );
|
|
||||||
arraygen.print( a_cstr );
|
left = array_count( array_asts );
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
while( left-- )
|
||||||
|
{
|
||||||
|
Code code = array_asts[index];
|
||||||
|
|
||||||
|
arraygen.print( code );
|
||||||
|
}
|
||||||
|
|
||||||
arraygen.write();
|
arraygen.write();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
22
test/c99/meson.build
Normal file
22
test/c99/meson.build
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
project( 'test', 'c', default_options : ['buildtype=debug'] )
|
||||||
|
|
||||||
|
# add_global_arguments('-E', language : 'cpp')
|
||||||
|
|
||||||
|
includes = include_directories(
|
||||||
|
[
|
||||||
|
'../gen',
|
||||||
|
'../../singleheader'
|
||||||
|
])
|
||||||
|
|
||||||
|
# get_sources = files('./get_sources.ps1')
|
||||||
|
# sources = files(run_command('powershell', get_sources, check: true).stdout().strip().split('\n'))
|
||||||
|
|
||||||
|
sources = [ 'test.c99.c' ]
|
||||||
|
|
||||||
|
if get_option('buildtype').startswith('debug')
|
||||||
|
|
||||||
|
add_project_arguments('-DBuild_Debug', language : ['c' ])
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
executable( 'test_c99', sources, include_directories : includes )
|
79
test/c99/table.h
Normal file
79
test/c99/table.h
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#include "gen.h"
|
||||||
|
|
||||||
|
#define Table( Type_ ) Table_##Type_
|
||||||
|
|
||||||
|
typedef u64(*)(void*) HashingFn;
|
||||||
|
|
||||||
|
#if gen_time
|
||||||
|
# define gen_table( Type_, HashingFn_ ) gen_request_table( #Type_, sizeof(Type_), HashingFn_ )
|
||||||
|
|
||||||
|
u64 table_default_hash_fn( void* address )
|
||||||
|
{
|
||||||
|
return crc32( address, 4 );
|
||||||
|
}
|
||||||
|
|
||||||
|
Code gen_table_code( char const* type_str, sw type_size, HashingFn hash_fn )
|
||||||
|
{
|
||||||
|
Code table;
|
||||||
|
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TableRequest
|
||||||
|
{
|
||||||
|
char const* Type;
|
||||||
|
sw Size;
|
||||||
|
HashingFn HashFn;
|
||||||
|
};
|
||||||
|
|
||||||
|
array(TableRequest) TableRequests;
|
||||||
|
|
||||||
|
void gen_request_table( const char* type_str, sw type_size, HashingFn hash_fn )
|
||||||
|
{
|
||||||
|
TableRequest request = { type_str, type_size, hash_fn };
|
||||||
|
|
||||||
|
array_append( TableRequests, request );
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 gen_table_file()
|
||||||
|
{
|
||||||
|
gen_table( u32 );
|
||||||
|
gen_table( char const* );
|
||||||
|
|
||||||
|
array(Code) array_asts;
|
||||||
|
array_init( array_asts, g_allocator );
|
||||||
|
|
||||||
|
sw left = array_count( TableRequests );
|
||||||
|
sw index = 0;
|
||||||
|
while( left -- )
|
||||||
|
{
|
||||||
|
ArrayRequest request = TableRequests[index];
|
||||||
|
|
||||||
|
Code result = gen_table_code( request.Name, request.Size, request.HashFn );
|
||||||
|
|
||||||
|
array_append( array_asts, result );
|
||||||
|
}
|
||||||
|
|
||||||
|
Builder
|
||||||
|
arraygen;
|
||||||
|
arraygen.open( "table.gen.h" );
|
||||||
|
|
||||||
|
left = array_count( array_asts );
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
while( left-- )
|
||||||
|
{
|
||||||
|
Code code = array_asts[index];
|
||||||
|
|
||||||
|
arraygen.print( code );
|
||||||
|
}
|
||||||
|
|
||||||
|
arraygen.write();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef gen_time
|
||||||
|
# include "table.gen.h"
|
||||||
|
#endif
|
||||||
|
|
40
test/c99/test.c99.c
Normal file
40
test/c99/test.c99.c
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#define GENC_IMPLEMENTATION
|
||||||
|
#include "genc.h"
|
||||||
|
#include "table.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct Test
|
||||||
|
{
|
||||||
|
u64 A;
|
||||||
|
u64 B;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if gen_time
|
||||||
|
|
||||||
|
|
||||||
|
u64 hash_struct( void* test )
|
||||||
|
{
|
||||||
|
return crc32( ((Test)test).A, sizeof(u64) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int gen_main()
|
||||||
|
{
|
||||||
|
gen_table( Test, & hash_struct )
|
||||||
|
|
||||||
|
gen_table_file();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if runtime
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
Table(Test) test_table;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
@ -25,7 +25,7 @@
|
|||||||
#ifndef GEN_DEFINE_DSL
|
#ifndef GEN_DEFINE_DSL
|
||||||
string name = string_sprintf( g_allocator, (char*)sprintf_buf, ZPL_PRINTF_MAXLEN, "square", type );
|
string name = string_sprintf( g_allocator, (char*)sprintf_buf, ZPL_PRINTF_MAXLEN, "square", type );
|
||||||
|
|
||||||
#if 1
|
#if 0
|
||||||
Code square;
|
Code square;
|
||||||
{
|
{
|
||||||
Code params = def_params( 1, integral_type, "value" );
|
Code params = def_params( 1, integral_type, "value" );
|
||||||
@ -43,9 +43,9 @@
|
|||||||
return value * value;
|
return value * value;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
char const* gen_code = token_fmt( tmpl, 1, type );
|
char const* gen_code = token_fmt( tmpl, 1, "type", type );
|
||||||
|
|
||||||
Code square = parse_proc(gen_code);
|
Code square = parse_proc(gen_code, strlen(gen_code));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
0
test/test.singleheader.cpp
Normal file
0
test/test.singleheader.cpp
Normal file
2
thirdparty/zpl.h
vendored
2
thirdparty/zpl.h
vendored
@ -5095,8 +5095,8 @@ License:
|
|||||||
|
|
||||||
typedef struct string_header {
|
typedef struct string_header {
|
||||||
allocator allocator;
|
allocator allocator;
|
||||||
sw length;
|
|
||||||
sw capacity;
|
sw capacity;
|
||||||
|
sw length;
|
||||||
} string_header;
|
} string_header;
|
||||||
|
|
||||||
#define ZPL_STRING_HEADER(str) (zpl_cast(ZPL_NS string_header *)(str) - 1)
|
#define ZPL_STRING_HEADER(str) (zpl_cast(ZPL_NS string_header *)(str) - 1)
|
||||||
|
Loading…
Reference in New Issue
Block a user