mirror of
https://github.com/Ed94/gencpp.git
synced 2024-12-22 07:44:45 -08:00
Major changes to library design, change test to reflect it.
This commit is contained in:
parent
96e1b91e9b
commit
9957ef0e7d
11
Readme.md
11
Readme.md
@ -2,9 +2,17 @@
|
||||
|
||||
An attempt at simple staged metaprogramming for c/c++.
|
||||
|
||||
This library is intended for small-to midsize projects that want rapid complation times.
|
||||
for fast debugging.
|
||||
|
||||
## Notes
|
||||
|
||||
This project is not minimum feature complete yet.
|
||||
Version 1 will have c and a subset of c++ features available to it.
|
||||
|
||||
I will generate with this library a C99 or 11 variant when Version 1 is complete.
|
||||
A single-header version will also be genrated.
|
||||
|
||||
## How it works
|
||||
|
||||
A metaprogram is built to generate files before the main program is built. We'll term runtime for this program as `gen_time`. The metaprogram's core implementation are within `gen.hpp` and `gen.cpp` in the project directory.
|
||||
@ -70,3 +78,6 @@ However, if the code being generated becomes complex, or from a datatable or dat
|
||||
|
||||
* Need problably a better name, I found a few repos with this same one...
|
||||
* Actually get to version 1.
|
||||
* Make a test suite made up of collections based of the ZPL library templated colllection macros and the memory module.
|
||||
* Generate a single-header library.
|
||||
* Generate a C-supported single-header library.
|
||||
|
@ -4,6 +4,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__) || 1
|
||||
// Supports 0-10 arguments
|
||||
#define VA_NARGS_IMPL( _0, \
|
||||
_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
|
||||
_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
|
||||
_21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
|
||||
N, ...) N
|
||||
// ## deletes preceding comma if _VA_ARGS__ is empty (GCC, Clang)
|
||||
#define VA_NARGS(...) VA_NARGS_IMPL(_, ## __VA_ARGS__, \
|
||||
30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \
|
||||
20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \
|
||||
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, \
|
||||
0)
|
||||
|
||||
#else
|
||||
// Supports 1-10 arguments
|
||||
#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
|
||||
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
|
||||
#endif
|
||||
|
||||
#define VA_NARGS2(...) ((int)(sizeof((int[]){ __VA_ARGS__ })/sizeof(int)))
|
||||
|
||||
#ifdef BLOAT_IMPL
|
||||
# define ZPL_IMPLEMENTATION
|
||||
#endif
|
||||
@ -21,7 +43,7 @@
|
||||
# define ZPL_MODULE_ESSENTIALS
|
||||
# define ZPL_MODULE_CORE
|
||||
# define ZPL_MODULE_TIMER
|
||||
// # define ZPL_MODULE_HASHING
|
||||
# define ZPL_MODULE_HASHING
|
||||
// # define ZPL_MODULE_REGEX
|
||||
// # define ZPL_MODULE_EVENT
|
||||
// # define ZPL_MODULE_DLL
|
||||
|
575
project/gen.cpp
575
project/gen.cpp
@ -5,26 +5,48 @@
|
||||
#ifdef gen_time
|
||||
namespace gen
|
||||
{
|
||||
void init()
|
||||
namespace StaticData
|
||||
{
|
||||
|
||||
static array(CodePOD) CodePool = nullptr;
|
||||
}
|
||||
|
||||
ct Code make()
|
||||
/*
|
||||
Used internally to retireve a Code object form the CodePool.
|
||||
*/
|
||||
Code make()
|
||||
{
|
||||
return { Code::Invalid, nullptr, nullptr, { nullptr } };
|
||||
using namespace StaticData;
|
||||
|
||||
array_append( CodePool, InvalidCode );
|
||||
|
||||
return * (Code*) & array_back( CodePool );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void init()
|
||||
{
|
||||
array_init( StaticData::CodePool, g_allocator );
|
||||
}
|
||||
|
||||
Code decl_type( char const* name, Code type, Code specifiers )
|
||||
{
|
||||
Code
|
||||
result = make();
|
||||
result.Type = Code::Decl_Type;
|
||||
result.Name = string_make( g_allocator, name );
|
||||
using namespace ECode;
|
||||
|
||||
array_init( result.Entries, g_allocator );
|
||||
result.add( specifiers );
|
||||
result.add( type );
|
||||
if ( type->Type != Specifiers )
|
||||
fatal( "gen::decl_type: type is not a Typename");
|
||||
|
||||
if ( type->Type != Typename )
|
||||
fatal( "gen::decl_type: specifiers is not a 'Specfiers' type");
|
||||
|
||||
Code
|
||||
result = make();
|
||||
result->Type = Decl_Type;
|
||||
result->Name = string_make( g_allocator, name );
|
||||
|
||||
array_init( result->Entries, g_allocator );
|
||||
result->add( specifiers );
|
||||
result->add( type );
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -35,57 +57,77 @@ namespace gen
|
||||
, Code ret_type
|
||||
)
|
||||
{
|
||||
Code
|
||||
result = make();
|
||||
result.Type = Code::Decl_Function;
|
||||
result.Name = string_make( g_allocator, name );
|
||||
using namespace ECode;
|
||||
|
||||
array_init( result.Entries, g_allocator );
|
||||
if ( specifiers->Type != Specifiers )
|
||||
fatal( "gen::decl_fn: specifiers was not a `Specifiers` type" );
|
||||
|
||||
if ( params->Type != Parameters )
|
||||
fatal( "gen::decl_fn: params was not a `Parameters` type" );
|
||||
|
||||
if ( ret_type->Type != Typename )
|
||||
fatal( "gen::decl_fn: ret_type was not a Typename" );
|
||||
|
||||
Code
|
||||
result = make();
|
||||
result->Type = Decl_Function;
|
||||
result->Name = string_make( g_allocator, name );
|
||||
|
||||
array_init( result->Entries, g_allocator );
|
||||
|
||||
if ( specifiers )
|
||||
result.add( specifiers );
|
||||
result->add( specifiers );
|
||||
|
||||
result.add( ret_type );
|
||||
result->add( ret_type );
|
||||
|
||||
if ( params )
|
||||
result.add( params );
|
||||
result->add( params );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code def_parameters( s32 num, ... )
|
||||
{
|
||||
using namespace ECode;
|
||||
|
||||
if (num <= 0)
|
||||
fatal("TT::make_paramters: num is %d", num);
|
||||
fatal( "TT::make_paramters: num cannot be zero or neg" );
|
||||
|
||||
Code
|
||||
result = make();
|
||||
result.Type = Code::Parameters;
|
||||
result = make();
|
||||
result->Type = Parameters;
|
||||
|
||||
va_list va;
|
||||
va_start(va, num);
|
||||
|
||||
result.Name = string_make( g_allocator, va_arg(va, char const*) );
|
||||
result->Name = string_make( g_allocator, va_arg(va, char const*) );
|
||||
|
||||
array_init( result.Entries, g_allocator );
|
||||
array_init( result->Entries, g_allocator );
|
||||
|
||||
Code type = va_arg(va, Code);
|
||||
result.add( type );
|
||||
|
||||
if ( type->Type != Typename )
|
||||
fatal( "gen::def_parameters: type of param %d is not a Typename", num - num + 1 );
|
||||
|
||||
result->add( type );
|
||||
|
||||
while( num -= 2, num && num % 2 == 0 )
|
||||
{
|
||||
Code
|
||||
param = make();
|
||||
param.Name = string_make( g_allocator, va_arg(va, char const*) );
|
||||
|
||||
array_init( param.Entries, g_allocator );
|
||||
|
||||
type = va_arg(va, Code);
|
||||
param.add( type );
|
||||
|
||||
result.add(param);
|
||||
Code
|
||||
param = make();
|
||||
param->Type = Parameters;
|
||||
param->Name = string_make( g_allocator, va_arg(va, char const*) );
|
||||
|
||||
array_init( param->Entries, g_allocator );
|
||||
|
||||
if ( type->Type != Typename )
|
||||
fatal( "gen::def_parameters: type of param %d is not a Typename", num - num + 1 );
|
||||
|
||||
param->add( type );
|
||||
result->add(param);
|
||||
}
|
||||
|
||||
va_end(va);
|
||||
|
||||
return result;
|
||||
@ -98,50 +140,155 @@ namespace gen
|
||||
, Code body
|
||||
)
|
||||
{
|
||||
Code
|
||||
result = make();
|
||||
result.Name = string_make( g_allocator, name );
|
||||
result.Type = Code::Function;
|
||||
using namespace ECode;
|
||||
|
||||
array_init( result.Entries, g_allocator );
|
||||
if ( specifiers && specifiers->Type != Specifiers )
|
||||
fatal( "gen::def_function: specifiers was not a `Specifiers` type" );
|
||||
|
||||
if ( params && params->Type != Parameters )
|
||||
fatal( "gen::def_function: params was not a `Parameters` type" );
|
||||
|
||||
if ( ret_type == nullptr || ret_type->Type != Typename )
|
||||
fatal( "gen::def_function: ret_type was not a Typename" );
|
||||
|
||||
switch ( body->Type )
|
||||
{
|
||||
case Function_Body:
|
||||
case Untyped:
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("gen::def_function: body must be either of Function_Body or Untyped type.");
|
||||
}
|
||||
|
||||
Code
|
||||
result = make();
|
||||
result->Name = string_make( g_allocator, name );
|
||||
result->Type = Function;
|
||||
|
||||
array_init( result->Entries, g_allocator );
|
||||
|
||||
if ( specifiers )
|
||||
result.add( specifiers );
|
||||
result->add( specifiers );
|
||||
|
||||
result.add( ret_type );
|
||||
result->add( ret_type );
|
||||
|
||||
if ( params )
|
||||
result.add( params );
|
||||
result->add( params );
|
||||
|
||||
result.add( body );
|
||||
result->add( body );
|
||||
|
||||
body->Parent = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code def_function_body( u32 num, ... )
|
||||
Code def_function_body( s32 num, ... )
|
||||
{
|
||||
using namespace ECode;
|
||||
|
||||
if ( num <= 0 )
|
||||
fatal("gen::def_function_body: num cannot zero or neg");
|
||||
|
||||
Code result = make();
|
||||
|
||||
array_init( result->Entries, g_allocator );
|
||||
|
||||
va_list va;
|
||||
va_start(va, num);
|
||||
do
|
||||
{
|
||||
Code entry = va_arg(va, Code);
|
||||
|
||||
switch ( entry->Type )
|
||||
{
|
||||
case Decl_Function:
|
||||
case Decl_Type:
|
||||
case Namespace:
|
||||
case Namespace_Body:
|
||||
case Parameters:
|
||||
case Specifiers:
|
||||
case Struct_Body:
|
||||
case Typename:
|
||||
fatal("gen::def_function_body: Entry type is not allowed: %s", entry->type_str() );
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
result->add( entry );
|
||||
}
|
||||
while ( num--, num > 0 );
|
||||
va_end(va);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code def_namespace( char const* name, Code body )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Code def_namespace_body( u32 num, ... )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Code def_specifiers( u32 num, ... )
|
||||
{
|
||||
if ( num <= 0 )
|
||||
fatal("gen::make_specifier: num cannot be zero.");
|
||||
using namespace ECode;
|
||||
|
||||
Code
|
||||
result = make();
|
||||
result.Type = Code::Specifiers;
|
||||
result.Content = string_make( g_allocator, "" );
|
||||
result = make();
|
||||
result->Type = Namespace;
|
||||
|
||||
array_init( result->Entries, g_allocator );
|
||||
|
||||
if ( body->Type != Namespace_Body || body->Type != Untyped )
|
||||
fatal("gen::def_namespace: body is not of namespace or untyped type");
|
||||
|
||||
result->add( body );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code def_namespace_body( s32 num, ... )
|
||||
{
|
||||
using namespace ECode;
|
||||
|
||||
if ( num <= 0 )
|
||||
fatal("gen::make_specifier: num cannot be zero or less");
|
||||
|
||||
Code
|
||||
result = make();
|
||||
result->Type = Namespace_Body;
|
||||
|
||||
va_list va;
|
||||
va_start(va, num);
|
||||
do
|
||||
{
|
||||
Code entry = va_arg(va, Code);
|
||||
|
||||
switch ( entry->Type )
|
||||
{
|
||||
case Namespace_Body:
|
||||
case Parameters:
|
||||
case Specifiers:
|
||||
case Struct_Body:
|
||||
case Typename:
|
||||
fatal("gen::def_function_body: Entry type is not allowed: %s", ECode::str(entry->Type) );
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
result->add( entry );
|
||||
}
|
||||
while ( num--, num > 0 );
|
||||
va_end(va);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code def_specifiers( s32 num, ... )
|
||||
{
|
||||
if ( num <= 0 )
|
||||
fatal("gen::make_specifier: num cannot be zero or less");
|
||||
|
||||
Code
|
||||
result = make();
|
||||
result->Type = ECode::Specifiers;
|
||||
result->Content = string_make( g_allocator, "" );
|
||||
|
||||
va_list va;
|
||||
va_start(va, num);
|
||||
@ -152,13 +299,13 @@ namespace gen
|
||||
switch ( type )
|
||||
{
|
||||
case Alignas:
|
||||
result.Content = string_append_fmt( result.Content, "%s(%d)", specifier_str(type), va_arg(va, u32) );
|
||||
result->Content = string_append_fmt( result->Content, "%s(%d)", specifier_str(type), va_arg(va, u32) );
|
||||
break;
|
||||
|
||||
default:
|
||||
const char* str = specifier_str(type);
|
||||
|
||||
result.Content = string_append_fmt( result.Content, "%s", str );
|
||||
result->Content = string_append_fmt( result->Content, "%s", str );
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -170,29 +317,125 @@ namespace gen
|
||||
|
||||
Code def_struct( char const* name, Code body, Code parent, Code specifiers )
|
||||
{
|
||||
using namespace ECode;
|
||||
|
||||
if ( specifiers && specifiers->Type != Specifiers )
|
||||
fatal( "gen::def_struct: specifiers was not a `Specifiers` type" );
|
||||
|
||||
if ( parent && parent->Type != Struct )
|
||||
fatal( "gen::def_struct: parent was not a `Struct` type" );
|
||||
|
||||
if ( body && body->Type != Struct_Body )
|
||||
fatal( "gen::def_struct: body was not a Struct_Body type" );
|
||||
|
||||
Code
|
||||
result = make();
|
||||
result->Type = Struct;
|
||||
result->Name = string_make( g_allocator, name );
|
||||
|
||||
array_init( result->Entries, g_allocator );
|
||||
|
||||
if ( body )
|
||||
result->add( body );
|
||||
|
||||
if ( parent )
|
||||
result->add( parent );
|
||||
|
||||
if ( specifiers )
|
||||
result->add( specifiers );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code def_struct_body( u32 num, ... )
|
||||
Code def_struct_body( s32 num, ... )
|
||||
{
|
||||
using namespace ECode;
|
||||
|
||||
if ( num == 0 )
|
||||
fatal("gen::def_struct_body: num cannot be zero");
|
||||
|
||||
Code result = make();
|
||||
|
||||
array_init( result->Entries, g_allocator );
|
||||
|
||||
va_list va;
|
||||
va_start(va, num);
|
||||
do
|
||||
{
|
||||
Code entry = va_arg(va, Code);
|
||||
|
||||
switch ( entry->Type )
|
||||
{
|
||||
case Namespace:
|
||||
case Namespace_Body:
|
||||
case Parameters:
|
||||
case Specifiers:
|
||||
case Struct_Body:
|
||||
case Typename:
|
||||
fatal("gen::def_struct_body: Entry type is not allowed: %s", ECode::str(entry->Type) );
|
||||
}
|
||||
|
||||
result->add( entry );
|
||||
}
|
||||
while ( num--, num > 0 );
|
||||
va_end(va);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code def_variable( char const* name, Code type, Code value, Code specifiers )
|
||||
{
|
||||
if ( specifiers && specifiers->Type != ECode::Specifiers )
|
||||
fatal( "gen::def_variable: specifiers was not a `Specifiers` type" );
|
||||
|
||||
if ( type->Type != ECode::Typename )
|
||||
fatal( "gen::def_variable: type was not a Typename" );
|
||||
|
||||
if ( value && value->Type != ECode::Untyped )
|
||||
fatal( "gen::def_variable: value was not a `Untyped` type" );
|
||||
|
||||
Code
|
||||
result = make();
|
||||
result->Name = string_make( g_allocator, name );
|
||||
result->Type = ECode::Variable;
|
||||
|
||||
array_init( result->Entries, g_allocator );
|
||||
|
||||
if ( specifiers )
|
||||
result->add( specifiers );
|
||||
|
||||
result->add( type );
|
||||
|
||||
if ( value )
|
||||
result->add( value );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code def_type( char const* name )
|
||||
{
|
||||
Code
|
||||
result = make();
|
||||
result.Name = string_make( g_allocator, name );
|
||||
result.Type = Code::Typename;
|
||||
result = make();
|
||||
result->Name = string_make( g_allocator, name );
|
||||
result->Type = ECode::Typename;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code def_using( char const* name, Code type )
|
||||
{
|
||||
Code
|
||||
result = make();
|
||||
result->Name = string_make( g_allocator, name );
|
||||
result->Type = ECode::Using;
|
||||
|
||||
array_init( result->Entries, g_allocator );
|
||||
|
||||
type->Parent = result;
|
||||
result->add( type );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code untyped_fmt(char const* fmt, ...)
|
||||
{
|
||||
@ -205,22 +448,123 @@ namespace gen
|
||||
va_end(va);
|
||||
|
||||
Code
|
||||
result = make();
|
||||
result.Name = string_make( g_allocator, fmt );
|
||||
result.Type = Code::Untyped;
|
||||
result.Content = string_make( g_allocator, buf );
|
||||
result = make();
|
||||
result->Name = string_make( g_allocator, fmt );
|
||||
result->Type = ECode::Untyped;
|
||||
result->Content = string_make( g_allocator, buf );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code token_fmt( char const* fmt, ... )
|
||||
{
|
||||
|
||||
struct TokEntry
|
||||
{
|
||||
char const* Str;
|
||||
s32 Length;
|
||||
};
|
||||
|
||||
ZPL_TABLE( static, TokMap, tokmap_, TokEntry )
|
||||
|
||||
sw token_fmt_va( char* buf, uw buf_size, char const* fmt, s32 num_tokens, va_list va )
|
||||
{
|
||||
char const* buf_begin = buf;
|
||||
sw remaining = buf_size;
|
||||
|
||||
TokMap tok_map;
|
||||
{
|
||||
tokmap_init( & tok_map, g_allocator );
|
||||
|
||||
s32 left = num_tokens;
|
||||
|
||||
while ( left-- )
|
||||
{
|
||||
char const* token = va_arg( va, char const* );
|
||||
char const* value = va_arg( va, char const* );
|
||||
|
||||
TokEntry entry
|
||||
{
|
||||
value,
|
||||
zpl_strnlen(value, 128)
|
||||
};
|
||||
|
||||
u32 key = crc32( token, zpl_strnlen(token, 32) );
|
||||
|
||||
tokmap_set( & tok_map, key, entry );
|
||||
}
|
||||
}
|
||||
|
||||
sw result = 0;
|
||||
char current = *fmt;
|
||||
|
||||
while ( current )
|
||||
{
|
||||
sw len = 0;
|
||||
|
||||
while ( current && current != '{' && remaining )
|
||||
{
|
||||
*buf = *fmt;
|
||||
buf++;
|
||||
fmt++;
|
||||
|
||||
current = *fmt;
|
||||
}
|
||||
|
||||
if ( current == '{' )
|
||||
{
|
||||
char const* scanner = fmt;
|
||||
|
||||
s32 tok_len = 0;
|
||||
|
||||
while ( *scanner != '}' )
|
||||
{
|
||||
tok_len++;
|
||||
scanner++;
|
||||
}
|
||||
|
||||
char const* token = fmt;
|
||||
|
||||
s32 key = crc32( token, tok_len );
|
||||
TokEntry value = *tokmap_get( & tok_map, key );
|
||||
s32 left = value.Length;
|
||||
|
||||
while ( left-- )
|
||||
{
|
||||
*buf = *value.Str;
|
||||
buf++;
|
||||
value.Str++;
|
||||
}
|
||||
|
||||
scanner++;
|
||||
fmt = scanner;
|
||||
current = *fmt;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code 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();
|
||||
result->Name = string_make( g_allocator, fmt );
|
||||
result->Type = ECode::Untyped;
|
||||
result->Content = string_make( g_allocator, buf );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
string Code::to_string()
|
||||
string AST::to_string()
|
||||
{
|
||||
string result = string_make( g_allocator, "" );
|
||||
|
||||
@ -229,6 +573,8 @@ namespace gen
|
||||
|
||||
switch ( Type )
|
||||
{
|
||||
using namespace ECode;
|
||||
|
||||
case Invalid:
|
||||
fatal("Attempted to serialize invalid code! - %s", Name);
|
||||
break;
|
||||
@ -237,13 +583,6 @@ namespace gen
|
||||
result = string_append_length( result, Content, string_length(Content) );
|
||||
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 Decl_Function:
|
||||
{
|
||||
u32 index = 0;
|
||||
@ -252,9 +591,9 @@ namespace gen
|
||||
if ( left <= 0 )
|
||||
fatal( "Code::to_string - Name: %s Type: %s, expected definition", Name, Type );
|
||||
|
||||
if ( Entries[index].Type == Specifiers )
|
||||
if ( Entries[index]->Type == Specifiers )
|
||||
{
|
||||
result = string_append_fmt( result, "%s\n", Entries[index].to_string() );
|
||||
result = string_append_fmt( result, "%s\n", Entries[index]->to_string() );
|
||||
index++;
|
||||
left--;
|
||||
}
|
||||
@ -262,13 +601,13 @@ namespace gen
|
||||
if ( left <= 0 )
|
||||
fatal( "Code::to_string - Name: %s Type: %s, expected return type", Name, Type );
|
||||
|
||||
result = string_append_fmt( result, "\n%s %s(", Entries[index].to_string(), Name );
|
||||
result = string_append_fmt( result, "\n%s %s(", Entries[index]->to_string(), Name );
|
||||
index++;
|
||||
left--;
|
||||
|
||||
if ( left && Entries[index].Type == Parameters )
|
||||
if ( left && Entries[index]->Type == Parameters )
|
||||
{
|
||||
result = string_append_fmt( result, "%s", Entries[index].to_string() );
|
||||
result = string_append_fmt( result, "%s", Entries[index]->to_string() );
|
||||
index++;
|
||||
left--;
|
||||
}
|
||||
@ -277,22 +616,11 @@ namespace gen
|
||||
}
|
||||
break;
|
||||
|
||||
case Function_Body:
|
||||
break;
|
||||
case Decl_Type:
|
||||
if ( Entries[0]->Type == Specifiers )
|
||||
result = string_append_fmt( result, "%s\n", Entries[0]->to_string());
|
||||
|
||||
case Parameters:
|
||||
{
|
||||
result = string_append_fmt( result, "%s %s", Entries[0].to_string(), Name );
|
||||
|
||||
s32 index = 1;
|
||||
s32 left = array_count( Entries ) - 1;
|
||||
|
||||
while ( left--, left > 0 )
|
||||
result = string_append_fmt( result, ", %s %s"
|
||||
, Entries[index].Entries[0].to_string()
|
||||
, Entries[index].Name
|
||||
);
|
||||
}
|
||||
result = string_append_fmt( result, "%s %s;\n", Entries[1]->to_string(), Name );
|
||||
break;
|
||||
|
||||
case Function:
|
||||
@ -303,9 +631,9 @@ namespace gen
|
||||
if ( left <= 0 )
|
||||
fatal( "Code::to_string - Name: %s Type: %s, expected definition", Name, Type );
|
||||
|
||||
if ( Entries[index].Type == Specifiers )
|
||||
if ( Entries[index]->Type == Specifiers )
|
||||
{
|
||||
result = string_append_fmt( result, "%s", Entries[index].to_string() );
|
||||
result = string_append_fmt( result, "%s", Entries[index]->to_string() );
|
||||
index++;
|
||||
left--;
|
||||
}
|
||||
@ -313,18 +641,45 @@ namespace gen
|
||||
if ( left <= 0 )
|
||||
fatal( "Code::to_string - Name: %s Type: %s, expected return type", Name, Type );
|
||||
|
||||
result = string_append_fmt( result, "\n%s %s(", Entries[index].to_string(), Name );
|
||||
result = string_append_fmt( result, "\n%s %s(", Entries[index]->to_string(), Name );
|
||||
index++;
|
||||
left--;
|
||||
|
||||
if ( left && Entries[index].Type == Parameters )
|
||||
if ( left && Entries[index]->Type == Parameters )
|
||||
{
|
||||
result = string_append_fmt( result, "%s", Entries[index].to_string() );
|
||||
result = string_append_fmt( result, "%s", Entries[index]->to_string() );
|
||||
index++;
|
||||
left--;
|
||||
}
|
||||
|
||||
result = string_append_fmt( result, ")\n{\n%s\n}", Entries[index].to_string() );
|
||||
result = string_append_fmt( result, ")\n{\n%s\n}", Entries[index]->to_string() );
|
||||
}
|
||||
break;
|
||||
|
||||
case Function_Body:
|
||||
fatal("NOT SUPPORTED YET");
|
||||
break;
|
||||
|
||||
case Namespace:
|
||||
fatal("NOT SUPPORTED YET");
|
||||
break;
|
||||
|
||||
case Namespace_Body:
|
||||
fatal("NOT SUPPORTED YET");
|
||||
break;
|
||||
|
||||
case Parameters:
|
||||
{
|
||||
result = string_append_fmt( result, "%s %s", Entries[0]->to_string(), Name );
|
||||
|
||||
s32 index = 1;
|
||||
s32 left = array_count( Entries ) - 1;
|
||||
|
||||
while ( left--, left > 0 )
|
||||
result = string_append_fmt( result, ", %s %s"
|
||||
, Entries[index]->Entries[0]->to_string()
|
||||
, Entries[index]->Name
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -344,9 +699,17 @@ namespace gen
|
||||
fatal("NOT SUPPORTED YET");
|
||||
break;
|
||||
|
||||
case Typedef:
|
||||
fatal("NOT SUPPORTED YET");
|
||||
break;
|
||||
|
||||
case Typename:
|
||||
result = string_append_fmt( result, "%s", Name );
|
||||
break;
|
||||
|
||||
case Using:
|
||||
fatal("NOT SUPPORTED YET");
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -356,7 +719,7 @@ namespace gen
|
||||
|
||||
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() );
|
||||
}
|
||||
|
||||
bool Builder::open( char const* path )
|
||||
|
471
project/gen.hpp
471
project/gen.hpp
@ -1,20 +1,42 @@
|
||||
/*
|
||||
gencpp: A simple staged metaprogramming library for C++.
|
||||
|
||||
This library is intended for small-to midsize projects that want rapid complation times
|
||||
for fast debugging.
|
||||
|
||||
AST type checking supports only a small subset of c++.
|
||||
See the 'ECode' namespace and 'gen API' region to see what is supported.
|
||||
|
||||
There is no support for accessability fields in structs.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Bloat.hpp"
|
||||
|
||||
// Defined by default.
|
||||
|
||||
#define GEN_ENABLE_READONLY_AST
|
||||
// #define GEN_DEFINE_DSL
|
||||
|
||||
#define gen_time
|
||||
#ifdef gen_time
|
||||
namespace gen
|
||||
{
|
||||
#if 0
|
||||
ct sw ColumnLimit = 256;
|
||||
ct sw MaxLines = kilobytes(256);
|
||||
|
||||
using LineStr = char[ColumnLimit];
|
||||
#endif
|
||||
|
||||
// Specifier Type
|
||||
enum Specifier : u8
|
||||
{
|
||||
Alignas, // alignas(#)
|
||||
Constexpr, // constexpr
|
||||
Inline, // inline
|
||||
|
||||
C_Linkage, // extern "C"
|
||||
API_Import, // Vendor specific way dynamic import symbol
|
||||
API_Export, // Vendor specific way to dynamic export
|
||||
@ -27,12 +49,16 @@ namespace gen
|
||||
Num_Specifiers
|
||||
};
|
||||
|
||||
// Specifier to string
|
||||
inline
|
||||
char const* specifier_str( Specifier specifier )
|
||||
{
|
||||
static char const* lookup[ Num_Specifiers ] = {
|
||||
static
|
||||
char const* lookup[ Num_Specifiers ] = {
|
||||
"alignas",
|
||||
"constexpr",
|
||||
"inline",
|
||||
|
||||
"extern \"C\"",
|
||||
#if defined(ZPL_SYSTEM_WINDOWS)
|
||||
"__declspec(dllexport)",
|
||||
@ -44,63 +70,93 @@ namespace gen
|
||||
"extern",
|
||||
"static",
|
||||
"static",
|
||||
"static",
|
||||
"thread_local"
|
||||
};
|
||||
|
||||
return lookup[ specifier ];
|
||||
}
|
||||
|
||||
struct Code
|
||||
// Code Type
|
||||
namespace ECode
|
||||
{
|
||||
enum EType : u8
|
||||
enum Type : u8
|
||||
{
|
||||
Invalid,
|
||||
Unused,
|
||||
|
||||
Untyped, // User provided raw string.
|
||||
|
||||
Decl_Type,
|
||||
Decl_Function,
|
||||
Decl_Function, // Forward a function
|
||||
Decl_Type, // Forward a type.
|
||||
Function, // <type> <name>( <parameters> )
|
||||
Function_Body, // { <body> }
|
||||
Namespace,
|
||||
Namespace_Body,
|
||||
Parameters, // Used with functions.
|
||||
Specifiers,
|
||||
Struct,
|
||||
Struct_Body,
|
||||
Function,
|
||||
Function_Body,
|
||||
Specifiers,
|
||||
Variable,
|
||||
Typedef,
|
||||
Typename,
|
||||
Using,
|
||||
|
||||
Num_Types
|
||||
};
|
||||
|
||||
#pragma region Member API
|
||||
void comment( string value )
|
||||
inline
|
||||
char const* str( Type type )
|
||||
{
|
||||
Comment = value;
|
||||
}
|
||||
static
|
||||
char const* lookup[Num_Types] = {
|
||||
"Invalid",
|
||||
|
||||
"Untyped",
|
||||
|
||||
"Decl_Function",
|
||||
"Decl_type",
|
||||
"Function",
|
||||
"Function_Body",
|
||||
"Namespace",
|
||||
"Namespace_Body",
|
||||
"Parameters",
|
||||
"Specifiers",
|
||||
"Struct",
|
||||
"Struct_Body",
|
||||
"Variable",
|
||||
"Typedef",
|
||||
"Typename",
|
||||
"using"
|
||||
};
|
||||
|
||||
return lookup[ type ];
|
||||
}
|
||||
}
|
||||
using CodeT = ECode::Type;
|
||||
|
||||
// TODO: If perf needs it, convert layout an SOA format.
|
||||
/*
|
||||
Simple AST POD with functionality to seralize into C++ syntax.
|
||||
|
||||
ASTs are currently stored as an AOS. They are always reconstructed on demand.
|
||||
Thus redundant AST can easily occur.
|
||||
Not sure if its better to store them in a hashmap.
|
||||
*/
|
||||
struct AST
|
||||
{
|
||||
#pragma region Member API
|
||||
forceinline
|
||||
void add( Code other )
|
||||
void add( AST* other )
|
||||
{
|
||||
array_append( Entries, other );
|
||||
}
|
||||
|
||||
forceinline
|
||||
void add( array(Code) other )
|
||||
{
|
||||
array_appendv( Entries, other, sizeof(other) );
|
||||
}
|
||||
|
||||
forceinline
|
||||
void add( Code* entries, u32 num_entries )
|
||||
{
|
||||
array_appendv( Entries, entries, num_entries );
|
||||
other->Parent = this;
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool has_entries()
|
||||
{
|
||||
static bool lookup[Num_Types] = {
|
||||
static bool lookup[ ECode::Num_Types] = {
|
||||
false, // Invalid
|
||||
false, // Unused
|
||||
false, // Untyped
|
||||
@ -117,105 +173,310 @@ namespace gen
|
||||
return lookup[Type];
|
||||
}
|
||||
|
||||
string to_string();
|
||||
forceinline
|
||||
bool is_invalid()
|
||||
{
|
||||
return Type != ECode::Invalid;
|
||||
}
|
||||
|
||||
forceinline
|
||||
operator bool()
|
||||
char const* type_str()
|
||||
{
|
||||
return Type != Invalid;
|
||||
return ECode::str( Type );
|
||||
}
|
||||
|
||||
operator char const*()
|
||||
{
|
||||
return to_string();
|
||||
}
|
||||
string to_string();
|
||||
|
||||
#if 0
|
||||
bool operator ==( Code& other )
|
||||
{
|
||||
bool children_equal = true;
|
||||
|
||||
#define is( Value_ ) Type == Value_
|
||||
|
||||
if ( has_children() )
|
||||
{
|
||||
u32 left = array_count( Children );
|
||||
do
|
||||
{
|
||||
|
||||
}
|
||||
while ( left--, left > 0 )
|
||||
}
|
||||
|
||||
return
|
||||
Type == other.Type
|
||||
&& Name == other.Name
|
||||
&& children_equal
|
||||
;
|
||||
}
|
||||
#endif
|
||||
#pragma endregion Member API
|
||||
|
||||
#define Using_Code_POD \
|
||||
Code::EType Type; \
|
||||
string Name; \
|
||||
string Comment; \
|
||||
union { \
|
||||
array(Code) Entries; \
|
||||
string Content; \
|
||||
#define Using_Code_POD \
|
||||
CodeT Type; \
|
||||
bool Readonly; \
|
||||
AST* Parent; \
|
||||
string Name; \
|
||||
string Comment; \
|
||||
union { \
|
||||
array(AST*) Entries; \
|
||||
string Content; \
|
||||
};
|
||||
|
||||
Using_Code_POD;
|
||||
};
|
||||
|
||||
using CodeType = Code::EType;
|
||||
|
||||
struct Code_POD
|
||||
struct CodePOD
|
||||
{
|
||||
Using_Code_POD;
|
||||
};
|
||||
|
||||
constexpr Code UnusedCode = { Code::Unused, nullptr, nullptr, { nullptr } };
|
||||
// Its intended for the AST to have equivalent size to its POD.
|
||||
// All extra functionality within the AST namespace should just be syntatic sugar.
|
||||
static_assert( sizeof(AST) == sizeof(CodePOD), "ERROR: AST IS NOT POD" );
|
||||
|
||||
/*
|
||||
AST* typedef as to not constantly have to add the '*' as this is written often..
|
||||
|
||||
If GEN_ENABLE_READONLY_AST is defined, readonly assertions will be done on any member dreference,
|
||||
and the 'gen API' related functions. will set their created ASTs to readonly before returning.
|
||||
|
||||
Casting to AST* will bypass.
|
||||
*/
|
||||
struct Code
|
||||
{
|
||||
AST* ast;
|
||||
|
||||
forceinline
|
||||
operator bool()
|
||||
{
|
||||
return ast->is_invalid();
|
||||
}
|
||||
|
||||
bool operator ==( Code other )
|
||||
{
|
||||
return ast == other.ast;
|
||||
}
|
||||
|
||||
operator AST*()
|
||||
{
|
||||
return ast;
|
||||
}
|
||||
|
||||
Code& operator =( Code other )
|
||||
{
|
||||
ast = other.ast;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef GEN_ENABLE_READONLY_AST
|
||||
forceinline
|
||||
AST* operator ->()
|
||||
{
|
||||
if ( ast == nullptr )
|
||||
fatal("Attempt to dereference a nullptr!");
|
||||
|
||||
if ( ast->Readonly )
|
||||
fatal("Attempted to access a member from a readonly ast!");
|
||||
|
||||
return ast;
|
||||
}
|
||||
|
||||
Code& operator *() = delete;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Used when the its desired when omission is allowed in a definition.
|
||||
ct Code UnusedCode = { nullptr };
|
||||
|
||||
// Used internally for the most part to identify invaidly generated code.
|
||||
ct CodePOD InvalidCode = { ECode::Invalid, false, nullptr, nullptr, nullptr, { nullptr } };
|
||||
|
||||
/*
|
||||
Type registy: Used to store Typename ASTs. Types are registered by their string literal value.
|
||||
|
||||
Purely used as a memory optimization.
|
||||
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 );
|
||||
|
||||
#pragma region gen API
|
||||
/*
|
||||
Initialize the library.
|
||||
This currently just initializes the CodePool.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/*
|
||||
Foward Declare a type:
|
||||
<specifiers> <type> <name>;
|
||||
*/
|
||||
Code decl_type( char const* name, Code type, Code specifiers = UnusedCode );
|
||||
|
||||
/*
|
||||
Foward Declare a function:
|
||||
<specifiers> <name> ( <params> );
|
||||
*/
|
||||
Code decl_fn( char const* name
|
||||
, Code specifiers
|
||||
, Code params
|
||||
, Code ret_type
|
||||
);
|
||||
|
||||
Code def_parameters( s32 num, ... );
|
||||
/*
|
||||
Define an expression:
|
||||
< c/c++ expression >
|
||||
*/
|
||||
Code def_expression( Code value );
|
||||
|
||||
/*
|
||||
Define a function:
|
||||
<specifiers> <name> ( <params> )
|
||||
{
|
||||
<body>
|
||||
}
|
||||
*/
|
||||
Code def_function( char const* name
|
||||
, Code specifiers
|
||||
, Code params
|
||||
, Code ret_type
|
||||
, Code body
|
||||
);
|
||||
Code def_function_body( u32 num, ... );
|
||||
|
||||
/*
|
||||
Define a fucntion body:
|
||||
{
|
||||
<entry>
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
Each entry is provided an empty line separation.
|
||||
*/
|
||||
Code def_function_body( s32 num, ... );
|
||||
|
||||
/*
|
||||
Define a namespace;
|
||||
namespace <name>
|
||||
{
|
||||
<body>
|
||||
}
|
||||
*/
|
||||
Code def_namespace( char const* name, Code body );
|
||||
Code def_namespace_body( u32 num, ... );
|
||||
|
||||
Code def_specifiers( u32 num , ... );
|
||||
/*
|
||||
Define a namespace body:
|
||||
{
|
||||
<entry>
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
Each entry is provided an empty line separation.
|
||||
*/
|
||||
Code def_namespace_body( s32 num, ... );
|
||||
|
||||
/*
|
||||
Define a set of parameters for a function:
|
||||
<name> <type>, ...
|
||||
*/
|
||||
Code def_parameters( s32 num, ... );
|
||||
|
||||
/*
|
||||
Define a set of specifiers for a function, struct, type, or varaible
|
||||
*/
|
||||
Code def_specifiers( s32 num , ... );
|
||||
|
||||
/*
|
||||
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_body( u32 num, ... );
|
||||
|
||||
/*
|
||||
Define a struct's body:
|
||||
{
|
||||
<entry>
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
Each entry is provided an empty line separation.
|
||||
*/
|
||||
Code def_struct_body( s32 num, ... );
|
||||
|
||||
/*
|
||||
Define a variable:
|
||||
<specifiers> <type> <name> = <value>;
|
||||
*/
|
||||
Code def_variable( char const* name, Code type, Code value = UnusedCode, Code specifiers = UnusedCode );
|
||||
|
||||
/*
|
||||
Define a type AST value.
|
||||
Useless by itself, its intended to be used in conjunction with
|
||||
*/
|
||||
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 );
|
||||
|
||||
/*
|
||||
Define an untyped code string.
|
||||
|
||||
Untyped code may be used in bodies of functions, namespaces, or structs
|
||||
or the in places where expressions may be placed.
|
||||
|
||||
Because the code within it is untyped, errors will naturally not be provided.
|
||||
Consider this an a preprocessor define.
|
||||
*/
|
||||
Code untyped_str( char const* str );
|
||||
|
||||
/*
|
||||
Define an untyped code string using traditional 'printf'.
|
||||
|
||||
Untyped code may be used in bodies of functions, namespaces, or structs
|
||||
or the in places where expressions may be placed.
|
||||
|
||||
Because the code within it is untyped, errors will naturally not be provided.
|
||||
Consider this an a preprocessor define.
|
||||
*/
|
||||
Code untyped_fmt( char const* fmt, ... );
|
||||
|
||||
Code token_fmt( char const* fmt, ... );
|
||||
/*
|
||||
Define an untyped code string using token formatting:
|
||||
... { <ID> } ... Will be repalced with value of token ID.
|
||||
|
||||
Values are to provided as: <char const* ID>, <char const* Value>, ...
|
||||
|
||||
num_tokens : The number of ID-Value pairs provided.
|
||||
|
||||
Untyped code may be used in bodies of functions, namespaces, or structs
|
||||
or the in places where expressions may be placed.
|
||||
|
||||
Because the code within it is untyped, errors will naturally not be provided.
|
||||
Consider this an a preprocessor define.
|
||||
*/
|
||||
Code token_fmt( char const* fmt, s32 num_tokens, ... );
|
||||
|
||||
|
||||
/*
|
||||
Creates a unit file.
|
||||
|
||||
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.
|
||||
|
||||
The name provided is the name of the file.
|
||||
*/
|
||||
Code create_Unit( char const* name );
|
||||
|
||||
/*
|
||||
Used to generate the files.
|
||||
This is inspired by jai's usage of the string_builder with #insert.
|
||||
|
||||
Its expected when using this library that Code ast will be serialized with the:
|
||||
Builder::print() proc
|
||||
|
||||
The seralized content of the Code ast will be appended to Buffer within an empty line
|
||||
prepared for a another definition or to add an empty newline to the end of the file.
|
||||
|
||||
Builder::write() should be called when all Code has been seralized for that file.
|
||||
|
||||
The #insert directive is thus represented by an #include of the generated file at your desired line
|
||||
of any file in the target project.
|
||||
*/
|
||||
struct Builder
|
||||
{
|
||||
zpl_file File;
|
||||
@ -226,7 +487,67 @@ namespace gen
|
||||
bool open( char const* path );
|
||||
void write();
|
||||
};
|
||||
#pragma endregion gen API
|
||||
}
|
||||
|
||||
#define gen_main main
|
||||
#pragma region MACROS
|
||||
# define gen_main main
|
||||
|
||||
# define __ UnusedCode
|
||||
|
||||
/*
|
||||
gen's Domain Specific Langauge.
|
||||
|
||||
Completely optional, makes the code gen syntax less verbose..
|
||||
*/
|
||||
#ifdef GEN_DEFINE_DSL
|
||||
# define type( Name_, Value_ ) Code Name_ = gen::def_type( txt(Value_) )
|
||||
# define type_fmt( Name_, Fmt_, ... ) Code Name_ = gen::def_type( bprintf( Fmt_, __VA_ARGS__ ) )
|
||||
# define value( Name_, Value_ ) Code Name_ = gen::untyped_str( Value_ )
|
||||
# define specifiers( Name_, ... ) Code Name_ = gen::def_specifiers( VA_NARGS( __VA_ARGS__ ), __VA_ARGS__ )
|
||||
# define using( Name_, Type_ ) Code Name_ = gen::def_using( #Name_, Type_ )
|
||||
|
||||
# define var( Name_, Type_, Value_, Specifiers_ ) \
|
||||
Code Name_ = gen::def_variable( #Name_, Type_, untyped_str( #Value_ ), Specifiers_ )
|
||||
|
||||
// # define def ( Name _ ) Code Name_;
|
||||
|
||||
# define params( ... ) gen::def_parameters( VA_NARGS( __VA_ARGS__ ) / 2, __VA_ARGS__ )
|
||||
|
||||
/*
|
||||
Defines scoped symbol.
|
||||
|
||||
Used with:
|
||||
- function
|
||||
- namespace
|
||||
- struct
|
||||
*/
|
||||
# define def( Name_ ) Code Name_;
|
||||
|
||||
# define function( Name_, Specifiers_, ReturnType_, Parameters_, Body_ ) \
|
||||
Name_ = gen::def_function( #Name_, Specifiers_, Parameters_, ReturnType_, Body_ )
|
||||
|
||||
# define function_body( ... ) \
|
||||
gen::def_function_body( VA_NARGS( __VA_ARS__ ), __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__ )
|
||||
#endif
|
||||
#pragma endregion MACROS
|
||||
|
||||
#pragma region CONSTANTS
|
||||
namespace gen
|
||||
{
|
||||
// Predefined typename codes.
|
||||
|
||||
extern const Code t_bool;
|
||||
extern const Code t_sw;
|
||||
extern const Code t_uw;
|
||||
|
||||
extern const Code spec_inline;
|
||||
}
|
||||
#pragma endregion CONSTANTS
|
||||
#endif
|
||||
|
507
test/Array.hpp
507
test/Array.hpp
@ -17,6 +17,7 @@
|
||||
Code t_uw = def_type( txt(uw) );
|
||||
Code t_allocator = def_type( txt(allocator) );
|
||||
|
||||
#ifndef GEN_DEFINE_DSL
|
||||
Code header;
|
||||
{
|
||||
Code num = def_variable( "Num", t_uw );
|
||||
@ -30,20 +31,44 @@
|
||||
Code grow_formula;
|
||||
{
|
||||
Code spec = def_specifiers(1, Specifier::Inline);
|
||||
Code params = def_parameters(1, "value", t_uw );
|
||||
Code body = untyped_fmt( "\t""return 2 * value * 8;" );
|
||||
Code params = def_parameters(1, t_uw, "value" );
|
||||
Code body = untyped_str( "return 2 * value * 8;" );
|
||||
|
||||
grow_formula = def_function( "grow_formula", spec, params, t_sw, body );
|
||||
}
|
||||
|
||||
Code base_body = def_struct_body(2, header, grow_formula);
|
||||
Code base = def_struct( "ArrayBase", base_body );
|
||||
return base;
|
||||
Code body = def_struct_body(2, header, grow_formula);
|
||||
Code ArrayBase = def_struct( "ArrayBase", body );
|
||||
|
||||
#else
|
||||
def( ArrayBase )
|
||||
def ( Header )
|
||||
{
|
||||
var( Num, t_uw, __, __ );
|
||||
var( Capacity, t_uw, __, __);
|
||||
var( Allocator, t_allocator, __, __);
|
||||
|
||||
Code body = struct_body( Num, Capacity, Allocator );
|
||||
|
||||
struct( Header, __, __, body );
|
||||
}
|
||||
|
||||
def( grow_formula )
|
||||
{
|
||||
function( grow_formula, spec_inline, t_uw, params( t_uw, "value" ), untyped_str("return 2 * value * 8") );
|
||||
}
|
||||
|
||||
Code body = struct_body( Header, grow_formula );
|
||||
struct( ArrayBase, __, __, body );
|
||||
#endif
|
||||
|
||||
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
|
||||
// Make these global consts to be accessed anywhere...
|
||||
Code t_uw = def_type( txt(uw) );
|
||||
Code t_sw = def_type( txt(sw) );
|
||||
@ -51,16 +76,14 @@
|
||||
Code t_allocator = def_type( txt(allocator) );
|
||||
Code t_void = def_type( txt(void) );
|
||||
|
||||
Code v_nullptr = untyped_fmt( "nullptr" );
|
||||
Code v_nullptr = untyped_str( "nullptr" );
|
||||
|
||||
Code spec_ct = def_specifiers(1, Specifier::Constexpr );
|
||||
Code spec_inline = def_specifiers(1, Specifier::Inline );
|
||||
|
||||
Code type = def_type( type_str );
|
||||
Code ptr_type = def_type( string_sprintf_buf( g_allocator, "%s*", type_str ) );
|
||||
Code ref_type = def_type( string_sprintf_buf( g_allocator, "%s&", type_str ) );
|
||||
|
||||
string name = string_sprintf_buf( g_allocator, "Array_%s", type_str );
|
||||
Code ptr_type = def_type( bprintf( "%s*", type_str ) );
|
||||
Code ref_type = def_type( bprintf( "%s&", type_str ) );
|
||||
|
||||
// From ArrayBase
|
||||
Code t_header = def_type( "Header" );
|
||||
@ -69,43 +92,43 @@
|
||||
|
||||
Code array_def;
|
||||
{
|
||||
Code using_type = def_using( "type", type );
|
||||
Code using_type = def_using( "Type", type );
|
||||
Code data = def_variable( "Data", ptr_type );
|
||||
|
||||
Code init;
|
||||
{
|
||||
Code params = def_parameters( 1, "mem_hanlder", t_allocator );
|
||||
Code body = untyped_fmt( "\t""return init_reserve( mem_handler, grow_formula(0) );" );
|
||||
Code params = def_parameters( 1, t_allocator, "mem_handler" );
|
||||
Code body = untyped_str( "return init_reserve( mem_handler, grow_formula(0) );" );
|
||||
|
||||
init = def_function( "init", UnusedCode, params, t_bool, body );
|
||||
}
|
||||
|
||||
Code init_reserve;
|
||||
{
|
||||
Code params = def_parameters( 2, "mem_handler", ref_type, "capacity", t_sw );
|
||||
Code params = def_parameters( 2, t_allocator, "mem_handler", t_sw, "capacity" );
|
||||
Code body;
|
||||
{
|
||||
Code header_value = untyped_fmt(
|
||||
"rcast( Header*, alloc( mem_handler, sizeof( Header ) + sizeof(type) + capacity ))"
|
||||
Code header_value = untyped_str(
|
||||
"rcast( Header*, alloc( mem_handler, sizeof( Header ) + sizeof(Type) + capacity ))"
|
||||
);
|
||||
Code header = def_variable( "", ptr_header, header_value );
|
||||
Code header = def_variable( "header", ptr_header, header_value );
|
||||
|
||||
Code null_check = untyped_fmt(
|
||||
"\t" "if (header == nullptr)"
|
||||
"\n\t\t" "return false;"
|
||||
Code null_check = untyped_str(
|
||||
"if (header == nullptr)"
|
||||
"\n" "return false;"
|
||||
);
|
||||
|
||||
Code header_init = untyped_fmt(
|
||||
"\n\t" "header->Num = 0;"
|
||||
"\n\t" "header->Capacity = capacity;"
|
||||
"\n\t" "header->Allocator = mem_handler;"
|
||||
Code header_init = untyped_str(
|
||||
"header->Num = 0;"
|
||||
"\n""header->Capacity = capacity;"
|
||||
"\n""header->Allocator = mem_handler;"
|
||||
);
|
||||
|
||||
Code assign_data = untyped_fmt(
|
||||
"\t" "Data = rcast( %s, header + 1 );", ptr_type
|
||||
Code assign_data = untyped_str(
|
||||
"Data = rcast( %s, header + 1 );", ptr_type
|
||||
);
|
||||
|
||||
Code ret_true = untyped_fmt( "\t""return true" );
|
||||
Code ret_true = untyped_str( "\t""return true" );
|
||||
|
||||
body = def_function_body( 5
|
||||
, header
|
||||
@ -121,9 +144,9 @@
|
||||
|
||||
Code free;
|
||||
{
|
||||
Code body = untyped_fmt(
|
||||
"\t" "Header& header = get_header();"
|
||||
"\n\t" "::free( header.Allocator, & get_header() );"
|
||||
Code body = untyped_str(
|
||||
"Header& header = get_header();"
|
||||
"\n""::free( header.Allocator, & get_header() );"
|
||||
);
|
||||
|
||||
free = def_function( "free", UnusedCode, UnusedCode, t_void, body );
|
||||
@ -131,22 +154,22 @@
|
||||
|
||||
Code append;
|
||||
{
|
||||
Code params = def_parameters( 1, "value", type );
|
||||
Code params = def_parameters( 1, type, "value" );
|
||||
Code body;
|
||||
{
|
||||
Code header = def_variable( "", ref_header, untyped_fmt( "get_header()") );
|
||||
Code header = def_variable( "header", ref_header, untyped_str( "get_header()") );
|
||||
|
||||
Code check_cap = untyped_fmt(
|
||||
"\t" "if ( header.Capacity < header.Num + 1 )"
|
||||
"\n\t\t" "if ( ! grow(0) )"
|
||||
"\n\t\t\t" "return false;"
|
||||
Code check_cap = untyped_str(
|
||||
"if ( header.Capacity < header.Num + 1 )"
|
||||
"\n" "if ( ! grow(0) )"
|
||||
"\n" "return false;"
|
||||
);
|
||||
|
||||
Code assign = untyped_fmt(
|
||||
"\t" "Data[ header.Num ] = value;"
|
||||
"\t\n" "header.Num++;"
|
||||
Code assign = untyped_str(
|
||||
"Data[ header.Num ] = value;"
|
||||
"\n" "header.Num++;"
|
||||
"\n"
|
||||
"\n\t" "return true;"
|
||||
"\n" "return true;"
|
||||
);
|
||||
|
||||
body = def_function_body( 3, header, check_cap, assign );
|
||||
@ -157,9 +180,9 @@
|
||||
|
||||
Code back;
|
||||
{
|
||||
Code body = untyped_fmt(
|
||||
"\t" "Header& header = get_header();"
|
||||
"\n\t" "return data[ header.Num - 1 ];"
|
||||
Code body = untyped_str(
|
||||
"Header& header = get_header();"
|
||||
"\n" "return data[ header.Num - 1 ];"
|
||||
);
|
||||
|
||||
back = def_function( "back", UnusedCode, UnusedCode, type, body );
|
||||
@ -167,26 +190,26 @@
|
||||
|
||||
Code clear;
|
||||
{
|
||||
Code body = untyped_fmt( "\t""get_header().Num = 0;" );
|
||||
Code body = untyped_str( "get_header().Num = 0;" );
|
||||
|
||||
clear = def_function( "clear", UnusedCode, UnusedCode, t_void, body );
|
||||
}
|
||||
|
||||
Code fill;
|
||||
{
|
||||
Code params = def_parameters( 3, "begin", t_uw, "end", t_uw, "value", type );
|
||||
Code params = def_parameters( 3, t_uw, "begin", t_uw, "end", type, "value" );
|
||||
Code body;
|
||||
{
|
||||
Code header = def_variable( "", ref_header, untyped_fmt( "get_header()") );
|
||||
Code header = def_variable( "header", ref_header, untyped_str( "get_header()") );
|
||||
|
||||
Code check = untyped_fmt(
|
||||
"\t" "if ( begin < 0 || end >= header.Num )"
|
||||
"\n\t\t" "fatal( \"Range out of bounds\" );"
|
||||
Code check = untyped_str(
|
||||
"if ( begin < 0 || end >= header.Num )"
|
||||
"\n" "fatal( \"Range out of bounds\" );"
|
||||
);
|
||||
|
||||
Code iter = untyped_fmt(
|
||||
"\t" "for ( sw index = begin; index < end; index++ )"
|
||||
"\n\t\t" "Data[index] = vallue;"
|
||||
Code iter = untyped_str(
|
||||
"for ( sw index = begin; index < end; index++ )"
|
||||
"\n" "Data[index] = vallue;"
|
||||
);
|
||||
|
||||
body = def_function_body( 3, header, check, iter );
|
||||
@ -197,25 +220,25 @@
|
||||
|
||||
Code get_header;
|
||||
{
|
||||
Code body = untyped_fmt( "\t""return pcast( Header, Data - 1 );" );
|
||||
Code body = untyped_str( "return pcast( Header, Data - 1 );" );
|
||||
|
||||
get_header = def_function( "get_header", spec_inline, UnusedCode, ref_header, body );
|
||||
}
|
||||
|
||||
Code grow;
|
||||
{
|
||||
Code param = def_parameters( 1, "min_capacity", t_uw );
|
||||
Code param = def_parameters( 1, t_uw, "min_capacity" );
|
||||
Code body;
|
||||
{
|
||||
Code header = def_variable( "header", ref_header, untyped_fmt("get_header") );
|
||||
Code new_capacity = def_variable( "new_capacity", t_uw, untyped_fmt("grow_formula( header.Capacity )") );
|
||||
Code header = def_variable( "header", ref_header, untyped_str("get_header()") );
|
||||
Code new_capacity = def_variable( "new_capacity", t_uw, untyped_str("grow_formula( header.Capacity )") );
|
||||
|
||||
Code check_n_set = untyped_fmt(
|
||||
"\t" "if ( new_capacity < min_capacity )"
|
||||
"\n\t\t" "new_capacity = min_capacity;"
|
||||
Code check_n_set = untyped_str(
|
||||
"if ( new_capacity < min_capacity )"
|
||||
"\n" "new_capacity = min_capacity;"
|
||||
);
|
||||
|
||||
Code ret = untyped_fmt( "\t" "return set_capacity( new_capacity );" );
|
||||
Code ret = untyped_str( "return set_capacity( new_capacity );" );
|
||||
|
||||
body = def_function_body( 4, header, new_capacity, check_n_set, ret );
|
||||
}
|
||||
@ -227,10 +250,10 @@
|
||||
{
|
||||
Code body;
|
||||
{
|
||||
Code header = def_variable( "header", ref_header, untyped_fmt("get_header()") );
|
||||
Code header = def_variable( "header", ref_header, untyped_str("get_header()") );
|
||||
|
||||
Code assertion = untyped_fmt( "\t" "assert( header.Num > 0 );" );
|
||||
Code decrement = untyped_fmt( "\t" "header.Num--; " );
|
||||
Code assertion = untyped_str( "assert( header.Num > 0 );" );
|
||||
Code decrement = untyped_str( "header.Num--; " );
|
||||
|
||||
body = def_function_body( 3, header, assertion, decrement );
|
||||
}
|
||||
@ -240,17 +263,17 @@
|
||||
|
||||
Code reserve;
|
||||
{
|
||||
Code params = def_parameters( 1, "new_capacity", t_uw );
|
||||
Code params = def_parameters( 1, t_uw, "new_capacity" );
|
||||
Code body;
|
||||
{
|
||||
Code header = def_variable( "header", ref_header, untyped_fmt("get_header()") );
|
||||
Code header = def_variable( "header", ref_header, untyped_str("get_header()") );
|
||||
|
||||
Code check_n_set = untyped_fmt(
|
||||
"\t" "if ( header.Capacity < new_capacity )"
|
||||
"\n\t\t" "return set_capacity( new_capacity );"
|
||||
Code check_n_set = untyped_str(
|
||||
"if ( header.Capacity < new_capacity )"
|
||||
"\n" "return set_capacity( new_capacity );"
|
||||
);
|
||||
|
||||
Code ret = untyped_fmt( "\t" "return true" );
|
||||
Code ret = untyped_str( "\t" "return true" );
|
||||
|
||||
body = def_function_body( 3, header, check_n_set, ret );
|
||||
}
|
||||
@ -260,21 +283,21 @@
|
||||
|
||||
Code resize;
|
||||
{
|
||||
Code param = def_parameters( 1, "new_num", t_uw );
|
||||
Code param = def_parameters( 1, t_uw, "new_num" );
|
||||
|
||||
Code body;
|
||||
{
|
||||
Code header = def_variable( "header", ref_header, untyped_fmt("get_header()") );
|
||||
Code header = def_variable( "header", ref_header, untyped_str("get_header()") );
|
||||
|
||||
Code check_n_grow = untyped_fmt(
|
||||
"\t" "if ( header.Capacity < new_num )"
|
||||
"\n\t\t" "if ( ! grow( new_num) )"
|
||||
"\n\t\t\t" "return false;"
|
||||
Code check_n_grow = untyped_str(
|
||||
"if ( header.Capacity < new_num )"
|
||||
"\n" "if ( ! grow( new_num) )"
|
||||
"\n" "return false;"
|
||||
);
|
||||
|
||||
Code set_n_ret = untyped_fmt(
|
||||
"\t" "header.Count = new_num;"
|
||||
"\n\t" "return true;"
|
||||
Code set_n_ret = untyped_str(
|
||||
"header.Count = new_num;"
|
||||
"\n""return true;"
|
||||
);
|
||||
|
||||
body = def_function_body( 3, header, check_n_grow, set_n_ret );
|
||||
@ -285,40 +308,40 @@
|
||||
|
||||
Code set_capacity;
|
||||
{
|
||||
Code param = def_parameters( 1, "capacity", t_uw );
|
||||
Code param = def_parameters( 1, t_uw, "capacity" );
|
||||
|
||||
Code body;
|
||||
{
|
||||
Code header = def_variable( "header", ref_header, untyped_fmt("get_header()") );
|
||||
Code header = def_variable( "header", ref_header, untyped_str("get_header()") );
|
||||
|
||||
Code checks = untyped_fmt(
|
||||
"\t" "if ( capacity == header.Capacity )"
|
||||
"\n\t\t" "return true;"
|
||||
"\n"
|
||||
"\n\t" "if ( capacity < header.Num )"
|
||||
"\n\t\t" "header.Num = capacity;"
|
||||
Code checks = untyped_str(
|
||||
"if ( capacity == header.Capacity )"
|
||||
"\n" "return true;"
|
||||
|
||||
"if ( capacity < header.Num )"
|
||||
"\n" "header.Num = capacity;"
|
||||
);
|
||||
|
||||
Code size = def_variable( "size", t_uw, untyped_fmt("sizeof(Header) + sizeof(type) * capacity"));
|
||||
Code new_header = def_variable( "new_header", ptr_header, untyped_fmt("rcast( Header*, alloc( header.Allocator, size ));"));
|
||||
Code size = def_variable( "size", t_uw, untyped_str("sizeof(Header) + sizeof(Type) * capacity"));
|
||||
Code new_header = def_variable( "new_header", ptr_header, untyped_str("rcast( Header*, alloc( header.Allocator, size ));"));
|
||||
|
||||
Code check_n_move = untyped_fmt(
|
||||
"\t""if ( new_header == nullptr )"
|
||||
"\n\t\t""return false;"
|
||||
"\n"
|
||||
"\n\t""memmove( new_header, & header, sizeof(Header) + sizeof(type) * header.Num );"
|
||||
Code check_n_move = untyped_str(
|
||||
"if ( new_header == nullptr )"
|
||||
"\n" "return false;"
|
||||
"\n"
|
||||
"\n" "memmove( new_header, & header, sizeof(Header) + sizeof(Type) * header.Num );"
|
||||
);
|
||||
|
||||
Code set_free_ret = untyped_fmt(
|
||||
"\t" "new_header->Allocator = header.Allocator;"
|
||||
"\n\t" "new_header->Num = header.Num;"
|
||||
"\n\t" "new_header->Capacity = header.Capacity;"
|
||||
"\n"
|
||||
"\n\t" "zpl_free( header );"
|
||||
"\n"
|
||||
"\n\t" "*Data = new_header + 1;"
|
||||
"\n"
|
||||
"\n\t" "return true;"
|
||||
Code set_free_ret = untyped_str(
|
||||
"new_header->Allocator = header.Allocator;"
|
||||
"\n" "new_header->Num = header.Num;"
|
||||
"\n" "new_header->Capacity = header.Capacity;"
|
||||
"\n"
|
||||
"\n" "zpl_free( header );"
|
||||
"\n"
|
||||
"\n" "*Data = new_header + 1;"
|
||||
"\n"
|
||||
"\n" "return true;"
|
||||
);
|
||||
|
||||
body = def_function_body( 6, header, checks, size, new_header, check_n_move, set_free_ret );
|
||||
@ -327,6 +350,8 @@
|
||||
set_capacity = def_function( "set_capacity", UnusedCode, param, t_bool, body );
|
||||
}
|
||||
|
||||
string name = bprintf( "Array_%s", type_str );
|
||||
|
||||
Code body = def_struct_body( 15
|
||||
, using_type
|
||||
, data
|
||||
@ -348,6 +373,282 @@
|
||||
|
||||
array_def = def_struct( name, body, parent );
|
||||
}
|
||||
#else
|
||||
type( t_uw, uw );
|
||||
type( t_sw, sw );
|
||||
type( t_bool, bool );
|
||||
type( t_allocator, allocator );
|
||||
type( t_void, void );
|
||||
|
||||
value( v_nullptr, nullptr );
|
||||
|
||||
specifiers( spec_ct, Specifier::Constexpr );
|
||||
specifiers( spec_inline, Specifier::Inline );
|
||||
|
||||
type_fmt( type, type_str, __);
|
||||
type_fmt( ptr_type, "%s*", type_str );
|
||||
type_fmt( ref_type, "%&", type_str );
|
||||
|
||||
|
||||
// From ArrayBase
|
||||
type( t_header, Header );
|
||||
type( ptr_header, Header* );
|
||||
type( ref_header, Header& );
|
||||
|
||||
def( array_def )
|
||||
{
|
||||
using( Type, type );
|
||||
var( Data, ptr_type, __, __ );
|
||||
|
||||
def( init )
|
||||
{
|
||||
Code body = function_body( untyped_str("return init_reserve( mem_handler, grow_formula(0) );" ));
|
||||
|
||||
function( init, __, t_bool, params( t_allocator, "mem_handler" ), body );
|
||||
}
|
||||
|
||||
def( init_reserve )
|
||||
{
|
||||
def( body )
|
||||
{
|
||||
var(header, ptr_header, untyped_str("rcast( Header*, alloc( mem_handler, sizeof(Header) + sizeof(Type) + capacity))" ), __);
|
||||
|
||||
Code null_check = untyped_str(
|
||||
"if (header == nullptr)"
|
||||
"\n" "return false;"
|
||||
);
|
||||
|
||||
Code header_init = untyped_str(
|
||||
"header->Num = 0;"
|
||||
"\n""header->Capacity = capacity;"
|
||||
"\n""header->Allocator = mem_handler;"
|
||||
);
|
||||
|
||||
Code assign_data = untyped_str( "Data = rcast( Type*, header + 1 );" );
|
||||
Code ret_true = untyped_str( "return true" );
|
||||
|
||||
Code body = function_body( header, null_check, header_init, assign_data, ret_true );
|
||||
}
|
||||
|
||||
function( init_reserve, __, t_bool, params( ref_type, "mem_handler" ) , body);
|
||||
}
|
||||
|
||||
def( free )
|
||||
{
|
||||
Code body = untyped_str(
|
||||
"Header& header = get_header();"
|
||||
"\n""free( header.Allocator, & get_header() );"
|
||||
);
|
||||
|
||||
function( free, __, t_void, __, body );
|
||||
}
|
||||
|
||||
def( append )
|
||||
{
|
||||
def( body )
|
||||
{
|
||||
var( header, ref_header, untyped_str("get_header()"), __ );
|
||||
|
||||
Code check_cap = untyped_str(
|
||||
"if ( header.Capacity < header.Num + 1 )"
|
||||
"\n" "if ( ! grow(0) )"
|
||||
"\n" "return false;"
|
||||
);
|
||||
|
||||
Code assign = untyped_str(
|
||||
"Data[ header.Num ] = value;"
|
||||
"\n" "header.Num++;"
|
||||
"\n"
|
||||
"\n" "return true;"
|
||||
);
|
||||
|
||||
body = function_body( header, check_cap, assign );
|
||||
}
|
||||
|
||||
function( append, __, t_void, params( type, "value" ), body );
|
||||
}
|
||||
|
||||
def( back );
|
||||
{
|
||||
Code body = untyped_str(
|
||||
"Header& header = get_header();"
|
||||
"\n" "return data[ header.Num - 1 ];"
|
||||
);
|
||||
|
||||
function( back, __, type, __, body );
|
||||
}
|
||||
|
||||
def( clear )
|
||||
function( clear, __, t_void, __, untyped_str("get_header().Num = 0;") );
|
||||
|
||||
def( fill );
|
||||
{
|
||||
def( body )
|
||||
{
|
||||
var( header, ref_header, untyped_str("get_header()"), __ );
|
||||
|
||||
Code check = untyped_str(
|
||||
"if ( begin < 0 || end >= header.Num )"
|
||||
"\n" "fatal( \"Range out of bounds\" );"
|
||||
);
|
||||
|
||||
Code iter = untyped_str(
|
||||
"for ( sw index = begin; index < end; index++ )"
|
||||
"\n" "Data[index] = vallue;"
|
||||
);
|
||||
|
||||
function_body( header, check, iter );
|
||||
}
|
||||
|
||||
function( fill, __, t_void, params( t_uw, "begin", t_uw, "end", type, "value" ), body );
|
||||
}
|
||||
|
||||
def( get_header )
|
||||
function( get_header, spec_inline, ref_header, __, untyped_str("return pcast( Header, Data - 1);") );
|
||||
|
||||
def( grow )
|
||||
{
|
||||
def( body )
|
||||
{
|
||||
var( header, ref_header, untyped_str("get_header()"), __ );
|
||||
var( new_capacity, t_uw, untyped_str("grow_formula( header.Capacity)"), __);
|
||||
|
||||
Code check_n_set = untyped_str(
|
||||
"if ( new_capacity < min_capacity )"
|
||||
"new_capacity = min_capacity;"
|
||||
);
|
||||
|
||||
Code ret = untyped_str( "return set_capacity( new_capacity );" );
|
||||
|
||||
body = function_body( header, new_capacity, check_n_set, ret );
|
||||
}
|
||||
|
||||
function( grow, __, t_bool, params( t_uw, "min_capacity" ), body );
|
||||
}
|
||||
|
||||
def( pop )
|
||||
{
|
||||
def( body )
|
||||
{
|
||||
var( header, ref_header, get_header(), UnusedCode );
|
||||
|
||||
Code assertion = untyped_str( "assert( header.Num > 0 );" );
|
||||
Code decrement = untyped_str( "header.Num--; " );
|
||||
|
||||
body = function_body( header, assertion, decrement );
|
||||
}
|
||||
|
||||
function( pop, __, t_void, __, body );
|
||||
}
|
||||
|
||||
def( reserve )
|
||||
{
|
||||
def( body )
|
||||
{
|
||||
var( header, ref_header, untyped_str("get_header()"), __ );
|
||||
|
||||
Code check_n_set = untyped_str(
|
||||
"if ( header.Capacity < new_capacity )"
|
||||
"return set_capacity( new_capacity );"
|
||||
);
|
||||
|
||||
Code ret = untyped_str("return true");
|
||||
|
||||
body = function_body( header, check_n_set, ret );
|
||||
}
|
||||
|
||||
function( reserve, __, t_bool, params( t_uw, "new_capacity" ), body );
|
||||
}
|
||||
|
||||
def( resize )
|
||||
{
|
||||
def( body )
|
||||
{
|
||||
var( header, ref_header, untyped_str("get_header()"), __ );
|
||||
|
||||
Code check_n_grow = untyped_str(
|
||||
"if ( header.Capacity < new_num )"
|
||||
"if ( ! grow( new_num) )"
|
||||
"return false;"
|
||||
);
|
||||
|
||||
Code set_n_ret = untyped_str(
|
||||
"header.Count = new_num;"
|
||||
"return true;"
|
||||
);
|
||||
|
||||
body = function_body( header, check_n_grow, set_n_ret );
|
||||
}
|
||||
|
||||
function( resize, __, t_bool, params( t_uw, "new_num" ), body );
|
||||
}
|
||||
|
||||
def( set_capacity )
|
||||
{
|
||||
def( body )
|
||||
{
|
||||
var( header, ref_header, untyped_str("get_header()"), __ );
|
||||
|
||||
Code checks = untyped_str(
|
||||
"if ( capacity == header.Capacity )"
|
||||
"return true;"
|
||||
"\n\n"
|
||||
"if ( capacity < header.Num )"
|
||||
"header.Num = capacity;"
|
||||
);
|
||||
|
||||
var( size, t_uw, untyped_str("sizeof(Header) + sizeof(Type) * capacity"), __ );
|
||||
var( new_header, ptr_header, untyped_str("rcast( Header*, alloc( header.Allocator, size ))"), __ );
|
||||
|
||||
Code check_n_move = untyped_str(
|
||||
"if ( new_header == nullptr )"
|
||||
"return false;"
|
||||
"\n\n"
|
||||
"memmove( new_header, & header, sizeof(Header) + sizeof(Type) * header.Num );"
|
||||
);
|
||||
|
||||
Code set_free_ret = untyped_str(
|
||||
"new_header->Allocator = header.Allocator;"
|
||||
"new_header->Num = header.Num;"
|
||||
"new_header->Capacity = header.Capacity;"
|
||||
"\n\n"
|
||||
"zpl_free( header );"
|
||||
"\n\n"
|
||||
"*Data = new_header + 1;"
|
||||
"\n\n"
|
||||
"return true;"
|
||||
);
|
||||
|
||||
body = function_body( header, checks, size, new_header, check_n_move, set_free_ret );
|
||||
}
|
||||
|
||||
function( set_capacity, __, t_bool, params( t_uw, "capacity" ), body );
|
||||
}
|
||||
|
||||
char const* name = bprintf( "Array_%s", type_str );
|
||||
|
||||
Code body = struct_body(
|
||||
Type
|
||||
, Data
|
||||
|
||||
, init
|
||||
, init_reserve
|
||||
, append
|
||||
, back
|
||||
, clear
|
||||
, fill
|
||||
, free
|
||||
, get_header
|
||||
, grow
|
||||
, pop
|
||||
, reserve
|
||||
, resize
|
||||
, set_capacity
|
||||
);
|
||||
|
||||
array_def = def_struct( name, body, parent );
|
||||
}
|
||||
#endif
|
||||
|
||||
return array_def;
|
||||
}
|
||||
|
@ -22,21 +22,27 @@
|
||||
{
|
||||
Code integral_type = def_type( type );
|
||||
|
||||
#ifndef GEN_DEFINE_DSL
|
||||
string name = string_sprintf( g_allocator, (char*)sprintf_buf, ZPL_PRINTF_MAXLEN, "square", type );
|
||||
|
||||
Code result;
|
||||
Code square;
|
||||
{
|
||||
Code params = def_parameters( 1, "value", integral_type );
|
||||
Code params = def_parameters( 1, integral_type, "value" );
|
||||
Code specifiers = def_specifiers( 1, Specifier::Inline );
|
||||
Code ret_stmt = untyped_fmt( "\treturn value * value;" );
|
||||
Code ret_stmt = untyped_fmt( "return value * value;" );
|
||||
|
||||
result = def_function( name, specifiers, params, integral_type, ret_stmt );
|
||||
square = def_function( name, specifiers, params, integral_type, ret_stmt );
|
||||
}
|
||||
|
||||
if ( ! result )
|
||||
#else
|
||||
def( square )
|
||||
function( square, __, integral_type, params( integral_type, "value" ), untyped_str("return value * value") );
|
||||
#endif
|
||||
|
||||
if ( ! square )
|
||||
fatal( "Failed to generate square function for: %s", type );
|
||||
|
||||
return result;
|
||||
return square;
|
||||
}
|
||||
|
||||
u32 gen_math()
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "Bloat.cpp"
|
||||
#include "math.hpp"
|
||||
#include "Array.hpp"
|
||||
|
||||
|
||||
#ifdef gen_time
|
||||
@ -12,9 +13,11 @@ int gen_main()
|
||||
zpl_printf("\nPress any key after attaching to process\n");
|
||||
getchar();
|
||||
|
||||
gen::init()
|
||||
gen::init();
|
||||
|
||||
int result = gen_math();
|
||||
int
|
||||
result = gen_math();
|
||||
result = gen_array_file();
|
||||
|
||||
Memory::cleanup();
|
||||
return result;
|
||||
|
Loading…
Reference in New Issue
Block a user