mirror of
https://github.com/Ed94/gencpp.git
synced 2024-11-10 02:54:53 -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",
|
||||
"xtr1common": "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++.
|
||||
|
||||
This library is intended for small-to midsize projects.
|
||||
This library is intended for small-to midsized projects.
|
||||
|
||||
### TOC
|
||||
|
||||
@ -174,20 +174,27 @@ The construction will fail and return InvalidCode otherwise.
|
||||
|
||||
Interface :
|
||||
|
||||
* def_forward_decl
|
||||
* def_class
|
||||
* def_class_body
|
||||
* def_class_fwd
|
||||
* def_enum
|
||||
* def_enum_class
|
||||
* def_enum_body
|
||||
* def_global_body
|
||||
* def_proc
|
||||
* def_proc_body
|
||||
* def_namespace
|
||||
* def_namespace_body
|
||||
* def_operator
|
||||
* def_operator_fwd
|
||||
* def_param
|
||||
* def_params
|
||||
* def_operator
|
||||
* def_proc
|
||||
* def_proc_body
|
||||
* def_proc_fwd
|
||||
* def_specifier
|
||||
* def_specifiers
|
||||
* def_struct
|
||||
* def_struct_body
|
||||
* def_struct_fwd
|
||||
* def_variable
|
||||
* def_type
|
||||
* def_using
|
||||
@ -206,19 +213,20 @@ Code ASTs may be explictly validated at anytime using Code's check() member func
|
||||
|
||||
Interface :
|
||||
|
||||
* make_forward_decl
|
||||
* make_class
|
||||
* make_enum
|
||||
* make_enum_class
|
||||
* make_fwd
|
||||
* make_global_body
|
||||
* make_proc
|
||||
* make_namespace
|
||||
* make_params
|
||||
* make_operator
|
||||
* make_params
|
||||
* make_proc
|
||||
* make_specifiers
|
||||
* make_struct
|
||||
* make_variable
|
||||
* make_type
|
||||
* make_using
|
||||
* make_using_namespace
|
||||
|
||||
### Parse construction
|
||||
|
||||
@ -226,19 +234,29 @@ A string provided to the API is parsed for the intended language construct.
|
||||
|
||||
Interface :
|
||||
|
||||
* parse_forward_decl
|
||||
* parse_class
|
||||
* parse_glboal_body
|
||||
* parse_proc
|
||||
* parse_classes
|
||||
* parse_class_fwd
|
||||
* parse_classes_fwd
|
||||
* parse_enum
|
||||
* parse_enums
|
||||
* parse_global_body
|
||||
* parse_namespace
|
||||
* parse_namespaces
|
||||
* parse_params
|
||||
* parse_proc
|
||||
* parse_procs
|
||||
* parse_operator
|
||||
* parse_operators
|
||||
* parse_specifiers
|
||||
* parse_struct
|
||||
* parse_strucs
|
||||
* parse_variable
|
||||
* parse_variables
|
||||
* parse_type
|
||||
* parse_types
|
||||
* parse_using
|
||||
* parse_using
|
||||
* 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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -73,17 +73,17 @@
|
||||
#endif
|
||||
|
||||
#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 forceinline ZPL_ALWAYS_INLINE
|
||||
#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 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( 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() \
|
||||
do \
|
||||
@ -131,6 +131,8 @@ namespace Memory
|
||||
void cleanup();
|
||||
}
|
||||
|
||||
sw token_fmt_va( char* buf, uw buf_size, char const* fmt, s32 num_tokens, va_list va );
|
||||
|
||||
inline
|
||||
char const* token_fmt( char const* fmt, sw num_tokens, ... )
|
||||
{
|
||||
@ -185,3 +187,4 @@ sw fatal(char const *fmt, ...)
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
411
project/gen.cpp
411
project/gen.cpp
@ -4,40 +4,57 @@
|
||||
#ifdef gen_time
|
||||
namespace gen
|
||||
{
|
||||
ZPL_TABLE_DEFINE( StringTable, str_tbl_, string );
|
||||
ZPL_TABLE_DEFINE( TypeTable, type_tbl_ , Code );
|
||||
|
||||
namespace StaticData
|
||||
{
|
||||
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
|
||||
# ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||
const Code t_void;
|
||||
Code t_void;
|
||||
|
||||
const Code t_bool;
|
||||
const Code t_char;
|
||||
const Code t_char_wide;
|
||||
Code t_bool;
|
||||
Code t_char;
|
||||
Code t_char_wide;
|
||||
|
||||
const Code t_s8;
|
||||
const Code t_s16;
|
||||
const Code t_s32;
|
||||
const Code t_s64;
|
||||
Code t_s8;
|
||||
Code t_s16;
|
||||
Code t_s32;
|
||||
Code t_s64;
|
||||
|
||||
const Code t_u8;
|
||||
const Code t_u16;
|
||||
const Code t_u32;
|
||||
const Code t_u64;
|
||||
Code t_u8;
|
||||
Code t_u16;
|
||||
Code t_u32;
|
||||
Code t_u64;
|
||||
|
||||
const Code t_sw;
|
||||
const Code t_uw;
|
||||
Code t_sw;
|
||||
Code t_uw;
|
||||
|
||||
const Code t_f32;
|
||||
const Code t_f64;
|
||||
|
||||
const Code spec_constexpr;
|
||||
const Code spec_inline;
|
||||
Code t_f32;
|
||||
Code t_f64;
|
||||
# endif
|
||||
#pragma endregion CONSTANTS
|
||||
|
||||
Code spec_constexpr;
|
||||
Code spec_inline;
|
||||
#pragma endregion CONSTANTS
|
||||
|
||||
/*
|
||||
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 = def_type( txt(void) );
|
||||
|
||||
# define def_constant_code_type( Type_ ) \
|
||||
Code& \
|
||||
t_##Type_##_write = ccast( Code, t_##Type_ ); \
|
||||
t_##Type_##_write = def_type( txt(Type_) ) \
|
||||
# define def_constant_code_type( Type_ ) \
|
||||
Code& \
|
||||
t_##Type_ = def_type( txt(Type_) )
|
||||
|
||||
def_constant_code_type( bool );
|
||||
def_constant_code_type( char );
|
||||
@ -109,80 +125,92 @@ namespace gen
|
||||
#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 )
|
||||
{
|
||||
log_failure( "gen::decl_type: type is not a Typename");
|
||||
return InvalidCode;
|
||||
}
|
||||
sw size = array_capacity( StaticData::CodePool );
|
||||
|
||||
if ( type->Type != Typename )
|
||||
{
|
||||
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;
|
||||
zpl_memset( StaticData::CodePool, 0, size );
|
||||
}
|
||||
|
||||
Code decl_proc( char const* name
|
||||
, Code specifiers
|
||||
, Code params
|
||||
, Code ret_type
|
||||
)
|
||||
allocator get_string_allocator( s32 str_length )
|
||||
{
|
||||
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" );
|
||||
return InvalidCode;
|
||||
arena new_arena;
|
||||
arena_init_from_allocator( & new_arena, Allocator_StringArena, InitSize_StringArena );
|
||||
|
||||
array_append( StringArenas, new_arena );
|
||||
|
||||
return arena_allocator( StringArenas );
|
||||
}
|
||||
|
||||
if ( params->Type != Parameters )
|
||||
{
|
||||
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;
|
||||
return arena_allocator( StringArenas );
|
||||
}
|
||||
|
||||
// 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, ... )
|
||||
{
|
||||
using namespace ECode;
|
||||
@ -271,7 +299,7 @@ namespace gen
|
||||
|
||||
switch ( body->Type )
|
||||
{
|
||||
case Function_Body:
|
||||
case Proc_Body:
|
||||
case Untyped:
|
||||
break;
|
||||
|
||||
@ -285,7 +313,7 @@ namespace gen
|
||||
Code
|
||||
result = make_code();
|
||||
result->Name = string_make( g_allocator, name );
|
||||
result->Type = Function;
|
||||
result->Type = Proc;
|
||||
|
||||
array_init( result->Entries, g_allocator );
|
||||
|
||||
@ -331,8 +359,7 @@ namespace gen
|
||||
|
||||
switch ( entry->Type )
|
||||
{
|
||||
case Decl_Function:
|
||||
case Decl_Type:
|
||||
case Proc_Forward:
|
||||
case Namespace:
|
||||
case Namespace_Body:
|
||||
case Parameters:
|
||||
@ -387,8 +414,7 @@ namespace gen
|
||||
|
||||
switch ( entry->Type )
|
||||
{
|
||||
case Decl_Function:
|
||||
case Decl_Type:
|
||||
case Proc_Forward:
|
||||
case Namespace:
|
||||
case Namespace_Body:
|
||||
case Parameters:
|
||||
@ -630,7 +656,7 @@ namespace gen
|
||||
return result;
|
||||
}
|
||||
|
||||
Code def_type( char const* name )
|
||||
Code def_type( char const* name, Code specifiers )
|
||||
{
|
||||
Code
|
||||
result = make_code();
|
||||
@ -654,57 +680,9 @@ namespace gen
|
||||
|
||||
return result;
|
||||
}
|
||||
# pragma endregion Upfront Constructors
|
||||
|
||||
Code untyped_str(char const* fmt)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
# pragma region Incremetnal Constructors
|
||||
Code make_proc( char const* name
|
||||
, Code specifiers
|
||||
, Code params
|
||||
@ -734,7 +712,7 @@ namespace gen
|
||||
Code
|
||||
result = make_code();
|
||||
result->Name = string_make( g_allocator, name );
|
||||
result->Type = Function;
|
||||
result->Type = Proc;
|
||||
|
||||
array_init( result->Entries, g_allocator );
|
||||
|
||||
@ -788,12 +766,12 @@ namespace gen
|
||||
return result;
|
||||
}
|
||||
|
||||
Code make_unit( char const* name )
|
||||
Code make_global_body( char const* name = "", s32 num = 0, ... )
|
||||
{
|
||||
Code
|
||||
result = make_code();
|
||||
result->Type = ECode::Unit;
|
||||
result->Name = string_make( g_allocator, name );
|
||||
result->Type = ECode::Global_Body;
|
||||
result->Name = string_make( g_allocator, "");
|
||||
|
||||
array_init( result->Entries, g_allocator );
|
||||
|
||||
@ -802,7 +780,9 @@ namespace gen
|
||||
|
||||
return result;
|
||||
}
|
||||
# pragma endregion Incremetnal Constructions
|
||||
|
||||
# pragma region Parsing Constructors
|
||||
Code parse_proc( char const* def, s32 length )
|
||||
{
|
||||
if ( def == nullptr )
|
||||
@ -856,7 +836,7 @@ namespace gen
|
||||
while ( left && char_is_space( * scanner ) ) \
|
||||
{ \
|
||||
left--; \
|
||||
scanner++ ;
|
||||
scanner++ ; \
|
||||
}
|
||||
|
||||
#define Get
|
||||
@ -947,7 +927,7 @@ namespace gen
|
||||
Code
|
||||
result = make_code();
|
||||
result->Name = string_make( g_allocator, name );
|
||||
result->Type = ECode::Function;
|
||||
result->Type = ECode::Proc;
|
||||
|
||||
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
|
||||
{
|
||||
@ -1007,7 +1103,7 @@ namespace gen
|
||||
result = string_append_length( result, Content, string_length(Content) );
|
||||
break;
|
||||
|
||||
case Decl_Function:
|
||||
case Proc_Forward:
|
||||
{
|
||||
u32 index = 0;
|
||||
u32 left = array_count( Entries );
|
||||
@ -1040,14 +1136,7 @@ namespace gen
|
||||
}
|
||||
break;
|
||||
|
||||
case Decl_Type:
|
||||
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:
|
||||
case Proc:
|
||||
{
|
||||
u32 index = 0;
|
||||
u32 left = array_count( Entries );
|
||||
@ -1080,7 +1169,7 @@ namespace gen
|
||||
}
|
||||
break;
|
||||
|
||||
case Function_Body:
|
||||
case Proc_Body:
|
||||
fatal("NOT SUPPORTED YET");
|
||||
break;
|
||||
|
||||
@ -1138,9 +1227,10 @@ namespace gen
|
||||
|
||||
return result;
|
||||
}
|
||||
# pragma endregion AST
|
||||
|
||||
|
||||
|
||||
# pragma region Builder
|
||||
void Builder::print( Code code )
|
||||
{
|
||||
Buffer = string_append_fmt( Buffer, "%s\n\n", code->to_string() );
|
||||
@ -1171,5 +1261,6 @@ namespace gen
|
||||
// file_seek( & File, 0 );
|
||||
file_close( & File );
|
||||
}
|
||||
# pragma endregion Builder
|
||||
}
|
||||
#endif
|
||||
|
570
project/gen.hpp
570
project/gen.hpp
@ -13,17 +13,14 @@
|
||||
* 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.
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
* Both AST and Code have member symbols but their data layout is enforced to be POD types.
|
||||
|
||||
@ -58,22 +55,30 @@
|
||||
|
||||
Interface :
|
||||
|
||||
* def_forward_decl
|
||||
* def_class
|
||||
* def_class_body
|
||||
* def_class_fwd
|
||||
* def_enum
|
||||
* def_enum_class
|
||||
* def_enum_body
|
||||
* def_global_body
|
||||
* def_proc
|
||||
* def_proc_body
|
||||
* def_namespace
|
||||
* def_namespace_body
|
||||
* def_operator
|
||||
* def_operator_fwd
|
||||
* def_param
|
||||
* def_params
|
||||
* def_operator
|
||||
* def_proc
|
||||
* def_proc_body
|
||||
* def_proc_fwd
|
||||
* def_specifier
|
||||
* def_specifiers
|
||||
* def_struct
|
||||
* def_struct_body
|
||||
* def_struct_fwd
|
||||
* def_variable
|
||||
* def_type
|
||||
* def_typedef
|
||||
* def_using
|
||||
* def_using_namespace
|
||||
|
||||
@ -82,27 +87,27 @@
|
||||
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:
|
||||
|
||||
* code.add( AST* ) // Adds AST with validation.
|
||||
* code.add_entry( AST* ) // Adds AST entry without validation.
|
||||
* code.add_content( AST* ) // Adds AST string content without validation.
|
||||
* code.add( AST* ) // Adds AST with validation.
|
||||
* code.add_entry( AST* ) // Adds AST entry without validation.
|
||||
|
||||
Code ASTs may be explictly validated at anytime using Code's check() member function.
|
||||
|
||||
Interface :
|
||||
|
||||
* make_forward_decl
|
||||
* make_class
|
||||
* make_enum
|
||||
* make_enum_class
|
||||
* make_global_body
|
||||
* make_proc
|
||||
* make_namespace
|
||||
* make_params
|
||||
* make_operator
|
||||
* make_params
|
||||
* make_proc
|
||||
* make_specifiers
|
||||
* make_struct
|
||||
* make_variable
|
||||
* make_type
|
||||
* make_typedef
|
||||
* make_using
|
||||
* make_using_namespace
|
||||
|
||||
### Parse construction
|
||||
|
||||
@ -110,23 +115,33 @@
|
||||
|
||||
Interface :
|
||||
|
||||
* parse_forward_decl
|
||||
* parse_class
|
||||
* parse_glboal_body
|
||||
* parse_proc
|
||||
* parse_classes
|
||||
* parse_enum
|
||||
* parse_enums
|
||||
* parse_global_body
|
||||
* parse_namespace
|
||||
* parse_params
|
||||
* parse_namespaces
|
||||
* parse_operator
|
||||
* parse_specifiers
|
||||
* parse_operators
|
||||
* parse_proc
|
||||
* parse_procs
|
||||
* parse_struct
|
||||
* parse_strucs
|
||||
* parse_variable
|
||||
* parse_variables
|
||||
* parse_type
|
||||
* parse_typedef
|
||||
* parse_typedefs
|
||||
* parse_using
|
||||
* parse_using
|
||||
* 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.
|
||||
@ -158,7 +173,7 @@
|
||||
// #define GEN_DEFINE_DSL
|
||||
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||
// #define GEN_BAN_CPP_TEMPLATES
|
||||
// #define GEN_USE_FATAL
|
||||
#define GEN_USE_FATAL
|
||||
|
||||
#ifdef gen_time
|
||||
namespace gen
|
||||
@ -179,41 +194,52 @@ namespace gen
|
||||
{
|
||||
enum Type : u8
|
||||
{
|
||||
Invalid, // Used only with improperly created Code nodes
|
||||
Untyped, // User provided raw string
|
||||
Decl_Function, // <specifier> <type> <name> ( <params> )
|
||||
Decl_Type, // <type> <name>;
|
||||
Function, // <type> <name>( <parameters> )
|
||||
Function_Body, // { <body> }
|
||||
Namespace, // Define a namespace
|
||||
Namespace_Body, // { <body> }
|
||||
Parameters, // <type> <param> ...
|
||||
Specifiers, // Used with functions, structs, variables
|
||||
Struct, // struct <specifier> <name> <parent>
|
||||
Struct_Body, // {<body> }
|
||||
Variable, // <type> <name>
|
||||
Typedef, // typedef <type> <alias>
|
||||
Typename, // Typename, used with other types
|
||||
Using, // using <name> = <type>
|
||||
Unit, // Represents a file.
|
||||
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,
|
||||
|
||||
Num_Types
|
||||
};
|
||||
|
||||
inline
|
||||
local_persist
|
||||
char const* str( Type type )
|
||||
{
|
||||
static
|
||||
char const* lookup[Num_Types] = {
|
||||
"Invalid",
|
||||
"Untyped",
|
||||
"Decl_Function",
|
||||
"Decl_Type",
|
||||
"Function",
|
||||
"Function_Body",
|
||||
"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",
|
||||
@ -221,7 +247,6 @@ namespace gen
|
||||
"Typedef",
|
||||
"Typename",
|
||||
"Using",
|
||||
"Unit",
|
||||
};
|
||||
|
||||
return lookup[ type ];
|
||||
@ -245,7 +270,7 @@ namespace gen
|
||||
inline
|
||||
char const* str( Type op )
|
||||
{
|
||||
static
|
||||
local_persist
|
||||
char const* lookup[ Num_Ops ] = {
|
||||
"+",
|
||||
"-",
|
||||
@ -262,43 +287,48 @@ namespace gen
|
||||
{
|
||||
enum Type : u8
|
||||
{
|
||||
Attribute, // [ <attributes ]
|
||||
Alignas, // alignas(#)
|
||||
Constexpr, // constexpr
|
||||
Const, // const
|
||||
Inline, // inline
|
||||
RValue, //
|
||||
Attribute,
|
||||
Alignas,
|
||||
Constexpr,
|
||||
Const,
|
||||
Inline,
|
||||
Pointer,
|
||||
Reference,
|
||||
RValue,
|
||||
|
||||
C_Linkage, // extern "C"
|
||||
API_Import, // Vendor specific way dynamic import symbol
|
||||
API_Export, // Vendor specific way to dynamic export
|
||||
External_Linkage, // extern
|
||||
Internal_Linkage, // static (within unit file)
|
||||
Static_Member, // static (within sturct/class)
|
||||
Local_Persist, // static (within function)
|
||||
Thread_Local, // thread_local
|
||||
C_Linkage,
|
||||
API_Import,
|
||||
API_Export,
|
||||
External_Linkage,
|
||||
Internal_Linkage,
|
||||
Static_Member,
|
||||
Local_Persist,
|
||||
Thread_Local,
|
||||
|
||||
Invalid,
|
||||
Num_Specifiers,
|
||||
Invalid
|
||||
};
|
||||
|
||||
// Specifier to string
|
||||
inline
|
||||
char const* to_str( Type specifier )
|
||||
{
|
||||
static
|
||||
local_persist
|
||||
char const* lookup[ Num_Specifiers ] = {
|
||||
"alignas",
|
||||
"constexpr",
|
||||
"const",
|
||||
"inline",
|
||||
"*",
|
||||
"&",
|
||||
"&&",
|
||||
|
||||
"extern \"C\"",
|
||||
|
||||
#if defined(ZPL_SYSTEM_WINDOWS) && 0// API_Import and API_Export strings
|
||||
#if defined(ZPL_SYSTEM_WINDOWS)
|
||||
"__declspec(dllexport)",
|
||||
"__declspec(dllimport)",
|
||||
#elif defined(ZPL_SYSTEM_MACOS) || 1
|
||||
#elif defined(ZPL_SYSTEM_MACOS)
|
||||
"__attribute__ ((visibility (\"default\")))",
|
||||
"__attribute__ ((visibility (\"default\")))",
|
||||
#endif
|
||||
@ -315,14 +345,14 @@ namespace gen
|
||||
|
||||
Type to_type( char const* str, s32 length )
|
||||
{
|
||||
static
|
||||
local_persist
|
||||
u32 keymap[ Num_Specifiers ];
|
||||
do_once_start
|
||||
for ( u32 index = 0; index < Num_Specifiers; 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
|
||||
|
||||
@ -339,6 +369,7 @@ namespace gen
|
||||
}
|
||||
using SpecifierT = ESpecifier::Type;
|
||||
|
||||
#pragma region Data Structures
|
||||
// TODO: If perf needs it, convert layout an SOA format.
|
||||
/*
|
||||
Simple AST POD with functionality to seralize into C++ syntax.
|
||||
@ -349,32 +380,46 @@ namespace gen
|
||||
*/
|
||||
struct AST
|
||||
{
|
||||
#pragma region Member API
|
||||
#pragma region Member Procedures
|
||||
bool add( AST* other );
|
||||
|
||||
forceinline
|
||||
void add( AST* other )
|
||||
void add_entry( AST* other )
|
||||
{
|
||||
array_append( Entries, other );
|
||||
|
||||
other->Parent = this;
|
||||
}
|
||||
|
||||
forceinline
|
||||
AST* body()
|
||||
{
|
||||
return Entries[0];
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool check();
|
||||
|
||||
forceinline
|
||||
bool has_entries() const
|
||||
{
|
||||
static bool lookup[ ECode::Num_Types] = {
|
||||
false, // Invalid
|
||||
false, // Untyped
|
||||
true, // Decl_Function
|
||||
true, // Decl_Type
|
||||
true, // Function
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true, // Global_Body
|
||||
true, // Parameters
|
||||
true, // Proc
|
||||
true, // Proc_Body
|
||||
true, // Proc_Forward
|
||||
false, // Specifies
|
||||
true, // Struct
|
||||
true, // Struct_Body
|
||||
true, // Variable
|
||||
true, // Typedef
|
||||
true, // Typename
|
||||
true, // Using
|
||||
};
|
||||
|
||||
return lookup[Type];
|
||||
@ -394,7 +439,7 @@ namespace gen
|
||||
|
||||
string to_string() const;
|
||||
|
||||
#pragma endregion Member API
|
||||
#pragma endregion Member Procedures
|
||||
|
||||
#define Using_Code_POD \
|
||||
CodeT Type; \
|
||||
@ -434,20 +479,32 @@ namespace gen
|
||||
Code body()
|
||||
{
|
||||
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 )
|
||||
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
|
||||
void lock()
|
||||
{
|
||||
#ifdef GEN_ENFORCE_READONLY_AST
|
||||
ast->Readonly = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
forceinline
|
||||
@ -468,6 +525,20 @@ namespace gen
|
||||
|
||||
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;
|
||||
|
||||
return *this;
|
||||
@ -476,12 +547,18 @@ namespace gen
|
||||
forceinline
|
||||
AST* operator ->()
|
||||
{
|
||||
#ifdef GEN_ENFORCE_READONLY_AST
|
||||
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 )
|
||||
fatal("Attempted to access a member from a readonly ast!");
|
||||
{
|
||||
log_failure("Attempted to access a member from a readonly AST!");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ast;
|
||||
@ -495,6 +572,10 @@ namespace gen
|
||||
// Used internally for the most part to identify invaidly generated code.
|
||||
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.
|
||||
|
||||
@ -502,47 +583,56 @@ namespace gen
|
||||
Strings made with the Typename ASTs are stored in thier own arena allocator.
|
||||
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.
|
||||
This currently just initializes the CodePool.
|
||||
*/
|
||||
void init();
|
||||
|
||||
#pragma region Upfront
|
||||
/*
|
||||
Foward Declare a type:
|
||||
<specifiers> <type> <name>;
|
||||
*/
|
||||
Code def_fwd_type( Code type, char const* name, Code specifiers = UnusedCode );
|
||||
// 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.
|
||||
void clear_code_pool();
|
||||
|
||||
/*
|
||||
Foward Declare a function:
|
||||
<specifiers> <name> ( <params> );
|
||||
*/
|
||||
Code def_fwd_proc( char const* name
|
||||
// Set these before calling gen's init() procedure.
|
||||
|
||||
void set_init_reserve_code_pool ( sw size );
|
||||
void set_init_reserve_string_arena( sw size );
|
||||
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 params
|
||||
, Code ret_type
|
||||
, Code body
|
||||
);
|
||||
Code def_operator_fwd( OperatorT op, Code specifiers, Code params, Code ret_type );
|
||||
|
||||
/*
|
||||
Define an expression:
|
||||
< c/c++ expression >
|
||||
Code def_param( Code type, char const* name );
|
||||
Code def_params( s32 num, ... );
|
||||
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 specifiers
|
||||
, Code params
|
||||
@ -550,197 +640,101 @@ namespace gen
|
||||
, 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* codes );
|
||||
|
||||
/*
|
||||
Define a namespace;
|
||||
namespace <name>
|
||||
{
|
||||
<body>
|
||||
}
|
||||
*/
|
||||
Code def_namespace( char const* name, Code body );
|
||||
Code def_proc_fwd( char const* name
|
||||
, Code specifiers
|
||||
, Code params
|
||||
, Code ret_type
|
||||
);
|
||||
|
||||
/*
|
||||
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_specifier( SpecifierT* specifier );
|
||||
Code def_specifiers( s32 num , ... );
|
||||
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 );
|
||||
|
||||
/*
|
||||
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* codes );
|
||||
|
||||
/*
|
||||
Define a variable:
|
||||
<specifiers> <type> <name> = <value>;
|
||||
*/
|
||||
Code def_sturct_fwd();
|
||||
|
||||
Code def_variable( Code type, char const* name, Code value = UnusedCode, Code specifiers = UnusedCode );
|
||||
|
||||
/*
|
||||
Define a typename AST value.
|
||||
Useless by itself, its intended to be used in conjunction with other Code.
|
||||
Code def_type( char const* name, Code specifiers = UnusedCode );
|
||||
|
||||
Planned - Not yet Implemented:
|
||||
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 ( char const* name, Code type );
|
||||
Code def_using_namespace( char const* name );
|
||||
#pragma endregion Upfront
|
||||
# pragma endregion Upfront
|
||||
|
||||
#pragma region Incremental
|
||||
/*
|
||||
Provides an incomplete procedure AST but sets the intended type.
|
||||
Any adds will be type checked.
|
||||
# pragma region Incremental
|
||||
Code make_class( char const* name, Code parent = UnusedCode, Code specifiers = UnusedCode );
|
||||
|
||||
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 specifiers = UnusedCode
|
||||
, Code params = UnusedCode
|
||||
, Code ret_type = UnusedCode
|
||||
);
|
||||
|
||||
/*
|
||||
Provides an incomplete struct AST but sets the intended type.
|
||||
Any adds will be type checked.
|
||||
Code make_specifiers( s32 num , ... );
|
||||
Code make_specifiers( s32 num, SpecifierT* specs );
|
||||
|
||||
Body is automatically made. Use body() to retrieve.
|
||||
*/
|
||||
Code make_struct( char const* name, Code parent = UnusedCode, Code specifiers = UnusedCode );
|
||||
|
||||
/*
|
||||
Creates a unit file.
|
||||
Code make_variable( char const* name, Code type = UnusedCode, Code value = UnusedCode, Code specifiers = UnusedCode );
|
||||
|
||||
These represent an encapsulation of a generated file
|
||||
Used this if you need to pass around a group of Code entires at file scope level.
|
||||
Code make_type( char const* name, Code specifiers = UnusedCode );
|
||||
|
||||
The name provided is the name of the file.
|
||||
*/
|
||||
Code make_file_body( char const* name );
|
||||
#pragma endregion Incremental
|
||||
Code make_using( char const* name, Code type = UnusedCode, Code specifiers = UnusedCode );
|
||||
# pragma endregion Incremental
|
||||
|
||||
/*
|
||||
*/
|
||||
Code parse_variable( char const* var_def, s32 length );
|
||||
# pragma region Parsing
|
||||
Code parse_class( char const* class_def, s32 length );
|
||||
s32 parse_classes( char const* class_defs, s32 length, Code* out_classes );
|
||||
|
||||
/*
|
||||
*/
|
||||
Code parse_using( char const* using_def, s32 length );
|
||||
Code parse_enum( char const* enum_def, s32 length);
|
||||
s32 parse_enums( char const* enum_defs, s32 length, Code* out_enums );
|
||||
|
||||
/*
|
||||
Code parse_global_body( char const* body_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 );
|
||||
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 );
|
||||
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 );
|
||||
|
||||
*/
|
||||
s32 parse_vars( char const* vars_def, s32 length, Code* out_vars_codes );
|
||||
Code parse_type( char const* type_def, s32 length );
|
||||
|
||||
/*
|
||||
Code parse_typedef( char const* typedef_def, s32 length );
|
||||
s32 parse_typedef( char const* typedef_def, s32 length, Code* out_typedef_codes );
|
||||
|
||||
*/
|
||||
s32 parse_usings( char const* usings_def, s32 length, Code* out_usings_codes );
|
||||
Code parse_using ( char const* using_def, s32 length );
|
||||
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.
|
||||
|
||||
@ -779,7 +773,7 @@ Code make_file_body( char const* name );
|
||||
Consider this an a preprocessor define.
|
||||
*/
|
||||
Code untyped_token_fmt( char const* fmt, s32 num_tokens, ... );
|
||||
#pragma endregion Untyped text
|
||||
# pragma endregion Untyped text
|
||||
|
||||
/*
|
||||
Used to generate the files.
|
||||
@ -806,7 +800,7 @@ Code make_file_body( char const* name );
|
||||
bool open( char const* path );
|
||||
void write();
|
||||
};
|
||||
#pragma endregion gen API
|
||||
#pragma endregion Gen Interface
|
||||
}
|
||||
|
||||
#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 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_fmt( Fmt_, ... ) gen::untyped_fmt( Fmt_, __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 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_body( ... ) gen::def_proc_body( VA_NARGS( __VA_ARS__ ), __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_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_untyped( Value_ ) add( gen::untyped_str( txt( Value ) ) )
|
||||
# define add_ret_type( ... )
|
||||
# define add_params( ... )
|
||||
# define add_var( Value_ ) add( gen::parse_variable( txt_with_length(Value_)) )
|
||||
# define add_untyped( Value_ ) add( gen::untyped_str( txt_with_length( Value_ ) ) )
|
||||
# define add_type( Value_ ) add( gen::parse_type( txt_with_length(Value_)) )
|
||||
# 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 struct_code( Def_ ) gen::parse_struct( txt( Def_ ), sizeof( txt( Def_ )) )
|
||||
# define variable_code( Def_ ) gen::parse_variable( txt_with_length( Def_ ) )
|
||||
#endif
|
||||
#pragma endregion MACROS
|
||||
|
||||
@ -873,31 +872,38 @@ namespace gen
|
||||
// These are not set until gen::init is called.
|
||||
// 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 const Code t_char;
|
||||
extern const Code t_wchar_t;
|
||||
extern Code t_bool;
|
||||
extern Code t_char;
|
||||
extern Code t_wchar_t;
|
||||
|
||||
extern const Code t_s8;
|
||||
extern const Code t_s16;
|
||||
extern const Code t_s32;
|
||||
extern const Code t_s64;
|
||||
extern Code t_s8;
|
||||
extern Code t_s16;
|
||||
extern Code t_s32;
|
||||
extern Code t_s64;
|
||||
|
||||
extern const Code t_u8;
|
||||
extern const Code t_u16;
|
||||
extern const Code t_u32;
|
||||
extern const Code t_u64;
|
||||
extern Code t_u8;
|
||||
extern Code t_u16;
|
||||
extern Code t_u32;
|
||||
extern Code t_u64;
|
||||
|
||||
extern const Code t_sw;
|
||||
extern const Code t_uw;
|
||||
extern Code t_sw;
|
||||
extern Code t_uw;
|
||||
|
||||
extern const Code t_f32;
|
||||
extern const Code t_f64;
|
||||
extern Code t_f32;
|
||||
extern Code t_f64;
|
||||
|
||||
extern const Code spec_constexpr;
|
||||
extern const Code spec_inline;
|
||||
extern Code spec_constexpr;
|
||||
extern Code spec_inline;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace gen
|
||||
{
|
||||
extern Code access_public;
|
||||
extern Code access_protected;
|
||||
extern Code access_private;
|
||||
}
|
||||
#pragma endregion CONSTANTS
|
||||
#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
|
||||
using namespace gen;
|
||||
|
||||
Code t_allocator = def_type( txt(allocator) );
|
||||
Code t_allocator = def_type( txt(allocator) );
|
||||
|
||||
Code header;
|
||||
{
|
||||
@ -64,7 +64,6 @@
|
||||
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 )
|
||||
{
|
||||
#ifndef GEN_DEFINE_DSL
|
||||
@ -155,6 +154,7 @@
|
||||
Code append = make_proc( "append" );
|
||||
{
|
||||
append->add( def_params( 1, type, "value") );
|
||||
append->add( t_bool );
|
||||
|
||||
Code
|
||||
body = append.body();
|
||||
@ -172,6 +172,8 @@
|
||||
|
||||
return true;
|
||||
)));
|
||||
|
||||
append->check();
|
||||
}
|
||||
|
||||
Code back;
|
||||
@ -295,7 +297,7 @@
|
||||
}
|
||||
|
||||
Code set_capacity = parse_proc( txt_with_length(
|
||||
bool set_capacity( new_capacity )
|
||||
bool set_capacity( sw new_capacity )
|
||||
{
|
||||
Header& header = get_header();
|
||||
|
||||
@ -305,7 +307,7 @@
|
||||
if ( capacity < header.Num )
|
||||
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 ));
|
||||
|
||||
if ( new_header == nullptr )
|
||||
@ -591,18 +593,58 @@
|
||||
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()
|
||||
{
|
||||
Code a_base = gen__array_base();
|
||||
|
||||
Code a_u32 = gen_array( u32 );
|
||||
Code a_cstr = gen_array( char const* );
|
||||
add_gen_array_request( "u32", sizeof(u32) );
|
||||
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
|
||||
arraygen;
|
||||
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();
|
||||
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
|
||||
string name = string_sprintf( g_allocator, (char*)sprintf_buf, ZPL_PRINTF_MAXLEN, "square", type );
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
Code square;
|
||||
{
|
||||
Code params = def_params( 1, integral_type, "value" );
|
||||
@ -43,9 +43,9 @@
|
||||
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
|
||||
|
||||
#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 {
|
||||
allocator allocator;
|
||||
sw length;
|
||||
sw capacity;
|
||||
sw length;
|
||||
} string_header;
|
||||
|
||||
#define ZPL_STRING_HEADER(str) (zpl_cast(ZPL_NS string_header *)(str) - 1)
|
||||
|
Loading…
Reference in New Issue
Block a user