Design: Added additional keywords to specifiers, added def_friend. Fleshed out scanner.

This commit is contained in:
Edward R. Gonzalez 2023-04-07 12:31:50 -04:00
parent fcf037d50f
commit f5fe30e7cb
2 changed files with 553 additions and 259 deletions

View File

@ -71,10 +71,11 @@ namespace gen
static StringTable StringMap; static StringTable StringMap;
static TypeTable TypeMap; static TypeTable TypeMap;
static sw InitSize_CodePool = megabytes(64); static sw InitSize_CodePool = megabytes(64);
static sw InitSize_StringArena = megabytes(32); static sw InitSize_StringTable = megabytes(4);
static sw InitSize_StringTable = megabytes(4); static sw InitSize_TypeTable = megabytes(4);
static sw InitSize_TypeTable = megabytes(4);
static sw SizePer_StringArena = megabytes(32);
static allocator Allocator_CodePool = heap(); static allocator Allocator_CodePool = heap();
static allocator Allocator_StringArena = heap(); static allocator Allocator_StringArena = heap();
@ -111,33 +112,6 @@ namespace gen
Code spec_inline; Code spec_inline;
#pragma endregion CONSTANTS #pragma endregion CONSTANTS
/*
Used internally to retireve a Code object form the CodePool.
*/
static Code make_code()
{
using namespace StaticData;
# ifndef GEN_CODE_USE_SOA
ct CodePOD Invalid = { ECode::Invalid, false, nullptr, nullptr, nullptr, { nullptr } };
array_append( CodePool, Invalid );
return pcast( Code, array_back( CodePool ));
# else
array_append( CodePool::Type, ECode::Invalid );
array_append( CodePool::Readonly, false );
array_append( CodePool::Name, nullptr );
array_append( CodePool::Comment, nullptr );
array_append( CodePool::Data, { nullptr } );
Code code { array_count( CodePool::Type) - 1 };
return code;
# endif
}
# pragma region AST # pragma region AST
bool AST::add( AST* other ) bool AST::add( AST* other )
{ {
@ -356,7 +330,7 @@ namespace gen
array_init( StaticData::StringArenas, heap() ); array_init( StaticData::StringArenas, heap() );
arena string_arena; arena string_arena;
arena_init_from_allocator( & string_arena, StaticData::Allocator_StringArena, StaticData::InitSize_StringArena ); arena_init_from_allocator( & string_arena, StaticData::Allocator_StringArena, StaticData::SizePer_StringArena );
str_tbl_init( & StaticData::StringMap, StaticData::Allocator_StringTable ); str_tbl_init( & StaticData::StringMap, StaticData::Allocator_StringTable );
type_tbl_init( & StaticData::TypeMap, StaticData::Allocator_TypeTable ); type_tbl_init( & StaticData::TypeMap, StaticData::Allocator_TypeTable );
@ -427,7 +401,7 @@ namespace gen
if ( StringArenas->total_allocated + str_length > StringArenas->total_size ) if ( StringArenas->total_allocated + str_length > StringArenas->total_size )
{ {
arena new_arena; arena new_arena;
arena_init_from_allocator( & new_arena, Allocator_StringArena, InitSize_StringArena ); arena_init_from_allocator( & new_arena, Allocator_StringArena, SizePer_StringArena );
array_append( StringArenas, new_arena ); array_append( StringArenas, new_arena );
@ -438,7 +412,7 @@ namespace gen
} }
// Will either make or retrive a code string. // Will either make or retrive a code string.
string code_string( char const* cstr, s32 length ) ro_string cached_string( char const* cstr, s32 length )
{ {
s32 hash_length = length > kilobytes(1) ? kilobytes(1) : length; s32 hash_length = length > kilobytes(1) ? kilobytes(1) : length;
@ -451,11 +425,40 @@ namespace gen
return * result; return * result;
} }
* result = string_make( get_string_allocator( length ), cstr );
str_tbl_set( & StaticData::StringMap, key, * result ); str_tbl_set( & StaticData::StringMap, key, * result );
return * result; return * result;
} }
/*
Used internally to retireve a Code object form the CodePool.
*/
Code make_code()
{
using namespace StaticData;
# ifndef GEN_CODE_USE_SOA
ct CodePOD Invalid = { nullptr, nullptr, nullptr, nullptr, ECode::Invalid, EOperator::Invalid, false, {0} };
array_append( CodePool, Invalid );
return pcast( Code, array_back( CodePool ));
# else
array_append( CodePool::Type, ECode::Invalid );
array_append( CodePool::Readonly, false );
array_append( CodePool::Name, nullptr );
array_append( CodePool::Comment, nullptr );
array_append( CodePool::Data, { nullptr } );
Code code { array_count( CodePool::Type) - 1 };
return code;
# endif
}
void set_init_reserve_code_pool( sw size ) void set_init_reserve_code_pool( sw size )
{ {
StaticData::InitSize_CodePool = size; StaticData::InitSize_CodePool = size;
@ -501,6 +504,12 @@ namespace gen
{ {
using namespace ECode; using namespace ECode;
if ( length <= 0 )
{
log_failure( "gen::def_class: Invalid name length provided - %d", length );
return Code::Invalid;
}
if ( name == nullptr ) if ( name == nullptr )
{ {
log_failure( "gen::def_class: name is null"); log_failure( "gen::def_class: name is null");
@ -509,35 +518,35 @@ namespace gen
if ( parent && parent->Type != Class || parent->Type != Struct ) if ( parent && parent->Type != Class || parent->Type != Struct )
{ {
log_failure( "gen::def_class: parent provided is not type 'Class' or 'Struct' - Type: %s", parent->type_str() ); log_failure( "gen::def_class: parent provided is not type 'Class' or 'Struct' - Type: %s", parent->debug_str() );
return Code::Invalid; return Code::Invalid;
} }
if ( specifiers && specifiers->Type != Specifiers ) if ( specifiers && specifiers->Type != Specifiers )
{ {
log_failure( "gen::def_class: specifiers was not a 'Specifiers' type - Type: %s", specifiers->type_str() ); log_failure( "gen::def_class: specifiers was not a 'Specifiers' type - Type: %s", specifiers->debug_str() );
return Code::Invalid; return Code::Invalid;
} }
switch ( body->Type )
{
case Class_Body:
case Untyped:
break;
default:
log_failure("gen_def_class: body must be either of Function_Body or Untyped type.");
return Code::Invalid;
}
Code Code
result = make_code(); result = make_code();
result->Name = code_string( name, length ); result->Name = cached_string( name, length );
array_init( result->Entries, StaticData::Allocator_CodePool ); array_init( result->Entries, StaticData::Allocator_CodePool );
if ( body ) if ( body )
{ {
switch ( body->Type )
{
case Class_Body:
case Untyped:
break;
default:
log_failure("gen::def_class: body must be either of Class_Body or Untyped type - %s", body->debug_str());
return Code::Invalid;
}
result->Type = Class; result->Type = Class;
result->add_entry( body ); result->add_entry( body );
} }
@ -558,21 +567,61 @@ namespace gen
Code def_enum( s32 length, char const* name, Code type, Code body ) Code def_enum( s32 length, char const* name, Code type, Code body )
{ {
using namespace ECode;
if ( length <= 0 ) if ( length <= 0 )
{ {
log_failure( "gen_def_enum: Invalid name length provided - %d", length ); log_failure( "gen::def_enum: Invalid name length provided - %d", length );
return Code::Invalid;
} }
if ( name == nullptr ) if ( name == nullptr )
{ {
log_failure( "gen::def_class: name is null"); log_failure( "gen::def_class: name is null" );
return Code::Invalid; return Code::Invalid;
} }
if ( type && type->Type != Typename )
{
log_failure( "gen::def_enum: enum underlying type provided was not of type Typename: %s", type->debug_str() );
return Code::Invalid;
}
Code
result = make_code();
result->Name = cached_string( name, length );
if ( body )
{
switch ( body->Type )
{
case Enum_Body:
case Untyped:
break;
default:
log_failure( "gen::def_enum: body must be of Enum_Body or Untyped type %s", body->debug_str());
return Code::Invalid;
}
result->Type = Enum;
result->add_entry( body );
}
else
{
result->Type = Enum_FwdDecl;
}
if ( type )
{
result->add_entry( type );
}
result.lock();
return result;
} }
Code def_function( char const* name Code def_function( s32 length, char const* name
, Code specifiers , Code specifiers
, Code params , Code params
, Code ret_type , Code ret_type
@ -581,52 +630,76 @@ namespace gen
{ {
using namespace ECode; using namespace ECode;
if ( length <= 0 )
{
log_failure( "gen::def_function: Invalid name length provided - %d", length );
return Code::Invalid;
}
if ( name == nullptr )
{
log_failure( "gen::def_function: name is null" );
return Code::Invalid;
}
if ( specifiers && specifiers->Type != Specifiers ) if ( specifiers && specifiers->Type != Specifiers )
{ {
log_failure( "gen::def_function: specifiers was not a `Specifiers` type" ); log_failure( "gen::def_function: specifiers was not a `Specifiers` type %s", specifiers->debug_str() );
return Code::Invalid; return Code::Invalid;
} }
if ( params && params->Type != Parameters ) if ( params && params->Type != Parameters )
{ {
log_failure( "gen::def_function: params was not a `Parameters` type" ); log_failure( "gen::def_function: params was not a `Parameters` type %s", params->debug_str() );
return Code::Invalid; return Code::Invalid;
} }
if ( ret_type == nullptr || ret_type->Type != Typename ) if ( ret_type == nullptr || ret_type->Type != Typename )
{ {
log_failure( "gen::def_function: ret_type was not a Typename" ); log_failure( "gen::def_function: ret_type was not a Typename %s", ret_type->debug_str() );
return Code::Invalid; return Code::Invalid;
} }
switch ( body->Type )
{
case Function_Body:
case Untyped:
break;
default:
{
log_failure("gen::def_function: body must be either of Function_Body or Untyped type.");
return Code::Invalid;
}
}
s32 name_length = zpl_strnlen( name, MaxNameLength );
Code Code
result = make_code(); result = make_code();
result->Name = code_string( name, name_length ); result->Name = cached_string( name, length );
result->Type = Function;
array_init( result->Entries, StaticData::Allocator_CodePool ); array_init( result->Entries, StaticData::Allocator_CodePool );
result->add_entry( body ); if ( body )
{
switch ( body->Type )
{
case Function_Body:
case Untyped:
break;
default:
{
log_failure("gen::def_function: body must be either of Function_Body or Untyped type. %s", body->debug_str());
return Code::Invalid;
}
}
result->Type = Function;
result->add_entry( body );
}
else
{
result->Type = Function_FwdDecl;
}
if ( specifiers ) if ( specifiers )
result->add_entry( specifiers ); result->add_entry( specifiers );
result->add_entry( ret_type ); if ( ret_type )
{
result->add_entry( ret_type );
}
else
{
result->add_entry( type_ns(void) );
}
if ( params ) if ( params )
result->add_entry( params ); result->add_entry( params );
@ -635,6 +708,45 @@ namespace gen
return result; return result;
} }
Code def_namespace( s32 length, char const* name, Code body )
{
using namespace ECode;
if ( length <= 0 )
{
log_failure( "gen::def_namespace: Invalid name length provided - %d", length );
return Code::Invalid;
}
if ( name == nullptr )
{
log_failure( "gen::def_namespace: name is null" );
return Code::Invalid;
}
Code
result = make_code();
result->Type = Namespace;
result->Name = cached_string( name, length );
array_init( result->Entries, g_allocator );
if ( body->Type != Namespace_Body || body->Type != Untyped )
{
log_failure("gen::def_namespace: body is not of namespace or untyped type %s", body->debug_str());
return Code::Invalid;
}
result->add_entry( body );
return result;
}
Code def_operator( OperatorT Op, Code params, Code ret_type, Code specifiers, Code body )
{
}
Code def_function_body( s32 num, ... ) Code def_function_body( s32 num, ... )
{ {
using namespace ECode; using namespace ECode;
@ -763,7 +875,7 @@ namespace gen
char const* name = va_arg(va, char const*); char const* name = va_arg(va, char const*);
s32 name_length = zpl_strnlen(name, MaxNameLength); s32 name_length = zpl_strnlen(name, MaxNameLength);
result->Name = code_string( name, name_length ); result->Name = cached_string( name, name_length );
array_init( result->Entries, g_allocator ); array_init( result->Entries, g_allocator );
@ -785,7 +897,7 @@ namespace gen
Code Code
param = make_code(); param = make_code();
param->Type = Parameters; param->Type = Parameters;
param->Name = code_string(name, name_length); param->Name = cached_string(name, name_length);
array_init( param->Entries, StaticData::Allocator_CodePool ); array_init( param->Entries, StaticData::Allocator_CodePool );
@ -806,27 +918,6 @@ namespace gen
return result; return result;
} }
Code def_namespace( char const* name, Code body )
{
using namespace ECode;
Code
result = make_code();
result->Type = Namespace;
array_init( result->Entries, g_allocator );
if ( body->Type != Namespace_Body || body->Type != Untyped )
{
log_failure("gen::def_namespace: body is not of namespace or untyped type");
return Code::Invalid;
}
result->add_entry( body );
return result;
}
Code def_namespace_body( s32 num, ... ) Code def_namespace_body( s32 num, ... )
{ {
using namespace ECode; using namespace ECode;
@ -874,10 +965,19 @@ namespace gen
if ( num <= 0 ) if ( num <= 0 )
fatal("gen::make_specifier: num cannot be zero or less"); fatal("gen::make_specifier: num cannot be zero or less");
// This should be more than enough...
static u8 FixedSizedBuffer[kilobytes(1024)];
static arena str_arena;
do_once_start
arena_init_from_memory( & str_arena, FixedSizedBuffer, kilobytes(1024) );
do_once_end
Code Code
result = make_code(); result = make_code();
result->Type = ECode::Specifiers; result->Type = ECode::Specifiers;
result->Content = string_make( g_allocator, "" );
string crafted = string_make( arena_allocator( & str_arena ), "" );
va_list va; va_list va;
va_start(va, num); va_start(va, num);
@ -888,26 +988,42 @@ namespace gen
switch ( type ) switch ( type )
{ {
case ESpecifier::Alignas: case ESpecifier::Alignas:
result->Content = string_append_fmt( result->Content, "%s(%d)", ESpecifier::to_str(type), va_arg(va, u32) ); crafted = string_append_fmt( result->Content, "%s(%d)", ESpecifier::to_str(type), va_arg(va, u32) );
break; break;
default: default:
const char* str = ESpecifier::to_str(type); const char* str = ESpecifier::to_str(type);
result->Content = string_append_fmt( result->Content, "%s", str ); crafted = string_append_fmt( result->Content, "%s", str );
break; break;
} }
} }
while ( --num, num ); while ( --num, num );
va_end(va); va_end(va);
result->Content = cached_string( crafted, string_length( crafted ) );
arena_free( & str_arena );
return result; return result;
} }
Code def_struct( char const* name, Code body, Code parent, Code specifiers ) Code def_struct( u32 length, char const* name, Code body, Code parent, Code specifiers )
{ {
using namespace ECode; using namespace ECode;
if ( length <= 0 )
{
log_failure( "gen::def_function: Invalid name length provided - %d", length );
return Code::Invalid;
}
if ( name == nullptr )
{
log_failure( "gen::def_function: name is null" );
return Code::Invalid;
}
if ( specifiers && specifiers->Type != Specifiers ) if ( specifiers && specifiers->Type != Specifiers )
{ {
log_failure( "gen::def_struct: specifiers was not a `Specifiers` type" ); log_failure( "gen::def_struct: specifiers was not a `Specifiers` type" );
@ -929,7 +1045,7 @@ namespace gen
Code Code
result = make_code(); result = make_code();
result->Type = Struct; result->Type = Struct;
result->Name = string_make( g_allocator, name ); result->Name = cached_string( name, length );
array_init( result->Entries, g_allocator ); array_init( result->Entries, g_allocator );
@ -987,8 +1103,20 @@ namespace gen
return result; return result;
} }
Code def_variable( Code type, char const* name, Code value, Code specifiers ) Code def_variable( Code type, u32 length, char const* name, Code value, Code specifiers )
{ {
if ( length <= 0 )
{
log_failure( "gen::def_function: Invalid name length provided - %d", length );
return Code::Invalid;
}
if ( name == nullptr )
{
log_failure( "gen::def_function: name is null" );
return Code::Invalid;
}
if ( specifiers && specifiers->Type != ECode::Specifiers ) if ( specifiers && specifiers->Type != ECode::Specifiers )
{ {
log_failure( "gen::def_variable: specifiers was not a `Specifiers` type" ); log_failure( "gen::def_variable: specifiers was not a `Specifiers` type" );
@ -1009,7 +1137,7 @@ namespace gen
Code Code
result = make_code(); result = make_code();
result->Name = string_make( g_allocator, name ); result->Name = cached_string( name, length );
result->Type = ECode::Variable; result->Type = ECode::Variable;
array_init( result->Entries, g_allocator ); array_init( result->Entries, g_allocator );
@ -1025,21 +1153,45 @@ namespace gen
return result; return result;
} }
Code def_type( char const* name, Code specifiers ) Code def_type( u32 length, char const* name, Code specifiers )
{ {
if ( length <= 0 )
{
log_failure( "gen::def_function: Invalid name length provided - %d", length );
return Code::Invalid;
}
if ( name == nullptr )
{
log_failure( "gen::def_function: name is null" );
return Code::Invalid;
}
Code Code
result = make_code(); result = make_code();
result->Name = string_make( g_allocator, name ); result->Name = cached_string( name, length );
result->Type = ECode::Typename; result->Type = ECode::Typename;
return result; return result;
} }
Code def_using( char const* name, Code type ) Code def_using( u32 length, char const* name, Code type )
{ {
if ( length <= 0 )
{
log_failure( "gen::def_function: Invalid name length provided - %d", length );
return Code::Invalid;
}
if ( name == nullptr )
{
log_failure( "gen::def_function: name is null" );
return Code::Invalid;
}
Code Code
result = make_code(); result = make_code();
result->Name = string_make( g_allocator, name ); result->Name = cached_string( name, length );
result->Type = ECode::Using; result->Type = ECode::Using;
array_init( result->Entries, g_allocator ); array_init( result->Entries, g_allocator );
@ -1295,7 +1447,7 @@ namespace gen
Code Code
result = make_code(); result = make_code();
result->Name = string_make( g_allocator, name ); result->Name = cached_string( name, name_length );
result->Type = ECode::Function; result->Type = ECode::Function;
array_init( result->Entries, g_allocator ); array_init( result->Entries, g_allocator );

View File

@ -18,6 +18,22 @@
* Modern C++ (STL library) features * Modern C++ (STL library) features
* Modern C++ RTTI : This is kinda covered with the last point, but just wanted to emphasize. * Modern C++ RTTI : This is kinda covered with the last point, but just wanted to emphasize.
Exceptions brought in from "Modern C++":
Specifiers:
* consteval
* constinit
* explicit
* export
* noexcept
* import
* final
* module
* override
* &&
* virtual
These features are in as they are just specifiers and aren't hard to implement seralization or validation.
The AST is managed by the library and provided the user via its interface prodedures. The AST is managed by the library and provided the user via its interface prodedures.
Notes: Notes:
@ -60,6 +76,7 @@
* def_class * def_class
* def_enum * def_enum
* def_enum_class * def_enum_class
* def_friend
* def_function * def_function
* def_namespace * def_namespace
* def_operator * def_operator
@ -113,6 +130,7 @@
* parse_class * parse_class
* parse_enum * parse_enum
* parse_friend
* parse_function * parse_function
* parse_global_body * parse_global_body
* parse_namespace * parse_namespace
@ -173,6 +191,8 @@
#define GEN_DEFINE_DSL #define GEN_DEFINE_DSL
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_USE_FATAL #define GEN_USE_FATAL
#define GEN_FEATURE_EDITOR
#define GEN_FEATURE_SCANNER
#ifdef gen_time #ifdef gen_time
@ -192,37 +212,42 @@ namespace gen
namespace ECode namespace ECode
{ {
enum Type : u8 # define Define_Types \
{ Entry( Untyped ) \
Invalid, Entry( Access_Public ) \
Untyped, Entry( Access_Private ) \
Access_Public, Entry( Access_Protected ) \
Access_Private, Entry( Class ) \
Access_Protected, Entry( Class_FwdDecl ) \
Class, Entry( Class_Body ) \
Class_FwdDecl, Entry( Enum ) \
Class_Body, Entry( Enum_FwdDecl ) \
Enum, Entry( Enum_Body ) \
Enum_FwdDecl, Entry( Friend ) \
Enum_Body, Entry( Global_Body ) \
Friend, Entry( Namespace ) \
Global_Body, Entry( Namespace_Body ) \
Namespace, Entry( Parameters ) \
Namespace_Body, Entry( Function ) \
Parameters, Entry( Function_FwdDecl ) \
Function, Entry( Function_Body ) \
Function_FwdDecl, Entry( Specifiers ) \
Function_Body, Entry( Struct ) \
Specifiers, Entry( Struct_FwdDecl ) \
Struct, Entry( Struct_Body ) \
Struct_FwdDecl, Entry( Variable ) \
Struct_Body, Entry( Typedef ) \
Variable, Entry( Typename ) \
Typedef, Entry( Using )
Typename,
Using,
Num_Types enum Type : u32
{
# define Entry( Type ) Type,
Define_Types
# undef Entry
Num_Types,
Invalid
}; };
inline inline
@ -230,49 +255,72 @@ namespace gen
{ {
static static
char const* lookup[Num_Types] = { char const* lookup[Num_Types] = {
"Invalid", # define Entry( Type ) txt( Type ),
"Untyped", Define_Types
"Access_Public", # undef Entry
"Access_Private",
"Access_Protected",
"Class",
"Class_FwdDecl",
"Class_Body",
"Enum",
"Enum_FwdDecl",
"Enum_Body",
"Function",
"Function_FwdDecl",
"Function_Body",
"Global_Body",
"Namespace",
"Namespace_Body",
"Parameters",
"Specifiers",
"Struct",
"Struct_Body",
"Variable",
"Typedef",
"Typename",
"Using",
}; };
return lookup[ type ]; return lookup[ type ];
} }
# undef Define_Types
} }
using CodeT = ECode::Type; using CodeT = ECode::Type;
namespace EOperator namespace EOperator
{ {
enum Type : u8 # define Define_Operators \
{ Entry( Assign, = ) \
Add, Entry( Assign_Add, += ) \
Subtract, Entry( Assign_Subtract, -= ) \
Multiply, Entry( Assgin_Multiply, *= ) \
Divide, Entry( Assgin_Divide, /= ) \
Modulo, Entry( Assgin_Modulo, %= ) \
Entry( Assgin_BAnd, &= ) \
Entry( Assgin_BOr, &= ) \
Entry( Assign_BXOr, ^= ) \
Entry( Assign_LShift, <<= ) \
Entry( Assign_RShift, >>= ) \
Entry( Increment, ++ ) \
Entry( Decrement, -- ) \
Entry( Unary_Plus, + ) \
Entry( Unary_Minus, - ) \
Entry( Add, + ) \
Entry( Subtract, - ) \
Entry( Multiply, * ) \
Entry( Divide, / ) \
Entry( Modulo, % ) \
Entry( BNot, ~ ) \
Entry( BAnd, & ) \
Entry( BOr, | ) \
Entry( BXOr, ^ ) \
Entry( LShift, << ) \
Entry( RShift, >> ) \
Entry( LNot, ! ) \
Entry( LAnd, && ) \
Entry( LOr, || ) \
Entry( Equals, == ) \
Entry( NotEquals, != ) \
Entry( Lesser, < ) \
Entry( Greater, > ) \
Entry( LesserEqual, <= ) \
Entry( GreaterEqual, >= ) \
Entry( Subscript, [] ) \
Entry( Indirection, * ) \
Entry( AddressOf, & ) \
Entry( MemberOfPointer, -> ) \
Entry( PtrToMemOfPtr, ->* ) \
Entry( FunctionCall, () )
Num_Ops enum Type : u32
{
# define Entry( Type, Token ) Type,
Define_Operators
# undef Entry
Comma,
Num_Ops,
Invalid
}; };
inline inline
@ -280,41 +328,74 @@ namespace gen
{ {
local_persist local_persist
char const* lookup[ Num_Ops ] = { char const* lookup[ Num_Ops ] = {
"+", # define Entry( Type, Token ) txt(Token),
"-", Define_Operators
"*", # undef Entry
"/", ","
}; };
return lookup[ op ]; return lookup[ op ];
} }
# undef Define_Operators
} }
using OperatorT = EOperator::Type; using OperatorT = EOperator::Type;
namespace ESpecifier namespace ESpecifier
{ {
enum Type : u8 # if defined(ZPL_SYSTEM_WINDOWS)
# define API_Export_Code __declspec(dllexport)
# define API_Import_Code __declspec(dllimport)
# elif defined(ZPL_SYSTEM_MACOS)
# define API_Export_Code __attribute__ ((visibility ("default")))
# define API_Import_Code __attribute__ ((visibility ("default")))
# endif
# if defined(ZPL_MODULE_THREADING)
# define Thread_Local_Code thread_local
# else
# define Thread_Local_Code "NOT DEFINED"
# endif
// Entry( Explicit, explicit ) \
#define Define_Specifiers \
Entry( API_Import, API_Export_Code ) \
Entry( API_Export, API_Import_Code ) \
Entry( Attribute, "You cannot stringize an attribute this way" ) \
Entry( Alignas, alignas ) \
Entry( Const, const ) \
Entry( C_Linkage, extern "C" ) \
Entry( Consteval, consteval ) \
Entry( Constexpr, constexpr ) \
Entry( Constinit, constinit ) \
Entry( Export, export ) \
Entry( External_Linkage, extern ) \
Entry( Import, import ) \
Entry( Inline, inline ) \
Entry( Internal_Linkage, static ) \
Entry( Final, final ) \
Entry( Local_Persist, static ) \
Entry( Module, module ) \
Entry( Mutable, mutable ) \
Entry( NoExcept, noexcept ) \
Entry( Override, override ) \
Entry( Pointer, * ) \
Entry( Reference, & ) \
Entry( Register, register ) \
Entry( RValue, && ) \
Entry( Static_Member, static ) \
Entry( Thread_Local, Thread_Local_Code ) \
Entry( Virtual, virtual ) \
Entry( Volatile, volatile )
enum Type : u32
{ {
Attribute, # define Entry( Specifier, Code ) Specifier,
Alignas, Define_Specifiers
Constexpr, # undef Entry
Const,
Inline,
Pointer,
Reference,
RValue,
C_Linkage,
API_Import,
API_Export,
External_Linkage,
Internal_Linkage,
Static_Member,
Local_Persist,
Thread_Local,
Invalid,
Num_Specifiers, Num_Specifiers,
Invalid,
}; };
// Specifier to string // Specifier to string
@ -323,29 +404,9 @@ namespace gen
{ {
local_persist local_persist
char const* lookup[ Num_Specifiers ] = { char const* lookup[ Num_Specifiers ] = {
"alignas", # define Entry( Spec_, Code_ ) txt(Code_),
"constexpr", Define_Specifiers
"const", # undef Entry
"inline",
"*",
"&",
"&&",
"extern \"C\"",
# if defined(ZPL_SYSTEM_WINDOWS)
"__declspec(dllexport)",
"__declspec(dllimport)",
# elif defined(ZPL_SYSTEM_MACOS)
"__attribute__ ((visibility (\"default\")))",
"__attribute__ ((visibility (\"default\")))",
# endif
"extern",
"static",
"static",
"static",
"thread_local"
}; };
return lookup[ specifier ]; return lookup[ specifier ];
@ -394,11 +455,13 @@ namespace gen
forceinline forceinline
void add_entry( AST* other ) void add_entry( AST* other )
{ {
array_append( Entries, other ); Code to_add = other->Parent ?
other->duplicate() : other;
other->Parent = this; array_append( Entries, to_add );
to_add->Parent = this;
} }
forceinline forceinline
AST* body() AST* body()
{ {
@ -408,6 +471,8 @@ namespace gen
forceinline forceinline
bool check(); bool check();
Code duplicate();
forceinline forceinline
bool has_entries() const bool has_entries() const
{ {
@ -440,6 +505,27 @@ namespace gen
return Type != ECode::Invalid; return Type != ECode::Invalid;
} }
forceinline
char const* debug_str() const
{
char const* fmt = txt(
\nCode Debug:
\nType : %s
\nReadonly: %s
\nParent : %s
\nName : %s
\nComment : %s
);
bprintf( fmt
, type_str()
, Readonly ? "true" : "false"
, Parent ? Parent->Name : ""
, Name ? Name : ""
, Comment ? Comment : ""
);
}
forceinline forceinline
char const* type_str() const char const* type_str() const
{ {
@ -449,16 +535,18 @@ namespace gen
string to_string() const; string to_string() const;
#pragma endregion Member Procedures #pragma endregion Member Procedures
#define Using_Code_POD \ #define Using_Code_POD \
CodeT Type; \ AST* Parent; \
bool Readonly; \ ro_string Name; \
AST* Parent; \ ro_string Comment; \
string Name; \ union { \
string Comment; \ array(AST*) Entries; \
union { \ ro_string Content; \
array(AST*) Entries; \ }; \
string Content; \ CodeT Type; \
}; OperatorT Op; \
bool Readonly; \
u8 _64_Align[23];
Using_Code_POD; Using_Code_POD;
}; };
@ -468,6 +556,9 @@ namespace gen
Using_Code_POD; Using_Code_POD;
}; };
ct u32 sizeof_AST = sizeof(AST);
ct u32 sizeof_CODE = sizeof(CodePOD);
// Its intended for the AST to have equivalent size to its POD. // Its intended for the AST to have equivalent size to its POD.
// All extra functionality within the AST namespace should just be syntatic sugar. // All extra functionality within the AST namespace should just be syntatic sugar.
static_assert( sizeof(AST) == sizeof(CodePOD), "ERROR: AST IS NOT POD" ); static_assert( sizeof(AST) == sizeof(CodePOD), "ERROR: AST IS NOT POD" );
@ -594,6 +685,8 @@ namespace gen
*/ */
ZPL_TABLE_DECLARE( ZPL_EXTERN, StringTable, str_tbl_, string ); ZPL_TABLE_DECLARE( ZPL_EXTERN, StringTable, str_tbl_, string );
using ro_string = char const*;
/* /*
Type registy: Used to store Typename ASTs. Types are registered by their string literal value. Type registy: Used to store Typename ASTs. Types are registered by their string literal value.
@ -615,6 +708,19 @@ namespace gen
// And rather get rid of current code asts instead of growing the pool memory. // And rather get rid of current code asts instead of growing the pool memory.
void clear_code_pool(); void clear_code_pool();
/*
Used internally to retrive or make string allocations.
Strings are stored in a series of string arenas of fixed size (SizePer_StringArena)
*/
ro_string cached_string( char const* cstr, s32 length );
/*
This provides a fresh Code AST struct.
The gen interface use this as their method from getting a new AST object from the CodePool.
Use this if you want to make your own API for formatting the supported Code Types.
*/
Code make_code();
// Set these before calling gen's init() procedure. // Set these before calling gen's init() procedure.
void set_init_reserve_code_pool ( sw size ); void set_init_reserve_code_pool ( sw size );
@ -632,6 +738,7 @@ namespace gen
Code def_class ( s32 length, char const* name, Code parent = NoCode, Code specifiers = NoCode, Code body = NoCode ); Code def_class ( s32 length, char const* name, Code parent = NoCode, Code specifiers = NoCode, Code body = NoCode );
Code def_enum ( char const* name, Code type = NoCode, Code body = NoCode); Code def_enum ( char const* name, Code type = NoCode, Code body = NoCode);
Code def_enum ( s32 length, char const* name, Code type = NoCode, Code body = NoCode ); Code def_enum ( s32 length, char const* name, Code type = NoCode, Code body = NoCode );
Code def_friend ( Code symbol );
Code def_function ( char const* name, Code params = NoCode, Code ret_type = NoCode, Code specifiers = NoCode, Code body = NoCode ); Code def_function ( char const* name, Code params = NoCode, Code ret_type = NoCode, Code specifiers = NoCode, Code body = NoCode );
Code def_function ( s32 length, char const* name, Code params = NoCode, Code ret_type = NoCode, Code specifiers = NoCode, Code body = NoCode ); Code def_function ( s32 length, char const* name, Code params = NoCode, Code ret_type = NoCode, Code specifiers = NoCode, Code body = NoCode );
Code def_namespace ( char const* name, Code body ); Code def_namespace ( char const* name, Code body );
@ -695,6 +802,7 @@ namespace gen
# pragma region Parsing # pragma region Parsing
Code parse_class ( s32 length, char const* class_def ); Code parse_class ( s32 length, char const* class_def );
Code parse_enum ( s32 length, char const* enum_def ); Code parse_enum ( s32 length, char const* enum_def );
Code parse_friend ( s32 length, char const* friend_def );
Code parse_function ( s32 length, char const* fn_def ); Code parse_function ( s32 length, char const* fn_def );
Code parse_global_body( s32 length, char const* body_def ); Code parse_global_body( s32 length, char const* body_def );
Code parse_namespace ( s32 length, char const* namespace_def ); Code parse_namespace ( s32 length, char const* namespace_def );
@ -705,8 +813,9 @@ namespace gen
Code parse_typedef ( s32 length, char const* typedef_def ); Code parse_typedef ( s32 length, char const* typedef_def );
Code parse_using ( s32 length, char const* using_def ); Code parse_using ( s32 length, char const* using_def );
s32 parse_classes ( s32 length, char const* class_defs, Code* out_classes ); s32 parse_classes ( s32 length, char const* class_defs, Code* out_class_codes );
s32 parse_enums ( s32 length, char const* enum_defs, Code* out_enums ); s32 parse_enums ( s32 length, char const* enum_defs, Code* out_enum_codes );
s32 parse_friends ( s32 length, char const* friend_defs, Code* out_friend_codes );
s32 parse_functions ( s32 length, char const* fn_defs, Code* out_fn_codes ); s32 parse_functions ( s32 length, char const* fn_defs, Code* out_fn_codes );
s32 parse_namespaces( s32 length, char const* namespace_defs, Code* out_namespaces_codes ); s32 parse_namespaces( s32 length, char const* namespace_defs, Code* out_namespaces_codes );
s32 parse_operators ( s32 length, char const* operator_defs, Code* out_operator_codes ); s32 parse_operators ( s32 length, char const* operator_defs, Code* out_operator_codes );
@ -740,25 +849,10 @@ namespace gen
}; };
struct AddPolicy
{
// Not sure yet
};
struct ReplacePolicy
{
};
struct RemovePolicy
{
};
struct SymbolInfo struct SymbolInfo
{ {
char const* File; ro_string File;
Code Signature; Code Signature;
}; };
struct Editor struct Editor
@ -770,27 +864,75 @@ namespace gen
Remove Remove
}; };
struct RequestEntry struct SymbolData
{ {
RequestType Type;
SymbolInfo Info;
Policy Policy; Policy Policy;
SymbolInfo Info;
}; };
struct RequestEntry
{
union {
SymbolData Symbol;
string Specification;
};
RequestType Type;
};
zpl_file File; struct Receipt
{
ro_string File;
Code Found;
Code Written;
bool Result;
};
static allocator Allocator;
static void set_allocator( allocator mem_allocator );
array(zpl_file) Files;
string Buffer; string Buffer;
array(RequestEntry) Requestss ; array(RequestEntry) Requests;
void add( SymbolInfo definition, AddPolicy policy, Code to_inject ); void add ( SymbolInfo definition, Policy policy, Code to_inject );
void replace( SymbolInfo definition, Policy policy, Code to_replace);
void replace( SymbolInfo definiton, ReplacePolicy policy, Code to_replace); void remove ( SymbolInfo definition, Policy policy, Code to_remove );
void remove( SymbolInfo definition, RemovePolicy policy, Code to_remove );
# ifdef GEN_USE_REFACTOR_LIBRARY # ifdef GEN_USE_REFACTOR_LIBRARY
void refactor( char const* specification ); void refactor( char const* specification );
# endif # endif
bool process_requests( array(Receipt) out_receipts );
};
#endif
#ifdef GEN_FEATURE_SCANNER
struct Scanner
{
struct RequestEntry
{
SymbolInfo Info;
};
struct Receipt
{
ro_string File;
Code Defintion;
bool Result;
};
allocator Allocator;
static void set_allocator( allocator mem_allocator );
array(zpl_file) Files;
string Buffer;
array(RequestEntry) Requests;
void add( SymbolInfo signature, Policy policy );
bool process_requests( array(Receipt) out_receipts );
}; };
#endif #endif
#pragma endregion Gen Interface #pragma endregion Gen Interface