mirror of
https://github.com/Ed94/gencpp.git
synced 2024-12-22 15:54: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++.
|
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.
|
This project is not minimum feature complete yet.
|
||||||
Version 1 will have c and a subset of c++ features available to it.
|
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
|
## 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.
|
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...
|
* Need problably a better name, I found a few repos with this same one...
|
||||||
* Actually get to version 1.
|
* 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
|
#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
|
#ifdef BLOAT_IMPL
|
||||||
# define ZPL_IMPLEMENTATION
|
# define ZPL_IMPLEMENTATION
|
||||||
#endif
|
#endif
|
||||||
@ -21,7 +43,7 @@
|
|||||||
# define ZPL_MODULE_ESSENTIALS
|
# define ZPL_MODULE_ESSENTIALS
|
||||||
# define ZPL_MODULE_CORE
|
# define ZPL_MODULE_CORE
|
||||||
# define ZPL_MODULE_TIMER
|
# define ZPL_MODULE_TIMER
|
||||||
// # define ZPL_MODULE_HASHING
|
# define ZPL_MODULE_HASHING
|
||||||
// # define ZPL_MODULE_REGEX
|
// # define ZPL_MODULE_REGEX
|
||||||
// # define ZPL_MODULE_EVENT
|
// # define ZPL_MODULE_EVENT
|
||||||
// # define ZPL_MODULE_DLL
|
// # define ZPL_MODULE_DLL
|
||||||
|
549
project/gen.cpp
549
project/gen.cpp
@ -5,26 +5,48 @@
|
|||||||
#ifdef gen_time
|
#ifdef gen_time
|
||||||
namespace gen
|
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 decl_type( char const* name, Code type, Code specifiers )
|
||||||
{
|
{
|
||||||
|
using namespace ECode;
|
||||||
|
|
||||||
|
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
|
Code
|
||||||
result = make();
|
result = make();
|
||||||
result.Type = Code::Decl_Type;
|
result->Type = Decl_Type;
|
||||||
result.Name = string_make( g_allocator, name );
|
result->Name = string_make( g_allocator, name );
|
||||||
|
|
||||||
array_init( result.Entries, g_allocator );
|
array_init( result->Entries, g_allocator );
|
||||||
result.add( specifiers );
|
result->add( specifiers );
|
||||||
result.add( type );
|
result->add( type );
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -35,57 +57,77 @@ namespace gen
|
|||||||
, Code ret_type
|
, Code ret_type
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
using namespace ECode;
|
||||||
|
|
||||||
|
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
|
Code
|
||||||
result = make();
|
result = make();
|
||||||
result.Type = Code::Decl_Function;
|
result->Type = Decl_Function;
|
||||||
result.Name = string_make( g_allocator, name );
|
result->Name = string_make( g_allocator, name );
|
||||||
|
|
||||||
array_init( result.Entries, g_allocator );
|
array_init( result->Entries, g_allocator );
|
||||||
|
|
||||||
if ( specifiers )
|
if ( specifiers )
|
||||||
result.add( specifiers );
|
result->add( specifiers );
|
||||||
|
|
||||||
result.add( ret_type );
|
result->add( ret_type );
|
||||||
|
|
||||||
if ( params )
|
if ( params )
|
||||||
result.add( params );
|
result->add( params );
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Code def_parameters( s32 num, ... )
|
Code def_parameters( s32 num, ... )
|
||||||
{
|
{
|
||||||
|
using namespace ECode;
|
||||||
|
|
||||||
if (num <= 0)
|
if (num <= 0)
|
||||||
fatal("TT::make_paramters: num is %d", num);
|
fatal( "TT::make_paramters: num cannot be zero or neg" );
|
||||||
|
|
||||||
Code
|
Code
|
||||||
result = make();
|
result = make();
|
||||||
result.Type = Code::Parameters;
|
result->Type = Parameters;
|
||||||
|
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, num);
|
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);
|
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 )
|
while( num -= 2, num && num % 2 == 0 )
|
||||||
{
|
{
|
||||||
|
type = va_arg(va, Code);
|
||||||
|
|
||||||
Code
|
Code
|
||||||
param = make();
|
param = make();
|
||||||
param.Name = string_make( g_allocator, va_arg(va, char const*) );
|
param->Type = Parameters;
|
||||||
|
param->Name = string_make( g_allocator, va_arg(va, char const*) );
|
||||||
|
|
||||||
array_init( param.Entries, g_allocator );
|
array_init( param->Entries, g_allocator );
|
||||||
|
|
||||||
type = va_arg(va, Code);
|
if ( type->Type != Typename )
|
||||||
param.add( type );
|
fatal( "gen::def_parameters: type of param %d is not a Typename", num - num + 1 );
|
||||||
|
|
||||||
result.add(param);
|
param->add( type );
|
||||||
|
result->add(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
va_end(va);
|
va_end(va);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -98,50 +140,155 @@ namespace gen
|
|||||||
, Code body
|
, Code body
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
using namespace ECode;
|
||||||
|
|
||||||
|
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
|
Code
|
||||||
result = make();
|
result = make();
|
||||||
result.Name = string_make( g_allocator, name );
|
result->Name = string_make( g_allocator, name );
|
||||||
result.Type = Code::Function;
|
result->Type = Function;
|
||||||
|
|
||||||
array_init( result.Entries, g_allocator );
|
array_init( result->Entries, g_allocator );
|
||||||
|
|
||||||
if ( specifiers )
|
if ( specifiers )
|
||||||
result.add( specifiers );
|
result->add( specifiers );
|
||||||
|
|
||||||
result.add( ret_type );
|
result->add( ret_type );
|
||||||
|
|
||||||
if ( params )
|
if ( params )
|
||||||
result.add( params );
|
result->add( params );
|
||||||
|
|
||||||
result.add( body );
|
result->add( body );
|
||||||
|
|
||||||
|
body->Parent = result;
|
||||||
|
|
||||||
return 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( char const* name, Code body )
|
||||||
{
|
{
|
||||||
|
using namespace ECode;
|
||||||
}
|
|
||||||
|
|
||||||
Code def_namespace_body( u32 num, ... )
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Code def_specifiers( u32 num, ... )
|
|
||||||
{
|
|
||||||
if ( num <= 0 )
|
|
||||||
fatal("gen::make_specifier: num cannot be zero.");
|
|
||||||
|
|
||||||
Code
|
Code
|
||||||
result = make();
|
result = make();
|
||||||
result.Type = Code::Specifiers;
|
result->Type = Namespace;
|
||||||
result.Content = string_make( g_allocator, "" );
|
|
||||||
|
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_list va;
|
||||||
va_start(va, num);
|
va_start(va, num);
|
||||||
@ -152,13 +299,13 @@ namespace gen
|
|||||||
switch ( type )
|
switch ( type )
|
||||||
{
|
{
|
||||||
case Alignas:
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
const char* str = specifier_str(type);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,29 +317,125 @@ namespace gen
|
|||||||
|
|
||||||
Code def_struct( char const* name, Code body, Code parent, Code specifiers )
|
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 )
|
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 def_type( char const* name )
|
||||||
{
|
{
|
||||||
Code
|
Code
|
||||||
result = make();
|
result = make();
|
||||||
result.Name = string_make( g_allocator, name );
|
result->Name = string_make( g_allocator, name );
|
||||||
result.Type = Code::Typename;
|
result->Type = ECode::Typename;
|
||||||
|
|
||||||
return result;
|
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, ...)
|
Code untyped_fmt(char const* fmt, ...)
|
||||||
{
|
{
|
||||||
@ -206,21 +449,122 @@ namespace gen
|
|||||||
|
|
||||||
Code
|
Code
|
||||||
result = make();
|
result = make();
|
||||||
result.Name = string_make( g_allocator, fmt );
|
result->Name = string_make( g_allocator, fmt );
|
||||||
result.Type = Code::Untyped;
|
result->Type = ECode::Untyped;
|
||||||
result.Content = string_make( g_allocator, buf );
|
result->Content = string_make( g_allocator, buf );
|
||||||
|
|
||||||
return result;
|
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, "" );
|
string result = string_make( g_allocator, "" );
|
||||||
|
|
||||||
@ -229,6 +573,8 @@ namespace gen
|
|||||||
|
|
||||||
switch ( Type )
|
switch ( Type )
|
||||||
{
|
{
|
||||||
|
using namespace ECode;
|
||||||
|
|
||||||
case Invalid:
|
case Invalid:
|
||||||
fatal("Attempted to serialize invalid code! - %s", Name);
|
fatal("Attempted to serialize invalid code! - %s", Name);
|
||||||
break;
|
break;
|
||||||
@ -237,13 +583,6 @@ namespace gen
|
|||||||
result = string_append_length( result, Content, string_length(Content) );
|
result = string_append_length( result, Content, string_length(Content) );
|
||||||
break;
|
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:
|
case Decl_Function:
|
||||||
{
|
{
|
||||||
u32 index = 0;
|
u32 index = 0;
|
||||||
@ -252,9 +591,9 @@ namespace gen
|
|||||||
if ( left <= 0 )
|
if ( left <= 0 )
|
||||||
fatal( "Code::to_string - Name: %s Type: %s, expected definition", Name, Type );
|
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++;
|
index++;
|
||||||
left--;
|
left--;
|
||||||
}
|
}
|
||||||
@ -262,13 +601,13 @@ namespace gen
|
|||||||
if ( left <= 0 )
|
if ( left <= 0 )
|
||||||
fatal( "Code::to_string - Name: %s Type: %s, expected return type", Name, Type );
|
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++;
|
index++;
|
||||||
left--;
|
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++;
|
index++;
|
||||||
left--;
|
left--;
|
||||||
}
|
}
|
||||||
@ -277,22 +616,11 @@ namespace gen
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Function_Body:
|
case Decl_Type:
|
||||||
break;
|
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;\n", Entries[1]->to_string(), Name );
|
||||||
{
|
|
||||||
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;
|
break;
|
||||||
|
|
||||||
case Function:
|
case Function:
|
||||||
@ -303,9 +631,9 @@ namespace gen
|
|||||||
if ( left <= 0 )
|
if ( left <= 0 )
|
||||||
fatal( "Code::to_string - Name: %s Type: %s, expected definition", Name, Type );
|
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++;
|
index++;
|
||||||
left--;
|
left--;
|
||||||
}
|
}
|
||||||
@ -313,18 +641,45 @@ namespace gen
|
|||||||
if ( left <= 0 )
|
if ( left <= 0 )
|
||||||
fatal( "Code::to_string - Name: %s Type: %s, expected return type", Name, Type );
|
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++;
|
index++;
|
||||||
left--;
|
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++;
|
index++;
|
||||||
left--;
|
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;
|
break;
|
||||||
|
|
||||||
@ -344,9 +699,17 @@ namespace gen
|
|||||||
fatal("NOT SUPPORTED YET");
|
fatal("NOT SUPPORTED YET");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Typedef:
|
||||||
|
fatal("NOT SUPPORTED YET");
|
||||||
|
break;
|
||||||
|
|
||||||
case Typename:
|
case Typename:
|
||||||
result = string_append_fmt( result, "%s", Name );
|
result = string_append_fmt( result, "%s", Name );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Using:
|
||||||
|
fatal("NOT SUPPORTED YET");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -356,7 +719,7 @@ namespace gen
|
|||||||
|
|
||||||
void Builder::print( Code code )
|
void Builder::print( Code code )
|
||||||
{
|
{
|
||||||
Buffer = string_append_fmt( Buffer, "%s\n\n", code.to_string() );
|
Buffer = string_append_fmt( Buffer, "%s\n\n", code->to_string() );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Builder::open( char const* path )
|
bool Builder::open( char const* path )
|
||||||
|
461
project/gen.hpp
461
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
|
#pragma once
|
||||||
|
|
||||||
#include "Bloat.hpp"
|
#include "Bloat.hpp"
|
||||||
|
|
||||||
|
// Defined by default.
|
||||||
|
|
||||||
|
#define GEN_ENABLE_READONLY_AST
|
||||||
|
// #define GEN_DEFINE_DSL
|
||||||
|
|
||||||
|
#define gen_time
|
||||||
#ifdef gen_time
|
#ifdef gen_time
|
||||||
namespace gen
|
namespace gen
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
ct sw ColumnLimit = 256;
|
ct sw ColumnLimit = 256;
|
||||||
ct sw MaxLines = kilobytes(256);
|
ct sw MaxLines = kilobytes(256);
|
||||||
|
|
||||||
using LineStr = char[ColumnLimit];
|
using LineStr = char[ColumnLimit];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Specifier Type
|
||||||
enum Specifier : u8
|
enum Specifier : u8
|
||||||
{
|
{
|
||||||
Alignas, // alignas(#)
|
Alignas, // alignas(#)
|
||||||
Constexpr, // constexpr
|
Constexpr, // constexpr
|
||||||
Inline, // inline
|
Inline, // inline
|
||||||
|
|
||||||
C_Linkage, // extern "C"
|
C_Linkage, // extern "C"
|
||||||
API_Import, // Vendor specific way dynamic import symbol
|
API_Import, // Vendor specific way dynamic import symbol
|
||||||
API_Export, // Vendor specific way to dynamic export
|
API_Export, // Vendor specific way to dynamic export
|
||||||
@ -27,12 +49,16 @@ namespace gen
|
|||||||
Num_Specifiers
|
Num_Specifiers
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Specifier to string
|
||||||
|
inline
|
||||||
char const* specifier_str( Specifier specifier )
|
char const* specifier_str( Specifier specifier )
|
||||||
{
|
{
|
||||||
static char const* lookup[ Num_Specifiers ] = {
|
static
|
||||||
|
char const* lookup[ Num_Specifiers ] = {
|
||||||
"alignas",
|
"alignas",
|
||||||
"constexpr",
|
"constexpr",
|
||||||
"inline",
|
"inline",
|
||||||
|
|
||||||
"extern \"C\"",
|
"extern \"C\"",
|
||||||
#if defined(ZPL_SYSTEM_WINDOWS)
|
#if defined(ZPL_SYSTEM_WINDOWS)
|
||||||
"__declspec(dllexport)",
|
"__declspec(dllexport)",
|
||||||
@ -44,63 +70,93 @@ namespace gen
|
|||||||
"extern",
|
"extern",
|
||||||
"static",
|
"static",
|
||||||
"static",
|
"static",
|
||||||
|
"static",
|
||||||
"thread_local"
|
"thread_local"
|
||||||
};
|
};
|
||||||
|
|
||||||
return lookup[ specifier ];
|
return lookup[ specifier ];
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Code
|
// Code Type
|
||||||
|
namespace ECode
|
||||||
{
|
{
|
||||||
enum EType : u8
|
enum Type : u8
|
||||||
{
|
{
|
||||||
Invalid,
|
Invalid,
|
||||||
Unused,
|
|
||||||
|
|
||||||
Untyped, // User provided raw string.
|
Untyped, // User provided raw string.
|
||||||
|
|
||||||
Decl_Type,
|
Decl_Function, // Forward a function
|
||||||
Decl_Function,
|
Decl_Type, // Forward a type.
|
||||||
|
Function, // <type> <name>( <parameters> )
|
||||||
|
Function_Body, // { <body> }
|
||||||
|
Namespace,
|
||||||
|
Namespace_Body,
|
||||||
Parameters, // Used with functions.
|
Parameters, // Used with functions.
|
||||||
|
Specifiers,
|
||||||
Struct,
|
Struct,
|
||||||
Struct_Body,
|
Struct_Body,
|
||||||
Function,
|
|
||||||
Function_Body,
|
|
||||||
Specifiers,
|
|
||||||
Variable,
|
Variable,
|
||||||
|
Typedef,
|
||||||
Typename,
|
Typename,
|
||||||
|
Using,
|
||||||
|
|
||||||
Num_Types
|
Num_Types
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma region Member API
|
inline
|
||||||
void comment( string value )
|
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
|
forceinline
|
||||||
void add( Code other )
|
void add( AST* other )
|
||||||
{
|
{
|
||||||
array_append( Entries, other );
|
array_append( Entries, other );
|
||||||
}
|
|
||||||
|
|
||||||
forceinline
|
other->Parent = this;
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
forceinline
|
forceinline
|
||||||
bool has_entries()
|
bool has_entries()
|
||||||
{
|
{
|
||||||
static bool lookup[Num_Types] = {
|
static bool lookup[ ECode::Num_Types] = {
|
||||||
false, // Invalid
|
false, // Invalid
|
||||||
false, // Unused
|
false, // Unused
|
||||||
false, // Untyped
|
false, // Untyped
|
||||||
@ -117,105 +173,310 @@ namespace gen
|
|||||||
return lookup[Type];
|
return lookup[Type];
|
||||||
}
|
}
|
||||||
|
|
||||||
string to_string();
|
forceinline
|
||||||
|
bool is_invalid()
|
||||||
|
{
|
||||||
|
return Type != ECode::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
forceinline
|
forceinline
|
||||||
operator bool()
|
char const* type_str()
|
||||||
{
|
{
|
||||||
return Type != Invalid;
|
return ECode::str( Type );
|
||||||
}
|
}
|
||||||
|
|
||||||
operator char const*()
|
string to_string();
|
||||||
{
|
|
||||||
return 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
|
#pragma endregion Member API
|
||||||
|
|
||||||
#define Using_Code_POD \
|
#define Using_Code_POD \
|
||||||
Code::EType Type; \
|
CodeT Type; \
|
||||||
|
bool Readonly; \
|
||||||
|
AST* Parent; \
|
||||||
string Name; \
|
string Name; \
|
||||||
string Comment; \
|
string Comment; \
|
||||||
union { \
|
union { \
|
||||||
array(Code) Entries; \
|
array(AST*) Entries; \
|
||||||
string Content; \
|
string Content; \
|
||||||
};
|
};
|
||||||
|
|
||||||
Using_Code_POD;
|
Using_Code_POD;
|
||||||
};
|
};
|
||||||
|
|
||||||
using CodeType = Code::EType;
|
struct CodePOD
|
||||||
|
|
||||||
struct Code_POD
|
|
||||||
{
|
{
|
||||||
Using_Code_POD;
|
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();
|
void init();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Foward Declare a type:
|
||||||
|
<specifiers> <type> <name>;
|
||||||
|
*/
|
||||||
Code decl_type( char const* name, Code type, Code specifiers = UnusedCode );
|
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 decl_fn( char const* name
|
||||||
, Code specifiers
|
, Code specifiers
|
||||||
, Code params
|
, Code params
|
||||||
, Code ret_type
|
, 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 def_function( char const* name
|
||||||
, Code specifiers
|
, Code specifiers
|
||||||
, Code params
|
, Code params
|
||||||
, Code ret_type
|
, Code ret_type
|
||||||
, Code body
|
, 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( 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( 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 );
|
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 );
|
Code def_type( char const* name );
|
||||||
|
|
||||||
|
/*
|
||||||
|
Define a using typedef:
|
||||||
|
using <name> = <type>;
|
||||||
|
*/
|
||||||
Code def_using( char const* name, Code 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 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
|
struct Builder
|
||||||
{
|
{
|
||||||
zpl_file File;
|
zpl_file File;
|
||||||
@ -226,7 +487,67 @@ namespace gen
|
|||||||
bool open( char const* path );
|
bool open( char const* path );
|
||||||
void write();
|
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
|
#endif
|
||||||
|
499
test/Array.hpp
499
test/Array.hpp
@ -17,6 +17,7 @@
|
|||||||
Code t_uw = def_type( txt(uw) );
|
Code t_uw = def_type( txt(uw) );
|
||||||
Code t_allocator = def_type( txt(allocator) );
|
Code t_allocator = def_type( txt(allocator) );
|
||||||
|
|
||||||
|
#ifndef GEN_DEFINE_DSL
|
||||||
Code header;
|
Code header;
|
||||||
{
|
{
|
||||||
Code num = def_variable( "Num", t_uw );
|
Code num = def_variable( "Num", t_uw );
|
||||||
@ -30,20 +31,44 @@
|
|||||||
Code grow_formula;
|
Code grow_formula;
|
||||||
{
|
{
|
||||||
Code spec = def_specifiers(1, Specifier::Inline);
|
Code spec = def_specifiers(1, Specifier::Inline);
|
||||||
Code params = def_parameters(1, "value", t_uw );
|
Code params = def_parameters(1, t_uw, "value" );
|
||||||
Code body = untyped_fmt( "\t""return 2 * value * 8;" );
|
Code body = untyped_str( "return 2 * value * 8;" );
|
||||||
|
|
||||||
grow_formula = def_function( "grow_formula", spec, params, t_sw, body );
|
grow_formula = def_function( "grow_formula", spec, params, t_sw, body );
|
||||||
}
|
}
|
||||||
|
|
||||||
Code base_body = def_struct_body(2, header, grow_formula);
|
Code body = def_struct_body(2, header, grow_formula);
|
||||||
Code base = def_struct( "ArrayBase", base_body );
|
Code ArrayBase = def_struct( "ArrayBase", body );
|
||||||
return base;
|
|
||||||
|
#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 )
|
#define gen_array( Type_ ) gen__array( #Type_, sizeof(Type_), a_base )
|
||||||
Code gen__array( char const* type_str, s32 type_size, Code parent )
|
Code gen__array( char const* type_str, s32 type_size, Code parent )
|
||||||
{
|
{
|
||||||
|
#ifndef GEN_DEFINE_DSL
|
||||||
// Make these global consts to be accessed anywhere...
|
// Make these global consts to be accessed anywhere...
|
||||||
Code t_uw = def_type( txt(uw) );
|
Code t_uw = def_type( txt(uw) );
|
||||||
Code t_sw = def_type( txt(sw) );
|
Code t_sw = def_type( txt(sw) );
|
||||||
@ -51,16 +76,14 @@
|
|||||||
Code t_allocator = def_type( txt(allocator) );
|
Code t_allocator = def_type( txt(allocator) );
|
||||||
Code t_void = def_type( txt(void) );
|
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_ct = def_specifiers(1, Specifier::Constexpr );
|
||||||
Code spec_inline = def_specifiers(1, Specifier::Inline );
|
Code spec_inline = def_specifiers(1, Specifier::Inline );
|
||||||
|
|
||||||
Code type = def_type( type_str );
|
Code type = def_type( type_str );
|
||||||
Code ptr_type = def_type( string_sprintf_buf( g_allocator, "%s*", type_str ) );
|
Code ptr_type = def_type( bprintf( "%s*", type_str ) );
|
||||||
Code ref_type = def_type( string_sprintf_buf( g_allocator, "%s&", type_str ) );
|
Code ref_type = def_type( bprintf( "%s&", type_str ) );
|
||||||
|
|
||||||
string name = string_sprintf_buf( g_allocator, "Array_%s", type_str );
|
|
||||||
|
|
||||||
// From ArrayBase
|
// From ArrayBase
|
||||||
Code t_header = def_type( "Header" );
|
Code t_header = def_type( "Header" );
|
||||||
@ -69,43 +92,43 @@
|
|||||||
|
|
||||||
Code array_def;
|
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 data = def_variable( "Data", ptr_type );
|
||||||
|
|
||||||
Code init;
|
Code init;
|
||||||
{
|
{
|
||||||
Code params = def_parameters( 1, "mem_hanlder", t_allocator );
|
Code params = def_parameters( 1, t_allocator, "mem_handler" );
|
||||||
Code body = untyped_fmt( "\t""return init_reserve( mem_handler, grow_formula(0) );" );
|
Code body = untyped_str( "return init_reserve( mem_handler, grow_formula(0) );" );
|
||||||
|
|
||||||
init = def_function( "init", UnusedCode, params, t_bool, body );
|
init = def_function( "init", UnusedCode, params, t_bool, body );
|
||||||
}
|
}
|
||||||
|
|
||||||
Code init_reserve;
|
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 body;
|
||||||
{
|
{
|
||||||
Code header_value = untyped_fmt(
|
Code header_value = untyped_str(
|
||||||
"rcast( Header*, alloc( mem_handler, sizeof( Header ) + sizeof(type) + capacity ))"
|
"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(
|
Code null_check = untyped_str(
|
||||||
"\t" "if (header == nullptr)"
|
"if (header == nullptr)"
|
||||||
"\n\t\t" "return false;"
|
"\n" "return false;"
|
||||||
);
|
);
|
||||||
|
|
||||||
Code header_init = untyped_fmt(
|
Code header_init = untyped_str(
|
||||||
"\n\t" "header->Num = 0;"
|
"header->Num = 0;"
|
||||||
"\n\t" "header->Capacity = capacity;"
|
"\n""header->Capacity = capacity;"
|
||||||
"\n\t" "header->Allocator = mem_handler;"
|
"\n""header->Allocator = mem_handler;"
|
||||||
);
|
);
|
||||||
|
|
||||||
Code assign_data = untyped_fmt(
|
Code assign_data = untyped_str(
|
||||||
"\t" "Data = rcast( %s, header + 1 );", ptr_type
|
"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
|
body = def_function_body( 5
|
||||||
, header
|
, header
|
||||||
@ -121,9 +144,9 @@
|
|||||||
|
|
||||||
Code free;
|
Code free;
|
||||||
{
|
{
|
||||||
Code body = untyped_fmt(
|
Code body = untyped_str(
|
||||||
"\t" "Header& header = get_header();"
|
"Header& header = get_header();"
|
||||||
"\n\t" "::free( header.Allocator, & get_header() );"
|
"\n""::free( header.Allocator, & get_header() );"
|
||||||
);
|
);
|
||||||
|
|
||||||
free = def_function( "free", UnusedCode, UnusedCode, t_void, body );
|
free = def_function( "free", UnusedCode, UnusedCode, t_void, body );
|
||||||
@ -131,22 +154,22 @@
|
|||||||
|
|
||||||
Code append;
|
Code append;
|
||||||
{
|
{
|
||||||
Code params = def_parameters( 1, "value", type );
|
Code params = def_parameters( 1, type, "value" );
|
||||||
Code body;
|
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(
|
Code check_cap = untyped_str(
|
||||||
"\t" "if ( header.Capacity < header.Num + 1 )"
|
"if ( header.Capacity < header.Num + 1 )"
|
||||||
"\n\t\t" "if ( ! grow(0) )"
|
"\n" "if ( ! grow(0) )"
|
||||||
"\n\t\t\t" "return false;"
|
"\n" "return false;"
|
||||||
);
|
);
|
||||||
|
|
||||||
Code assign = untyped_fmt(
|
Code assign = untyped_str(
|
||||||
"\t" "Data[ header.Num ] = value;"
|
"Data[ header.Num ] = value;"
|
||||||
"\t\n" "header.Num++;"
|
"\n" "header.Num++;"
|
||||||
"\n"
|
"\n"
|
||||||
"\n\t" "return true;"
|
"\n" "return true;"
|
||||||
);
|
);
|
||||||
|
|
||||||
body = def_function_body( 3, header, check_cap, assign );
|
body = def_function_body( 3, header, check_cap, assign );
|
||||||
@ -157,9 +180,9 @@
|
|||||||
|
|
||||||
Code back;
|
Code back;
|
||||||
{
|
{
|
||||||
Code body = untyped_fmt(
|
Code body = untyped_str(
|
||||||
"\t" "Header& header = get_header();"
|
"Header& header = get_header();"
|
||||||
"\n\t" "return data[ header.Num - 1 ];"
|
"\n" "return data[ header.Num - 1 ];"
|
||||||
);
|
);
|
||||||
|
|
||||||
back = def_function( "back", UnusedCode, UnusedCode, type, body );
|
back = def_function( "back", UnusedCode, UnusedCode, type, body );
|
||||||
@ -167,26 +190,26 @@
|
|||||||
|
|
||||||
Code clear;
|
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 );
|
clear = def_function( "clear", UnusedCode, UnusedCode, t_void, body );
|
||||||
}
|
}
|
||||||
|
|
||||||
Code fill;
|
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 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(
|
Code check = untyped_str(
|
||||||
"\t" "if ( begin < 0 || end >= header.Num )"
|
"if ( begin < 0 || end >= header.Num )"
|
||||||
"\n\t\t" "fatal( \"Range out of bounds\" );"
|
"\n" "fatal( \"Range out of bounds\" );"
|
||||||
);
|
);
|
||||||
|
|
||||||
Code iter = untyped_fmt(
|
Code iter = untyped_str(
|
||||||
"\t" "for ( sw index = begin; index < end; index++ )"
|
"for ( sw index = begin; index < end; index++ )"
|
||||||
"\n\t\t" "Data[index] = vallue;"
|
"\n" "Data[index] = vallue;"
|
||||||
);
|
);
|
||||||
|
|
||||||
body = def_function_body( 3, header, check, iter );
|
body = def_function_body( 3, header, check, iter );
|
||||||
@ -197,25 +220,25 @@
|
|||||||
|
|
||||||
Code get_header;
|
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 );
|
get_header = def_function( "get_header", spec_inline, UnusedCode, ref_header, body );
|
||||||
}
|
}
|
||||||
|
|
||||||
Code grow;
|
Code grow;
|
||||||
{
|
{
|
||||||
Code param = def_parameters( 1, "min_capacity", t_uw );
|
Code param = def_parameters( 1, t_uw, "min_capacity" );
|
||||||
Code body;
|
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 new_capacity = def_variable( "new_capacity", t_uw, untyped_fmt("grow_formula( header.Capacity )") );
|
Code new_capacity = def_variable( "new_capacity", t_uw, untyped_str("grow_formula( header.Capacity )") );
|
||||||
|
|
||||||
Code check_n_set = untyped_fmt(
|
Code check_n_set = untyped_str(
|
||||||
"\t" "if ( new_capacity < min_capacity )"
|
"if ( new_capacity < min_capacity )"
|
||||||
"\n\t\t" "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 );
|
body = def_function_body( 4, header, new_capacity, check_n_set, ret );
|
||||||
}
|
}
|
||||||
@ -227,10 +250,10 @@
|
|||||||
{
|
{
|
||||||
Code body;
|
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 assertion = untyped_str( "assert( header.Num > 0 );" );
|
||||||
Code decrement = untyped_fmt( "\t" "header.Num--; " );
|
Code decrement = untyped_str( "header.Num--; " );
|
||||||
|
|
||||||
body = def_function_body( 3, header, assertion, decrement );
|
body = def_function_body( 3, header, assertion, decrement );
|
||||||
}
|
}
|
||||||
@ -240,17 +263,17 @@
|
|||||||
|
|
||||||
Code reserve;
|
Code reserve;
|
||||||
{
|
{
|
||||||
Code params = def_parameters( 1, "new_capacity", t_uw );
|
Code params = def_parameters( 1, t_uw, "new_capacity" );
|
||||||
Code body;
|
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(
|
Code check_n_set = untyped_str(
|
||||||
"\t" "if ( header.Capacity < new_capacity )"
|
"if ( header.Capacity < new_capacity )"
|
||||||
"\n\t\t" "return set_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 );
|
body = def_function_body( 3, header, check_n_set, ret );
|
||||||
}
|
}
|
||||||
@ -260,21 +283,21 @@
|
|||||||
|
|
||||||
Code resize;
|
Code resize;
|
||||||
{
|
{
|
||||||
Code param = def_parameters( 1, "new_num", t_uw );
|
Code param = def_parameters( 1, t_uw, "new_num" );
|
||||||
|
|
||||||
Code body;
|
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(
|
Code check_n_grow = untyped_str(
|
||||||
"\t" "if ( header.Capacity < new_num )"
|
"if ( header.Capacity < new_num )"
|
||||||
"\n\t\t" "if ( ! grow( new_num) )"
|
"\n" "if ( ! grow( new_num) )"
|
||||||
"\n\t\t\t" "return false;"
|
"\n" "return false;"
|
||||||
);
|
);
|
||||||
|
|
||||||
Code set_n_ret = untyped_fmt(
|
Code set_n_ret = untyped_str(
|
||||||
"\t" "header.Count = new_num;"
|
"header.Count = new_num;"
|
||||||
"\n\t" "return true;"
|
"\n""return true;"
|
||||||
);
|
);
|
||||||
|
|
||||||
body = def_function_body( 3, header, check_n_grow, set_n_ret );
|
body = def_function_body( 3, header, check_n_grow, set_n_ret );
|
||||||
@ -285,40 +308,40 @@
|
|||||||
|
|
||||||
Code set_capacity;
|
Code set_capacity;
|
||||||
{
|
{
|
||||||
Code param = def_parameters( 1, "capacity", t_uw );
|
Code param = def_parameters( 1, t_uw, "capacity" );
|
||||||
|
|
||||||
Code body;
|
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(
|
Code checks = untyped_str(
|
||||||
"\t" "if ( capacity == header.Capacity )"
|
"if ( capacity == header.Capacity )"
|
||||||
"\n\t\t" "return true;"
|
"\n" "return true;"
|
||||||
"\n"
|
|
||||||
"\n\t" "if ( capacity < header.Num )"
|
"if ( capacity < header.Num )"
|
||||||
"\n\t\t" "header.Num = capacity;"
|
"\n" "header.Num = capacity;"
|
||||||
);
|
);
|
||||||
|
|
||||||
Code size = def_variable( "size", t_uw, untyped_fmt("sizeof(Header) + sizeof(type) * capacity"));
|
Code size = def_variable( "size", t_uw, untyped_str("sizeof(Header) + sizeof(Type) * capacity"));
|
||||||
Code new_header = def_variable( "new_header", ptr_header, untyped_fmt("rcast( Header*, alloc( header.Allocator, size ));"));
|
Code new_header = def_variable( "new_header", ptr_header, untyped_str("rcast( Header*, alloc( header.Allocator, size ));"));
|
||||||
|
|
||||||
Code check_n_move = untyped_fmt(
|
Code check_n_move = untyped_str(
|
||||||
"\t""if ( new_header == nullptr )"
|
"if ( new_header == nullptr )"
|
||||||
"\n\t\t""return false;"
|
"\n" "return false;"
|
||||||
"\n"
|
"\n"
|
||||||
"\n\t""memmove( new_header, & header, sizeof(Header) + sizeof(type) * header.Num );"
|
"\n" "memmove( new_header, & header, sizeof(Header) + sizeof(Type) * header.Num );"
|
||||||
);
|
);
|
||||||
|
|
||||||
Code set_free_ret = untyped_fmt(
|
Code set_free_ret = untyped_str(
|
||||||
"\t" "new_header->Allocator = header.Allocator;"
|
"new_header->Allocator = header.Allocator;"
|
||||||
"\n\t" "new_header->Num = header.Num;"
|
"\n" "new_header->Num = header.Num;"
|
||||||
"\n\t" "new_header->Capacity = header.Capacity;"
|
"\n" "new_header->Capacity = header.Capacity;"
|
||||||
"\n"
|
"\n"
|
||||||
"\n\t" "zpl_free( header );"
|
"\n" "zpl_free( header );"
|
||||||
"\n"
|
"\n"
|
||||||
"\n\t" "*Data = new_header + 1;"
|
"\n" "*Data = new_header + 1;"
|
||||||
"\n"
|
"\n"
|
||||||
"\n\t" "return true;"
|
"\n" "return true;"
|
||||||
);
|
);
|
||||||
|
|
||||||
body = def_function_body( 6, header, checks, size, new_header, check_n_move, set_free_ret );
|
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 );
|
set_capacity = def_function( "set_capacity", UnusedCode, param, t_bool, body );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string name = bprintf( "Array_%s", type_str );
|
||||||
|
|
||||||
Code body = def_struct_body( 15
|
Code body = def_struct_body( 15
|
||||||
, using_type
|
, using_type
|
||||||
, data
|
, data
|
||||||
@ -348,6 +373,282 @@
|
|||||||
|
|
||||||
array_def = def_struct( name, body, parent );
|
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;
|
return array_def;
|
||||||
}
|
}
|
||||||
|
@ -22,21 +22,27 @@
|
|||||||
{
|
{
|
||||||
Code integral_type = def_type( type );
|
Code integral_type = def_type( type );
|
||||||
|
|
||||||
|
#ifndef GEN_DEFINE_DSL
|
||||||
string name = string_sprintf( g_allocator, (char*)sprintf_buf, ZPL_PRINTF_MAXLEN, "square", type );
|
string name = string_sprintf( g_allocator, (char*)sprintf_buf, ZPL_PRINTF_MAXLEN, "square", type );
|
||||||
|
|
||||||
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 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 );
|
fatal( "Failed to generate square function for: %s", type );
|
||||||
|
|
||||||
return result;
|
return square;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 gen_math()
|
u32 gen_math()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "Bloat.cpp"
|
#include "Bloat.cpp"
|
||||||
#include "math.hpp"
|
#include "math.hpp"
|
||||||
|
#include "Array.hpp"
|
||||||
|
|
||||||
|
|
||||||
#ifdef gen_time
|
#ifdef gen_time
|
||||||
@ -12,9 +13,11 @@ int gen_main()
|
|||||||
zpl_printf("\nPress any key after attaching to process\n");
|
zpl_printf("\nPress any key after attaching to process\n");
|
||||||
getchar();
|
getchar();
|
||||||
|
|
||||||
gen::init()
|
gen::init();
|
||||||
|
|
||||||
int result = gen_math();
|
int
|
||||||
|
result = gen_math();
|
||||||
|
result = gen_array_file();
|
||||||
|
|
||||||
Memory::cleanup();
|
Memory::cleanup();
|
||||||
return result;
|
return result;
|
||||||
|
Loading…
Reference in New Issue
Block a user