gencpp/project/gen.cpp

752 lines
15 KiB
C++

#include "Bloat.hpp"
#include "gen.hpp"
#define gen_time
#ifdef gen_time
namespace gen
{
namespace StaticData
{
static array(CodePOD) CodePool = nullptr;
}
/*
Used internally to retireve a Code object form the CodePool.
*/
Code make()
{
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 )
{
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
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;
}
Code decl_fn( char const* name
, Code specifiers
, Code params
, 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
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( ret_type );
if ( params )
result->add( params );
return result;
}
Code def_parameters( s32 num, ... )
{
using namespace ECode;
if (num <= 0)
fatal( "TT::make_paramters: num cannot be zero or neg" );
Code
result = make();
result->Type = Parameters;
va_list va;
va_start(va, num);
result->Name = string_make( g_allocator, va_arg(va, char const*) );
array_init( result->Entries, g_allocator );
Code type = va_arg(va, Code);
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 )
{
type = va_arg(va, Code);
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;
}
Code def_function( char const* name
, Code specifiers
, Code params
, Code ret_type
, 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
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( ret_type );
if ( params )
result->add( params );
result->add( body );
body->Parent = result;
return result;
}
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 )
{
using namespace ECode;
Code
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);
do
{
Specifier type = (Specifier)va_arg(va, int);
switch ( type )
{
case Alignas:
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 );
break;
}
}
while ( --num, num );
va_end(va);
return result;
}
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( 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 = 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, ...)
{
local_persist thread_local
char buf[ZPL_PRINTF_MAXLEN] = { 0 };
va_list va;
va_start(va, fmt);
zpl_snprintf_va(buf, ZPL_PRINTF_MAXLEN, fmt, va);
va_end(va);
Code
result = make();
result->Name = string_make( g_allocator, fmt );
result->Type = ECode::Untyped;
result->Content = string_make( g_allocator, buf );
return result;
}
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 AST::to_string()
{
string result = string_make( g_allocator, "" );
if ( Comment )
result = string_append_fmt( result, "// %s\n", Comment );
switch ( Type )
{
using namespace ECode;
case Invalid:
fatal("Attempted to serialize invalid code! - %s", Name);
break;
case Untyped:
result = string_append_length( result, Content, string_length(Content) );
break;
case Decl_Function:
{
u32 index = 0;
u32 left = array_count( Entries );
if ( left <= 0 )
fatal( "Code::to_string - Name: %s Type: %s, expected definition", Name, Type );
if ( Entries[index]->Type == Specifiers )
{
result = string_append_fmt( result, "%s\n", Entries[index]->to_string() );
index++;
left--;
}
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 );
index++;
left--;
if ( left && Entries[index]->Type == Parameters )
{
result = string_append_fmt( result, "%s", Entries[index]->to_string() );
index++;
left--;
}
result = string_appendc( result, ");\n" );
}
break;
case Decl_Type:
if ( Entries[0]->Type == Specifiers )
result = string_append_fmt( result, "%s\n", Entries[0]->to_string());
result = string_append_fmt( result, "%s %s;\n", Entries[1]->to_string(), Name );
break;
case Function:
{
u32 index = 0;
u32 left = array_count( Entries );
if ( left <= 0 )
fatal( "Code::to_string - Name: %s Type: %s, expected definition", Name, Type );
if ( Entries[index]->Type == Specifiers )
{
result = string_append_fmt( result, "%s", Entries[index]->to_string() );
index++;
left--;
}
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 );
index++;
left--;
if ( left && Entries[index]->Type == Parameters )
{
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() );
}
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;
case Specifiers:
result = string_append_fmt( result, "%s", Content );
break;
case Struct:
fatal("NOT SUPPORTED YET");
break;
case Struct_Body:
fatal("NOT SUPPORTED YET");
break;
case Variable:
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;
}
void Builder::print( Code code )
{
Buffer = string_append_fmt( Buffer, "%s\n\n", code->to_string() );
}
bool Builder::open( char const* path )
{
file_error error = file_open_mode( & File, ZPL_FILE_MODE_WRITE, path );
if ( error != ZPL_FILE_ERROR_NONE )
{
fatal( "gen::File::open - Could not open file: %s", path);
return false;
}
Buffer = string_make( g_allocator, "" );
return true;
}
void Builder::write()
{
bool result = file_write( & File, Buffer, string_length(Buffer) );
if ( result == false )
fatal("gen::File::write - Failed to write to file: %s", file_name( & File ) );
// file_seek( & File, 0 );
file_close( & File );
}
}
#endif