diff --git a/.vscode/settings.json b/.vscode/settings.json index 399b819..54ab575 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,7 +8,13 @@ "xtr1common": "cpp", "xutility": "cpp", "initializer_list": "cpp", - "table.h": "c" + "table.h": "c", + "iterator": "cpp", + "memory": "cpp", + "exception": "cpp", + "optional": "cpp", + "tuple": "cpp", + "xmemory": "cpp" }, "C_Cpp.intelliSenseEngineFallback": "disabled" } \ No newline at end of file diff --git a/project/Bloat.cpp b/project/Bloat.cpp index e7df7ed..e464f48 100644 --- a/project/Bloat.cpp +++ b/project/Bloat.cpp @@ -109,9 +109,9 @@ sw token_fmt_va( char* buf, uw buf_size, char const* fmt, s32 num_tokens, va_lis char const* token = fmt; - s32 key = crc32( token, tok_len ); + u32 key = crc32( token, tok_len ); TokEntry value = * tokmap_get( & tok_map, key ); - s32 left = value.Length; + sw left = value.Length; while ( left-- ) { diff --git a/project/Bloat.hpp b/project/Bloat.hpp index 6d7b731..b778837 100644 --- a/project/Bloat.hpp +++ b/project/Bloat.hpp @@ -61,9 +61,11 @@ using zpl::alloc; using zpl::arena_allocator; using zpl::arena_init_from_memory; using zpl::arena_free; +using zpl::bprintf; using zpl::char_is_alpha; using zpl::char_is_space; using zpl::crc32; +using zpl::free_all; using zpl::memset; using zpl::pool_allocator; using zpl::pool_init; diff --git a/project/gen.cpp b/project/gen.cpp index 5adb665..a0c9532 100644 --- a/project/gen.cpp +++ b/project/gen.cpp @@ -1,7 +1,8 @@ +// ReSharper disable CppClangTidyClangDiagnosticSwitchEnum #include "Bloat.hpp" #include "gen.hpp" -#ifdef gentime +#ifdef gen_time namespace gen { ZPL_TABLE_DEFINE( StringTable, str_tbl_, String ); @@ -61,7 +62,7 @@ namespace gen #pragma endregion Constants # pragma region AST - const Code Code::Invalid; + Code Code::Invalid; bool AST::add( AST* other ) { @@ -87,7 +88,7 @@ namespace gen case Class: break; - case Class_FwdDecl: + case Class_Fwd: break; case Class_Body: @@ -96,7 +97,7 @@ namespace gen case Enum: break; - case Enum_FwdDecl: + case Enum_Fwd: break; case Enum_Body: @@ -105,7 +106,7 @@ namespace gen case Enum_Class: break; - case Enum_Class_FwdDecl: + case Enum_Class_Fwd: break; case Friend: @@ -117,7 +118,7 @@ namespace gen case Function_Body: break; - case Function_FwdDecl: + case Function_Fwd: break; case Global_Body: @@ -132,7 +133,7 @@ namespace gen case Operator: break; - case Operator_FwdDecl: + case Operator_Fwd: break; case Parameters: @@ -190,7 +191,7 @@ namespace gen case Enum: break; - case Enum_FwdDecl: + case Enum_Fwd: break; case Enum_Body: @@ -205,7 +206,7 @@ namespace gen case Function_Body: break; - case Function_FwdDecl: + case Function_Fwd: break; case Global_Body: @@ -220,7 +221,7 @@ namespace gen case Operator: break; - case Operator_FwdDecl: + case Operator_Fwd: break; case Parameters: @@ -256,8 +257,7 @@ namespace gen using namespace ECode; Code - result = make_code(); - + result = make_code(); result->Parent = Parent; result->Name = Name; result->Comment = Comment; @@ -275,13 +275,13 @@ namespace gen case Access_Public: case Access_Protected: case Access_Private: - case Class_FwdDecl: - case Enum_FwdDecl: - case Function_FwdDecl: + case Class_Fwd: + case Enum_Fwd: + case Function_Fwd: case Specifiers: // Can just be the same, as its a cached string. result->Content = Content; - return; + return result; // The main purpose of this is to make sure entires in the AST are unique, // So that we can assign the new parent without corrupting the existing AST. @@ -297,25 +297,23 @@ namespace gen case Function: case Function_Body: case Struct: - case Struct_FwdDecl: + case Struct_Fwd: case Struct_Body: case Variable: case Typedef: case Typename: case Using: - result->Entries = make_code_entries(); - s32 index = 0; - s32 left = array_count( result->Entries ); + s32 index = 0; + s32 left = num_entries(); while ( left -- ) { // This will naturally duplicate the entire chain duplicate all of the ast nodes. // It may not be the most optimal way for memory reasons, however figuring out the heuristic // For when it should reparent all nodes or not is not within the simple scope of this library. result->add_entry( Entries[index]->duplicate() ); - result->Entries[index]->Parent = this; index++; } - return; + return result; } } @@ -347,7 +345,7 @@ namespace gen case Class: break; - case Class_FwdDecl: + case Class_Fwd: break; case Class_Body: @@ -356,7 +354,7 @@ namespace gen case Enum: break; - case Enum_FwdDecl: + case Enum_Fwd: break; case Enum_Body: @@ -365,7 +363,7 @@ namespace gen case Enum_Class: break; - case Enum_Class_FwdDecl: + case Enum_Class_Fwd: break; case Friend: @@ -404,7 +402,7 @@ namespace gen } break; - case Function_FwdDecl: + case Function_Fwd: { u32 index = 0; u32 left = array_count( Entries ); @@ -455,7 +453,7 @@ namespace gen case Operator: break; - case Operator_FwdDecl: + case Operator_Fwd: break; case Parameters: @@ -481,7 +479,7 @@ namespace gen log_failure("NOT SUPPORTED YET"); break; - case Struct_FwdDecl: + case Struct_Fwd: break; case Struct_Body: @@ -564,19 +562,20 @@ namespace gen fatal( "gen::init: Failed to initialize the TypeMap" ); } - Code& - InvalidCode_write = ccast( Code, Code::Invalid ); - InvalidCode_write = make_code(); + Code::Invalid = make_code(); + Code::Invalid.lock(); # ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS Code& t_bool_write = ccast( Code, t_void ); - t_bool_write = def_type( txt(void) ); + t_bool_write = def_type( name(void) ); # define def_constant_code_type( Type_ ) \ Code& \ - t_##Type_ = def_type( txt(Type_) ); \ - t_##Type_.lock() + t_##Type_ = def_type( name(Type_) ); \ + t_##Type_->Readonly = true; + + def_constant_code_type( int ); def_constant_code_type( bool ); def_constant_code_type( char ); @@ -614,31 +613,33 @@ namespace gen # undef def_constant_spec } - void clear_code_pools() + void clear_code_memory() { using namespace StaticData; // Clear the code pools { s32 index = 0; - s32 left = 0; - while (( left-- )) + s32 left = array_count( CodePools ); + while ( left-- ) { Pool* code_pool = & CodePools[index]; pool_free( code_pool ); + index++; } array_clear( CodePools ); } - // Clear the code entries pools + // Clear the code entries arenas { s32 index = 0; - s32 left = 0; - while (( left-- )) + s32 left = array_count( CodeEntriesArenas ); + while ( left-- ) { Arena* code_entries_arena = & CodeEntriesArenas[index]; arena_free( code_entries_arena ); + index++; } array_clear( CodeEntriesArenas ); @@ -690,7 +691,18 @@ namespace gen { using namespace StaticData; - ct CodePOD Invalid = { nullptr, nullptr, nullptr, nullptr, ECode::Invalid, EOperator::Invalid, false, {0} }; + ct CodePOD Invalid { + /* Union */ {nullptr}, + /* Parent */ nullptr, + /* Name */ nullptr, + /* Comment */ nullptr, + /* Type */ ECode::Invalid, + /* Op */ EOperator::Invalid, + /* Readonly */ false, + /* DynamicEntries */ false, + /* StaticIndex */ 0, + /* _Align_Pad */ {0} + }; AllocatorInfo allocator = { nullptr, nullptr }; @@ -718,7 +730,15 @@ namespace gen Code result { rcast( AST*, alloc( allocator, sizeof(AST) )) }; - * result = pcast( AST, Invalid); + result->Content = nullptr; + result->Parent = nullptr; + result->Name = nullptr; + result->Comment = nullptr; + result->Type = ECode::Invalid; + result->Op = EOperator::Invalid; + result->Readonly = false; + result->DynamicEntries = false; + result->StaticIndex = 0; return result; } @@ -732,7 +752,7 @@ namespace gen s32 left = array_count( CodeEntriesArenas ); do { - if ( arena_size_remaining(CodeEntriesArenas, ZPL_DEFAULT_MEMORY_ALIGNMENT) > ZPL_ARRAY_GROW_FORMULA(0) ) + if ( arena_size_remaining(CodeEntriesArenas, ZPL_DEFAULT_MEMORY_ALIGNMENT) >= InitSize_CodeEntiresArray ) allocator = arena_allocator( & CodeEntriesArenas[left] ); } while( left--, left ); @@ -766,21 +786,21 @@ namespace gen case Access_Protected: case Access_Private: case Class_Body: - case Class_FwdDecl: - case Enum_FwdDecl: + case Class_Fwd: + case Enum_Fwd: case Enum_Body: - case Enum_Class_FwdDecl: + case Enum_Class_Fwd: case Friend: case Function: - case Function_FwdDecl: + case Function_Fwd: case Global_Body: case Namespace: case Namespace_Body: case Operator: - case Operator_FwdDecl: + case Operator_Fwd: case Parameters: case Specifiers: - case Struct_FwdDecl: + case Struct_Fwd: case Struct_Body: case Typename: return false; @@ -834,7 +854,7 @@ namespace gen # define null_check( Context_, Code_ ) \ if ( ! Code_ ) \ { \ - log_failure( "gen::%s: %s provided is null!", txt(Context_), txt(Code_) ); \ + log_failure( "gen::%s: %s provided is null", txt(Context_), txt(Code_) ); \ return Code::Invalid; \ } @@ -842,13 +862,13 @@ namespace gen { \ if ( ! Code_ ) \ { \ - log_failure( "gen::%s: %s provided is null!", txt(Context_) ); \ + log_failure( "gen::%s: %s provided is null", txt(Context_) ); \ return Code::Invalid; \ } \ \ if ( Code_->is_invalid() ) \ { \ - log_failure("gen::%s: %s provided is invalid!", txt(Context_), txt(Code_) ); \ + log_failure("gen::%s: %s provided is invalid", txt(Context_), txt(Code_) ); \ return Code::Invalid; \ } \ } @@ -894,13 +914,12 @@ namespace gen return Code::Invalid; } - result->Type = Class; - result->Entries = make_code_entries(); + result->Type = Class; result->add_entry( body ); } else { - result->Type = Class_FwdDecl; + result->Type = Class_Fwd; } if ( parent ) @@ -929,6 +948,11 @@ namespace gen result = make_code(); result->Name = get_cached_string( name, length ); + if ( type ) + { + result->add_entry( type ); + } + if ( body ) { switch ( body->Type ) @@ -945,18 +969,12 @@ namespace gen result->Type = specifier == EnumClass ? Enum_Class : Enum; - result->Entries = make_code_entries(); result->add_entry( body ); } else if ( specifier == EnumClass ) { result->Type = specifier == EnumClass ? - Enum_Class_FwdDecl : Enum_FwdDecl; - } - - if ( type ) - { - result->add_entry( type ); + Enum_Class_Fwd : Enum_Fwd; } result.lock(); @@ -989,10 +1007,10 @@ namespace gen switch ( declaration->Type ) { - case Class_FwdDecl: - case Function_FwdDecl: - case Operator_FwdDecl: - case Struct_FwdDecl: + case Class_Fwd: + case Function_Fwd: + case Operator_Fwd: + case Struct_Fwd: break; default: @@ -1002,9 +1020,8 @@ namespace gen } Code - result = make_code(); - result->Type = Friend; - result->Entries = make_code_entries(); + result = make_code(); + result->Type = Friend; result->add_entry( declaration ); @@ -1042,9 +1059,8 @@ namespace gen } Code - result = make_code(); - result->Name = get_cached_string( name, length ); - result->Entries = make_code_entries(); + result = make_code(); + result->Name = get_cached_string( name, length ); if ( body ) { @@ -1066,7 +1082,7 @@ namespace gen } else { - result->Type = Function_FwdDecl; + result->Type = Function_Fwd; } if ( specifiers ) @@ -1109,10 +1125,11 @@ namespace gen result->add_entry( body ); + result.lock(); return result; } - Code def_operator( OperatorT op, Code params, Code ret_type, Code specifiers, Code body ) + Code def_operator( OperatorT op, Code params_code, Code ret_type, Code specifiers, Code body ) { using namespace EOperator; @@ -1122,31 +1139,358 @@ namespace gen return Code::Invalid; } + if ( body && body->Type != ECode::Function_Body ) + { + log_failure( "gen::def_operator: Body was provided but its not of function body type - %s", body->debug_str() ); + return Code::Invalid; + } + +# pragma region Helper Macros +# define check_params() \ + if ( ! params_code ) \ + { \ + log_failure("gen::def_operator: params is null and operator%s requires it", to_str(op)); \ + return Code::Invalid; \ + } \ + if ( params_code->Type != ECode::Parameters ) \ + { \ + log_failure("gen::def_operator: params is not of Parameters type - %s", params_code->debug_str()); \ + return Code::Invalid; \ + } + +# define check_ret_type() \ + if ( ! ret_type ) \ + { \ + log_failure("gen::def_operator: ret_type is null but is required by operator%s", to_str(op)); \ + } \ + if ( ret_type->Type != ECode::Typename ) \ + { \ + log_failure("gen::def_operator: ret_type is not of typename type - %s", ret_type->debug_str()); \ + return Code::Invalid; \ + } + +# define check_param_eq_ret() \ + if ( ! is_member_symbol && params_code->param_type() != ret_type ) \ + { \ + log_failure("gen_def_operator: operator%s requires first parameter to equal return type\n" \ + "param types: %s\n" \ + "return type: %s", \ + to_str(op), \ + params_code->debug_str(), \ + ret_type->debug_str() \ + ); \ + return Code::Invalid; \ + } +# pragma endregion Helper Macros + + bool is_member_symbol = false; + + check_ret_type(); + switch ( op ) { +# define specs( ... ) macro_num_args( __VA_ARGS__ ), __VA_ARGS__ case Assign: + check_params(); + // check_ret_type(); + + if ( params_code->param_count() > 1 ) + { + log_failure("gen::def_operator: " + "operator%s does not support non-member definition (more than one parameter provided) - %s", + to_str(op), + params_code->debug_str() + ); + return Code::Invalid; + } + + is_member_symbol = true; + break; + case Assign_Add: case Assign_Subtract: case Assgin_Multiply: case Assgin_Divide: case Assgin_Modulo: + case Assgin_BAnd: + case Assgin_BOr: + case Assign_BXOr: + case Assign_LShift: + case Assign_RShift: + check_params(); + // check_ret_type(); + if ( params_code->param_count() == 1 ) + is_member_symbol = true; + + else + check_param_eq_ret(); + + if (params_code->param_count() > 2 ) + { + log_failure("gen::def_operator: operator%s may not be defined with more than two parametes - param count; %d\n%s" + , to_str(op) + , params_code->param_count() + , params_code->debug_str() + ); + return Code::Invalid; + } break; + + case Increment: + case Decrement: + // check_ret_type(); + + // If its not set, it just means its a prefix member op. + if ( params_code ) + { + if ( params_code->Type != ECode::Parameters ) + { + log_failure("gen::def_operator: operator%s params code provided is not of Parameters type - %s" + , to_str(op) + , params_code->debug_str() + ); + return Code::Invalid; + } + + switch ( params_code->param_count() ) + { + case 1: + if ( params_code->param_type() == type_ns(int) ) + is_member_symbol = true; + + else + check_param_eq_ret(); + break; + + case 2: + check_param_eq_ret(); + + if ( params_code->get_param(1) != type_ns(int) ) + { + log_failure("gen::def_operator: " + "operator%s requires second parameter of non-member definition to be int for post-decrement", + to_str(op) + ); + return Code::Invalid; + } + break; + + default: + log_failure("gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 0-2" + , to_str(op) + , params_code->param_count() + ); + return Code::Invalid; + } + } + break; + + case Unary_Plus: + case Unary_Minus: + case BNot: + // check_ret_type(); + + if ( ! params_code ) + is_member_symbol = true; + + else + { + if ( params_code->Type != ECode::Parameters ) + { + log_failure("gen::def_operator: params is not of Parameters type - %s", params_code->debug_str()); + return Code::Invalid; + } + + if ( params_code->param_type() == ret_type ) + { + log_failure("gen::def_operator: " + "operator%s is non-member symbol yet first paramter does not equal return type\n" + "param type: %s\n" + "return type: %s\n" + , params_code->debug_str() + , ret_type->debug_str() + ); + return Code::Invalid; + } + + if ( params_code->param_count() > 1 ) + { + log_failure("gen::def_operator: operator%s may not have more than one parameter - param count: %d" + , to_str(op) + , params_code->param_count() + ); + return Code::Invalid; + } + } + break; + + case Add: + case Subtract: + case Multiply: + case Divide: + case Modulo: + case BAnd: + case BOr: + case BXOr: + case LShift: + case RShift: + // check_ret_type(); + check_params(); + + switch ( params_code->param_count() ) + { + case 1: + is_member_symbol = true; + break; + + case 2: + if ( params_code->param_type() != ret_type ) + { + log_failure("gen::def_operator: " + "operator%s is non-member symbol yet first paramter does not equal return type\n" + "param type: %s\n" + "return type: %s\n" + , params_code->debug_str() + , ret_type->debug_str() + ); + return Code::Invalid; + } + break; + + default: + log_failure("gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 0-2" + , to_str(op) + , params_code->param_count() + ); + return Code::Invalid; + } + break; + + case LNot: + if ( ! params_code ) + is_member_symbol = true; + + else + { + if ( params_code->Type != ECode::Parameters ) + { + log_failure("gen::def_operator: params is not of Parameters type - %s", params_code->debug_str()); + return Code::Invalid; + } + + if ( params_code->param_count() != 1 ) + { + log_failure("gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 0-1" + , to_str(op) + , params_code->param_count() + ); + return Code::Invalid; + } + } + + if ( ret_type != type_ns(bool) ) + { + log_failure("gen::def_operator: operator%s return type must be of type bool - %s" + , to_str(op) + , ret_type->debug_str() + ); + return Code::Invalid; + } + break; + + case LAnd: + case LOr: + case Equals: + case NotEquals: + case Lesser: + case Greater: + case LesserEqual: + case GreaterEqual: + check_params(); + + switch ( params_code->param_count() ) + { + case 1: + is_member_symbol = true; + break; + + case 2: + break; + + default: + log_failure("gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 1-2" + , to_str(op) + , params_code->param_count() + ); + return Code::Invalid; + } + break; + + case Indirection: + case AddressOf: + case MemberOfPointer: + if ( params_code && params_code->param_count() > 1) + { + log_failure("gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 0-1" + , to_str(op) + , params_code->param_count() + ); + return Code::Invalid; + } + else + { + is_member_symbol = true; + } + break; + + case PtrToMemOfPtr: + if ( params_code ) + { + log_failure("gen::def_operator: operator%s expects no paramters - %s", to_str(op), params_code->debug_str()); + return Code::Invalid; + } + break; + + case Subscript: + case FunctionCall: + case Comma: + check_params(); + break; +# undef specs } +# undef check_params +# undef check_ret_type +# undef check_param_eq_ret + + char const* name = bprintf( "operator%s", to_str(op) ); + Code - result = make_code(); - result->Type = ECode::Operator; + result = make_code(); + result->Name = get_cached_string( name, strnlen(name, MaxNameLength) ); if ( body ) { + result->Type = is_member_symbol ? + ECode::Operator : ECode::Operator_Member; + result->add_entry( body ); } else { - + result->Type = is_member_symbol ? + ECode::Operator_Fwd : ECode::Operator_Member_Fwd; } + if (params_code) + result->add_entry( params_code ); + + result->add_entry( ret_type ); + + if ( specifiers ) + result->add_entry( specifiers ); + result.lock(); return result; } @@ -1212,7 +1556,7 @@ namespace gen } else { - result->Type = Struct_FwdDecl; + result->Type = Struct_Fwd; } if ( parent ) @@ -1221,6 +1565,7 @@ namespace gen if ( specifiers ) result->add_entry( specifiers ); + result.lock(); return result; } @@ -1261,6 +1606,7 @@ namespace gen if ( value ) result->add_entry( value ); + result.lock(); return result; } @@ -1301,8 +1647,7 @@ namespace gen switch ( specifier ) { case UsingRegular: - result->Entries = make_code_entries(); - result->Type = ECode::Using; + result->Type = ECode::Using; result->add_entry( type ); break; @@ -1345,25 +1690,18 @@ namespace gen case Global_Body: case Namespace: case Namespace_Body: + case Operator: + case Operator_Fwd: case Parameters: case Specifiers: case Struct_Body: case Typename: case Using_Namespace: - { - log_failure("gen::def_class_body: Entry type is not allowed: %s", ECode::str(entry->Type) ); + log_failure("gen::def_class_body: Entry type is not allowed: %s", entry->debug_str() ); return Code::Invalid; - } - case Operator: - // If an operator is getting added, we need to verify - // the definition conforms to the format required for member symbols. - if ( ! operator_member_symbol_check( entry ) ) - { - log_failure( "gen::def_class_body: Operator entry was not a valid member symbol."); - return Code::Invalid; - } - break; + default: + break; } result->add_entry( entry ); @@ -1380,6 +1718,11 @@ namespace gen not_implemented( def_enum_body ); } + Code def_enum_body( s32 num, Code* codes ) + { + not_implemented( def_enum_body ); + } + Code def_function_body( s32 num, ... ) { using namespace ECode; @@ -1390,9 +1733,9 @@ namespace gen return Code::Invalid; } - Code result = make_code(); - - array_init( result->Entries, g_allocator ); + Code + result = make_code(); + result->Type = Function_Body; va_list va; va_start(va, num); @@ -1415,11 +1758,14 @@ namespace gen case Enum_Body: case Friend: case Function_Body: - case Function_FwdDecl: + case Function_Fwd: case Global_Body: case Namespace: case Namespace_Body: case Operator: + case Operator_Fwd: + case Operator_Member: + case Operator_Member_Fwd: case Parameters: case Specifiers: case Struct_Body: @@ -1438,6 +1784,7 @@ namespace gen while ( num--, num > 0 ); va_end(va); + result.lock(); return result; } @@ -1457,9 +1804,10 @@ namespace gen return Code::Invalid; } - Code result = make_code(); + Code + result = make_code(); + result->Type = Function_Body; - array_init( result->Entries, g_allocator ); do { Code entry = *codes; @@ -1479,11 +1827,14 @@ namespace gen case Enum_Body: case Friend: case Function_Body: - case Function_FwdDecl: + case Function_Fwd: case Global_Body: case Namespace: case Namespace_Body: case Operator: + case Operator_Fwd: + case Operator_Member: + case Operator_Member_Fwd: case Parameters: case Specifiers: case Struct_Body: @@ -1501,6 +1852,7 @@ namespace gen } while ( num--, num > 0 ); + result.lock(); return result; } @@ -1514,9 +1866,9 @@ namespace gen return Code::Invalid; } - Code result = make_code(); - - array_init( result->Entries, g_allocator ); + Code + result = make_code(); + result->Type = Global_Body; va_list va; va_start(va, num); @@ -1542,6 +1894,8 @@ namespace gen case Function_Body: case Global_Body: case Namespace_Body: + case Operator_Member: + case Operator_Member_Fwd: case Parameters: case Specifiers: case Struct_Body: @@ -1560,6 +1914,72 @@ namespace gen while ( num--, num > 0 ); va_end(va); + result.lock(); + return result; + } + + Code def_global_body( s32 num, Code* codes ) + { + using namespace ECode; + + if ( num <= 0 ) + { + log_failure("gen::def_global_body: num cannot zero or neg"); + return Code::Invalid; + } + + if ( codes == nullptr ) + { + log_failure("gen::def_global_body: Provided a null array of codes!"); + return Code::Invalid; + } + + Code + result = make_code(); + result->Type = Global_Body; + + do + { + Code entry = *codes; + + if ( ! entry ) + { + log_failure("gen::def_global_body: Provided an invalid entry!"); + return Code::Invalid; + } + + switch ( entry->Type ) + { + case Access_Public: + case Access_Protected: + case Access_Private: + case Class_Body: + case Enum_Body: + case Execution: + case Friend: + case Function_Body: + case Global_Body: + case Namespace_Body: + case Operator_Member: + case Operator_Member_Fwd: + case Parameters: + case Specifiers: + case Struct_Body: + case Typename: + { + log_failure("gen::def_global_body: Entry type is not allowed: %s", entry->type_str() ); + return Code::Invalid; + } + + default: + break; + } + + result->add_entry( entry ); + } + while ( num--, num > 0 ); + + result.lock(); return result; } @@ -1569,7 +1989,7 @@ namespace gen if ( num <= 0 ) { - log_failure("gen::make_specifier: num cannot be zero or less"); + log_failure("gen::def_namesapce_body: num cannot be zero or less"); return Code::Invalid; } @@ -1585,12 +2005,23 @@ namespace gen switch ( entry->Type ) { + case Access_Public: + case Access_Protected: + case Access_Private: + case Class_Body: + case Enum_Body: + case Execution: + case Friend: + case Function_Body: + case Global_Body: case Namespace_Body: + case Operator_Member: + case Operator_Member_Fwd: case Parameters: case Specifiers: case Struct_Body: case Typename: - log_failure("gen::def_function_body: Entry type is not allowed: %s", ECode::str(entry->Type) ); + log_failure("gen::def_namesapce_body: Entry type is not allowed: %s", ECode::to_str(entry->Type) ); return Code::Invalid; default: @@ -1602,6 +2033,72 @@ namespace gen while ( num--, num > 0 ); va_end(va); + result.lock(); + return result; + } + + Code def_namespace_body( s32 num, Code* codes ) + { + using namespace ECode; + + if ( num <= 0 ) + { + log_failure("gen::def_namesapce_body: num cannot zero or neg"); + return Code::Invalid; + } + + if ( codes == nullptr ) + { + log_failure("gen::def_namesapce_body: Provided a null array of codes!"); + return Code::Invalid; + } + + Code + result = make_code(); + result->Type = Global_Body; + + do + { + Code entry = *codes; + + if ( ! entry ) + { + log_failure("gen::def_namesapce_body: Provided an invalid entry!"); + return Code::Invalid; + } + + switch ( entry->Type ) + { + case Access_Public: + case Access_Protected: + case Access_Private: + case Class_Body: + case Enum_Body: + case Execution: + case Friend: + case Function_Body: + case Global_Body: + case Namespace_Body: + case Operator_Member: + case Operator_Member_Fwd: + case Parameters: + case Specifiers: + case Struct_Body: + case Typename: + { + log_failure("gen::def_namesapce_body: Entry type is not allowed: %s", entry->type_str() ); + return Code::Invalid; + } + + default: + break; + } + + result->add_entry( entry ); + } + while ( num--, num > 0 ); + + result.lock(); return result; } @@ -1611,7 +2108,7 @@ namespace gen if (num <= 0) { - log_failure( "TT::make_paramters: num cannot be zero or neg" ); + log_failure( "gen::def_params: num cannot be zero or neg" ); return Code::Invalid; } @@ -1622,14 +2119,12 @@ namespace gen va_list va; va_start(va, num); - Code type = va_arg(va, Code); - + Code type = va_arg(va, Code); + s32 name_length = va_arg(va, s32 ); char const* name = va_arg(va, char const*); - s32 name_length = strnlen(name, MaxNameLength); - result->Name = get_cached_string( name, name_length ); - - array_init( result->Entries, g_allocator ); + result->Name = get_cached_string( name, name_length ); + result->Entries = make_code_entries(); if ( type->Type != Typename ) { @@ -1639,18 +2134,17 @@ namespace gen result->add_entry( type ); - while( num -= 2, num && num % 2 == 0 ) + while( num -= 3, num && num % 3 == 0 ) { type = va_arg(va, Code); name_length = va_arg(va, u32); name = va_arg(va, char const*); Code - param = make_code(); - param->Type = Parameters; - param->Name = get_cached_string(name, name_length); - - array_init( param->Entries, StaticData::Allocator_CodePool ); + param = make_code(); + param->Type = Parameters; + param->Name = get_cached_string(name, name_length); + param->Entries = make_code_entries(); if ( type->Type != Typename ) { @@ -1669,10 +2163,58 @@ namespace gen return result; } + Code def_params( s32 num, Code* codes ) + { + using namespace ECode; + + if (num <= 0) + { + log_failure( "gen::def_params: num cannot be zero or neg" ); + return Code::Invalid; + } + + if ( codes == nullptr ) + { + log_failure("gen::def_params: Provided a null array of codes"); + return Code::Invalid; + } + +# define check_current() \ + if ( current == nullptr ) \ + { \ + log_failure("gen::def_params: Provide a null code in codes array"); \ + return Code::Invalid; \ + } \ + \ + if (current->Type != Parameters ) \ + { \ + log_failure("gen::def_params: Code in coes array is not of paramter type - %s", current->debug_str() ); \ + return Code::Invalid; \ + } + + Code current = * codes; + check_current(); + + Code + result = make_code(); + result->Name = current->Name; + result->Type = current->Type; + + while( codes++, current = * codes, num--, num > 0 ) + { + check_current(); + result->add_entry( current ); + } +# undef check_current + + result.lock(); + return result; + } + Code def_specifiers( s32 num, ... ) { if ( num <= 0 ) - log_failure("gen::make_specifier: num cannot be zero or less"); + log_failure("gen::def_specifiers: num cannot be zero or less"); // This should be more than enough... static u8 FixedSizedBuffer[kilobytes(1024)]; @@ -1712,8 +2254,9 @@ namespace gen result->Content = get_cached_string( crafted, string_length( crafted ) ); - arena_free( & str_arena ); + free_all( arena_allocator( & str_arena ) ); + result.lock(); return result; } @@ -1728,8 +2271,7 @@ namespace gen } Code - result = make_code(); - result->Entries = make_code_entries(); + result = make_code(); va_list va; va_start(va, num); @@ -1751,7 +2293,7 @@ namespace gen case Typename: case Using_Namespace: { - log_failure("gen::def_struct_body: Entry type is not allowed: %s", ECode::str(entry->Type) ); + log_failure("gen::def_struct_body: Entry type is not allowed: %s", ECode::to_str(entry->Type) ); return Code::Invalid; } @@ -1764,6 +2306,9 @@ namespace gen return Code::Invalid; } break; + + default: + break; } result->add_entry( entry ); @@ -1771,6 +2316,7 @@ namespace gen while ( num--, num > 0 ); va_end(va); + result.lock(); return result; } # pragma endregion Upfront Constructors @@ -1778,7 +2324,40 @@ namespace gen # pragma region Incremetnal Constructors Code make_class( s32 length, char const* name, Code parent, Code specifiers ) { - not_implemented( make_class ); + using namespace ECode; + + name_check( make_struct, length, name ); + + if ( specifiers && specifiers->Type != Specifiers ) + { + log_failure( "gen::make_class: specifiers was not a `Specifiers` type" ); + return Code::Invalid; + } + + if ( parent && parent->Type != Struct ) + { + log_failure( "gen::make_class: parent was not a `Struct` type" ); + return Code::Invalid; + } + + Code + result = make_code(); + result->Type = Struct; + result->Name = get_cached_string( name, length ); + + Code + body = make_code(); + body->Type = Function_Body; + + result->add_entry( make_code() ); + + if ( parent ) + result->add_entry( parent ); + + if ( specifiers ) + result->add_entry( specifiers ); + + return result; } Code make_enum( s32 length, char const* name, Code type, EnumT specifier ) @@ -1815,17 +2394,15 @@ namespace gen } Code - result = make_code(); - result->Name = get_cached_string( name, length ); - result->Type = Function; - result->Entries = make_code_entries(); + result = make_code(); + result->Name = get_cached_string( name, length ); + result->Type = Function; Code - body = make_code(); - body->Type = Function_Body; - body->Entries = make_code_entries(); + body = make_code(); + body->Type = Function_Body; - result->add_entry( make_code() ); + result->add_entry( body ); if ( specifiers ) result->add_entry( specifiers ); @@ -1844,13 +2421,9 @@ namespace gen name_check( make_global_body, length, name ); Code - result = make_code(); - result->Type = ECode::Global_Body; - result->Name = get_cached_string( name, length ); - result->Entries = make_code_entries(); - - // Making body at entry 0; - result->add_entry( make_code() ); + result = make_code(); + result->Type = ECode::Global_Body; + result->Name = get_cached_string( name, length ); return result; } @@ -1883,26 +2456,24 @@ namespace gen if ( specifiers && specifiers->Type != Specifiers ) { - log_failure( "gen::def_struct: specifiers was not a `Specifiers` type" ); + log_failure( "gen::make_struct: specifiers was not a `Specifiers` type" ); return Code::Invalid; } if ( parent && parent->Type != Struct ) { - log_failure( "gen::def_struct: parent was not a `Struct` type" ); + log_failure( "gen::make_struct: parent was not a `Struct` type" ); return Code::Invalid; } Code - result = make_code(); - result->Type = Struct; - result->Name = get_cached_string( name, length ); - result->Entries = make_code_entries(); + result = make_code(); + result->Type = Struct; + result->Name = get_cached_string( name, length ); Code - body = make_code(); - body->Type = Function_Body; - body->Entries = make_code_entries(); + body = make_code(); + body->Type = Function_Body; result->add_entry( make_code() ); @@ -2066,9 +2637,6 @@ namespace gen // get end specifiers - - - if ( * scanner != '{') { @@ -2084,10 +2652,9 @@ namespace gen Code body = untyped_str( body_length, body_str ); Code - result = make_code(); - result->Name = get_cached_string( name, name_length ); - result->Type = ECode::Function; - result->Entries = make_code_entries(); + result = make_code(); + result->Name = get_cached_string( name, name_length ); + result->Type = ECode::Function; result->add_entry( body ); @@ -2260,7 +2827,7 @@ namespace gen #pragma region Builder 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 ) diff --git a/project/gen.hpp b/project/gen.hpp index f2c2e53..8224512 100644 --- a/project/gen.hpp +++ b/project/gen.hpp @@ -30,22 +30,23 @@ These features are in as they either are not horrible when used conservatively or are a performance benefit (modules). - When it comes to expressions: - There is no parse API for validating expressions (possibly will add in the future). - This reason there isn't one: thats where the can of worms open for parsing validation. - For most metaprogramming (espcially for c/c++), expression validation is not necessary, it can be done by the compiler for the runtime program. - Most of the time, the critical complex metaprogramming conundrums are actaully producing the frame of abstractions around the expressions. - Thus its not very much a priority to add such a level of complexity to the library when there isn't a high reward or need for it. + #### When it comes to expressions: - To further this point, lets say you do have an error with an expressions composition. - It will either be caught by the c++ compiler when compiling the target program, or at runtime for the program. + There is no support for validating expressions. + The reason: thats where the can of worms open for parsing validation. This library would most likey more than double in size with that addition alone. + For most metaprogramming (espcially for C/C++), expression validation is not necessary for metaprogramming, it can be done by the compiler for the runtime program. + Most of the time, the critical complex metaprogramming conundrums are actaully producing the frame of abstractions around the expressions. + Thus its not very much a priority to add such a level of complexity to the library when there isn't a high reward or need for it. - * If its not caught by the compiler, the only downside is the error appers on the generated function. - Those with knowledge of how that definition was generated know where to find the code that inlined that expression in that file for that definition. - * If its caught at runtime. The expression will be shown in a stack trace if debug symbols are enabled in the generated function body. - Yet again those with knowledge of how that definition was generated know where to find the code that inlined that expression. + To further this point, lets say you do have an error with an expressions composition. + It will either be caught by the c++ compiler when compiling the target program, or at runtime for the program. - In both these cases will get objectively better debug information than you would normally get on most c++ compilers with complex macros or templates. + * If its not caught by the compiler, the only downside is the error appers on the generated function. + Those with knowledge of how that definition was generated know where to find the code that inlined that expression in that file for that definition. + * If its caught at runtime. The expression will be shown in a stack trace if debug symbols are enabled in the generated function body. + Yet again those with knowledge of how that definition was generated know where to find the code that inlined that expression. + + In both these cases the user will get objectively better debug information than you would normally get on most c++ compilers/editors using complex macros or templates. ### The Data & Interface: @@ -58,31 +59,48 @@ * ASTs are wrapped for the user in a Code struct which essentially a warpper for a AST* type. * Both AST and Code have member symbols but their data layout is enforced to be POD types. * This library treats memory failures as fatal. - * The default setup assumes large definition sets may be provided to bodies so AST::Entires are dynamic arrays. - * They're allocated to arenas currently and are pretty wasteful if they go over their reserve size (its never recycled). - * Most likely will need to implement a dynamic-sized bucket allocation strategy for the entry arrays if memory is getting stressed. - * Otherwise if you are using fixed size entries and your definitions are under 128~512 entries for the body, you may be better of with a fixed-sized array. + * The AST's data union is can either hold a static array of AST*'s, a dynmaic array if the the static capacity is not enough, or a cached string content. + * The dynamic array is allocated to arenas currently and are pretty wasteful if they go over their reserve size (its never recycled). Data layout of AST struct: - AST* Parent; - CachedString Name; - CachedString Comment; - union { - array(AST*) Entries; - CachedString Content; - }; - CodeT Type; - OperatorT Op; - bool Readonly; - u8 _64_Align[23]; + union { + AST* ArrStatic[ArrS_Cap]; + Array(AST*) Entries; + StringCached Content; + + }; + AST* Parent; + StringCached Name; + StringCached Comment; + CodeT Type; + OperatorT Op; + bool Readonly; + bool DynamicEntries; + u8 StaticIndex; + u8 _Align_Pad[6]; *`CodeT` is a typedef for `ECode::Type` which is the type of the enum.* + AST widths are setup to be AST_POD_Size. + The width dictates how much the static array can hold before it must give way to using an allocated array: + constexpr static + u32 ArrS_Cap = + ( AST_POD_Size + - sizeof(AST*) + - sizeof(StringCached) * 2 + - sizeof(CodeT) + - sizeof(OperatorT) + - sizeof(bool) * 2 + - sizeof(u8) * 7 ) + / sizeof(AST*); + + Ex: If the AST_POD_Size is 256 the capacity of the static array is 26. + ASTs can be set to readonly by calling Code's lock() member function. Adding comments is always available even if the AST is set to readonly. - Data Notes: + #### Misc * The allocator definitions used are exposed to the user incase they want to dictate memory usage * You'll find the memory handling in `init`, `gen_string_allocator`, `get_cached_string`, `make_code`, and `make_code_entries`. @@ -261,6 +279,16 @@ Code = parse_( gen_code_str ); ``` + ## Extent of operator overload validation: + + The AST and constructors will be able to validate that the arguments provided for the operator type match the expected form: + * If return type must match a parameter + * If number of parameters is correct + * If added as a member symbol to a class or struct, that operator matches the requirements for the class (types match up) + + The user is responsible for making sure the code types provided are correct + and have the desired specifiers assigned to them beforehand. + ## Code generation and modification There are three provided interfaces: @@ -318,12 +346,10 @@ Request queue in both Editor and Scanner are cleared once process_requests completes. - ### Notes on multi-threading: + ### On multi-threading: - Its intended eventually for this library to support multi-threading at some point, - however for now it does not. - The following changes would have to be made: - * Setup static data accesss with fences if more than one thread will generate ASTs + Currently supported but want to. The following changes would have to be made: + * Setup static data accesss with fences if more than one thread will generate ASTs ( or keep a different set for each thread) * Make sure local peristent data of functions are also thread local. * The builder should be done on a per-thread basis. * Due to the design of the editor and scanner, it will most likely @@ -352,9 +378,6 @@ #include "Bloat.hpp" // Temporarily here for debugging purposes. -#define gentime - - #define GEN_BAN_CPP_TEMPLATES #define GEN_DEFINE_DSL #define GEN_DEFINE_LIBRARY_CODE_CONSTANTS @@ -364,7 +387,7 @@ #define GEN_FEATURE_SCANNER -#ifdef gentime +#ifdef gen_time namespace gen { using LogFailType = sw(*)(char const*, ...); @@ -383,38 +406,40 @@ namespace gen namespace ECode { -# define Define_Types \ - Entry( Untyped ) \ - Entry( Access_Public ) \ - Entry( Access_Protected ) \ - Entry( Access_Private ) \ - Entry( Class ) \ - Entry( Class_FwdDecl ) \ - Entry( Class_Body ) \ - Entry( Enum ) \ - Entry( Enum_FwdDecl ) \ - Entry( Enum_Body ) \ - Entry( Enum_Class ) \ - Entry( Enum_Class_FwdDecl ) \ - Entry( Execution ) \ - Entry( Friend ) \ - Entry( Function ) \ - Entry( Function_FwdDecl ) \ - Entry( Function_Body ) \ - Entry( Global_Body ) \ - Entry( Namespace ) \ - Entry( Namespace_Body ) \ - Entry( Operator ) \ - Entry( Operator_FwdDecl ) \ - Entry( Parameters ) \ - Entry( Specifiers ) \ - Entry( Struct ) \ - Entry( Struct_FwdDecl ) \ - Entry( Struct_Body ) \ - Entry( Variable ) \ - Entry( Typedef ) \ - Entry( Typename ) \ - Entry( Using ) \ +# define Define_Types \ + Entry( Untyped ) \ + Entry( Access_Public ) \ + Entry( Access_Protected ) \ + Entry( Access_Private ) \ + Entry( Class ) \ + Entry( Class_Fwd ) \ + Entry( Class_Body ) \ + Entry( Enum ) \ + Entry( Enum_Fwd ) \ + Entry( Enum_Body ) \ + Entry( Enum_Class ) \ + Entry( Enum_Class_Fwd ) \ + Entry( Execution ) \ + Entry( Friend ) \ + Entry( Function ) \ + Entry( Function_Fwd ) \ + Entry( Function_Body ) \ + Entry( Global_Body ) \ + Entry( Namespace ) \ + Entry( Namespace_Body ) \ + Entry( Operator ) \ + Entry( Operator_Fwd ) \ + Entry( Operator_Member ) \ + Entry( Operator_Member_Fwd ) \ + Entry( Parameters ) \ + Entry( Specifiers ) \ + Entry( Struct ) \ + Entry( Struct_Fwd ) \ + Entry( Struct_Body ) \ + Entry( Variable ) \ + Entry( Typedef ) \ + Entry( Typename ) \ + Entry( Using ) \ Entry( Using_Namespace ) enum Type : u32 @@ -428,7 +453,7 @@ namespace gen }; inline - char const* str( Type type ) + char const* to_str( Type type ) { static char const* lookup[Num_Types] = { @@ -520,7 +545,7 @@ namespace gen }; inline - char const* str( Type op ) + char const* to_str( Type op ) { using something = u8; typedef u8 another; @@ -568,24 +593,19 @@ namespace gen Entry( Constexpr, constexpr ) \ Entry( Constinit, constinit ) \ Entry( Export, export ) \ - Entry( Explicit, explicit ) \ 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( Ptr, * ) \ + Entry( Ref, & ) \ Entry( Register, register ) \ Entry( RValue, && ) \ Entry( Static_Member, static ) \ Entry( Thread_Local, Thread_Local_Code ) \ - Entry( Virtual, virtual ) \ Entry( Volatile, volatile ) enum Type : u32 @@ -641,6 +661,16 @@ namespace gen using SpecifierT = ESpecifier::Type; #pragma region Data Structures + // Implements basic string interning. Data structure is based off the ZPL Hashtable. + ZPL_TABLE_DECLARE( ZPL_EXTERN, StringTable, str_tbl_, String ); + + // Represents strings cached with the string table. + // Should never be modified, if changed string is desired, cache_string( str ) another. + using StringCached = char const*; + + // Desired width of the AST data structure. + ct u32 AST_POD_Size = 256; + // TODO: If perf needs it, convert layout an SOA format. /* Simple AST POD with functionality to seralize into C++ syntax. @@ -648,28 +678,24 @@ namespace gen 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. + + Any type specific functions assume the construction of the AST was done correctly. */ struct AST { # pragma region Member Functions + + // Used with incremental constructors + // Adds and checks entries to see if they are valid additions the type of ast. bool add( AST* other ); - forceinline - void add_entry( AST* other ) - { - AST* to_add = other->Parent ? - other->duplicate() : other; - - array_append( Entries, to_add ); - - to_add->Parent = this; - } + inline + void add_entry( AST* other ); forceinline AST* body() { - return Entries && array_count(Entries) ? - Entries[0] : nullptr; + return Entries[0]; } forceinline @@ -678,39 +704,76 @@ namespace gen AST* duplicate(); forceinline - bool has_entries() const + bool has_entries() { - static bool lookup[ ECode::Num_Types] = { - false, // Invalid - false, // Untyped - false, - false, - false, - true, // Global_Body - true, // Parameters - true, // Proc - true, // Proc_Body - true, // Proc_Forward - false, // Specifies - true, // Struct - true, // Struct_Body - true, // Variable - true, // Typedef - true, // Typename - true, // Using - }; - - return lookup[Type]; + return Entries[0]; } forceinline - bool is_invalid() const + bool is_invalid() { return Type != ECode::Invalid; } forceinline - char const* debug_str() const + s32 num_entries() + { + return DynamicEntries ? array_count(Entries) : StaticIndex; + } + + // Parameter + + forceinline + AST* get_param( s32 index ) + { + if ( index <= 0 ) + return this; + + return Entries[ index + 1 ]; + } + + forceinline + s32 param_count() + { + // The first entry (which holds the type) represents the first parameter. + return num_entries(); + } + + forceinline + AST* param_type() + { + return Entries[0]; + } + + // Typename + + forceinline + bool typename_is_ptr() + { + zpl::assert_crash("not implemented"); + } + + forceinline + bool typename_is_ref() + { + zpl::assert_crash("not implemented"); + } + + forceinline + AST* typename_specifiers() + { + return Entries[0]; + } + + // AST*& operator=(AST* const& b) + // { + + // } + + // Serialization + + forceinline + char const* debug_str() { char const* fmt = txt( \nCode Debug: @@ -725,7 +788,7 @@ namespace gen // Thus if its desired to keep the debug str // for multiple calls to bprintf, // allocate this to proper string. - return zpl::bprintf( fmt + return bprintf( fmt , type_str() , Readonly ? "true" : "false" , Parent ? Parent->Name : "" @@ -735,40 +798,60 @@ namespace gen } forceinline - char const* type_str() const + char const* type_str() { - return ECode::str( Type ); + return ECode::to_str( Type ); } String to_string() const; # pragma endregion Member Functions + constexpr + static uw ArrS_Cap = + ( AST_POD_Size + - sizeof(AST*) + - sizeof(StringCached) * 2 + - sizeof(CodeT) + - sizeof(OperatorT) + - sizeof(bool) * 2 + - sizeof(u8) * 7 ) + / sizeof(AST*); -# define Using_Code_POD \ - AST* Parent; \ - StringCached Name; \ - StringCached Comment; \ - union { \ - Array(AST*) Entries; \ - StringCached Content; \ - }; \ - CodeT Type; \ - OperatorT Op; \ - bool Readonly; \ - u8 _64_Align[23]; + // SpecifierT Specifiers[] \ - Using_Code_POD; + // Size : 256 bytes +# define Using_Code_POD \ + union { \ + AST* ArrStatic[AST::ArrS_Cap]; \ + Array(AST*) Entries; \ + StringCached Content; \ + }; \ + AST* Parent; \ + StringCached Name; \ + StringCached Comment; \ + CodeT Type; \ + OperatorT Op; \ + bool Readonly; \ + bool DynamicEntries; \ + u8 StaticIndex; \ + u8 _Align_Pad[6]; + + Using_Code_POD }; + struct CodePOD { - Using_Code_POD; + Using_Code_POD # undef Using_CodePOD; }; + ct sw size_AST = sizeof(AST); + ct sw size_POD = sizeof(CodePOD); // 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" ); + static_assert( sizeof(AST) == sizeof(CodePOD), "ERROR: AST IS NOT POD" ); + static_assert( sizeof(CodePOD) == AST_POD_Size, "ERROR: AST POD is not size of AST_POD_Size" ); /* AST* typedef as to not constantly have to add the '*' as this is written often.. @@ -782,7 +865,7 @@ namespace gen { # pragma region Statics // Used internally for the most part to identify invaidly generated code. - static const Code Invalid; + static Code Invalid; # pragma endregion Statics # pragma region Member Functions @@ -824,22 +907,37 @@ namespace gen } forceinline - operator bool() const + char const* to_string() + { + return ast->to_string(); + } + + forceinline + operator bool() { return ast; } - bool operator ==( Code other ) const + forceinline + bool operator ==( Code other ) { return ast == other.ast; } + forceinline + bool operator !=( Code other ) + { + return ast != other.ast; + } + + forceinline operator AST*() { return ast; } - Code& operator =( Code other ) + forceinline + Code& operator=( Code other ) { if ( ast == nullptr ) { @@ -861,7 +959,7 @@ namespace gen } forceinline - AST* operator ->() + AST* operator->() { if ( ast == nullptr ) { @@ -889,13 +987,6 @@ namespace gen ct Code NoCode = { nullptr }; // extern const Code InvalidCode; - // Implements basic string interning. Data structure is based off the ZPL Hashtable. - ZPL_TABLE_DECLARE( ZPL_EXTERN, StringTable, str_tbl_, String ); - - // Represents strings cached with the string table. - // Should never be modified, if changed string is desired, cache_string( str ) another. - using StringCached = char const*; - /* Type Table: Used to store Typename ASTs. Types are registered by their string literal value. @@ -911,10 +1002,13 @@ namespace gen // This currently just initializes the CodePool. void init(); - // Use this only if you know you generated the code you needed to a file. - // And rather get rid of current code asts instead of growing the pool memory. - // This generally can be done everytime a file is generated - void clear_code_pool(); + /* + Use this only if you know you generated the code you needed to a file. + And rather get rid of current code asts instead of growing the pool memory. + This generally can be done everytime a file is generated + TODO: In order for this to work, the type map needs its own arenas so do specifiers. + */ + void clear_code_memory(); // Used internally to retrive or make string allocations. // Strings are stored in a series of string arenas of fixed size (SizePer_StringArena) @@ -964,11 +1058,13 @@ namespace gen Code def_class_body ( s32 num, ... ); Code def_enum_body ( u32 num, ... ); - Code def_enum_body ( u32 num, Code* Values ); + Code def_enum_body ( u32 num, Code* codes ); Code def_global_body ( s32 num, ... ); + Code def_global_body ( s32 num, Code* codes ); Code def_function_body ( s32 num, ... ); Code def_function_body ( s32 num, Code* codes ); Code def_namespace_body ( s32 num, ... ); + Code def_namespace_body ( s32 num, Code* codes ); Code def_params ( s32 num, ... ); Code def_params ( s32 num, Code* params ); Code def_specifiers ( s32 num , ... ); @@ -1274,12 +1370,6 @@ namespace gen { // Predefined typename codes. Are set to readonly and are setup during gen::init() - extern Code type_ns( void ); - - extern Code type_ns( bool ); - extern Code type_ns( char ); - extern Code type_ns( wchar_t ); - extern Code type_ns( s8 ); extern Code type_ns( s16 ); extern Code type_ns( s32 ); @@ -1309,7 +1399,7 @@ namespace gen ct s32 InitSize_TypeTable = megabytes(4); ct s32 CodePool_NumBlocks = 4096; - ct s32 CodeEntiresPool_NumBlocks = 4096; + ct s32 InitSize_CodeEntiresArray = 512; ct s32 SizePer_CodeEntriresArena = megabytes(16); ct s32 SizePer_StringArena = megabytes(32); @@ -1319,6 +1409,12 @@ namespace gen // Predefined Codes. Are set to readonly and are setup during gen::init() + extern Code type_ns( void ); + extern Code type_ns( int ); + extern Code type_ns( bool ); + extern Code type_ns( char ); + extern Code type_ns( wchar_t ); + extern Code access_public; extern Code access_protected; extern Code access_private; @@ -1333,3 +1429,44 @@ namespace gen // end: gen_time #endif + +#pragma region Inlines +namespace gen +{ + inline void AST::add_entry( AST* other ) + { + AST* to_add = other->Parent ? + other->duplicate() : other; + + if (DynamicEntries) + array_append( Entries, to_add ); + + else + { + if ( StaticIndex < ArrS_Cap ) + { + ArrStatic[StaticIndex] = to_add; + StaticIndex++; + } + else + { + Entries = make_code_entries(); + + s32 index = 0; + do + { + array_append( Entries, ArrStatic[index] ); + } + while ( StaticIndex--, StaticIndex ); + + array_append( Entries, to_add ); + } + } + + to_add->Parent = this; + } +} +#pragma endregion Inlines + +#pragma region Undefines +#pragma endregion Undefines diff --git a/test/gen/meson.build b/test/gen/meson.build index 04d8f65..b3780d5 100644 --- a/test/gen/meson.build +++ b/test/gen/meson.build @@ -22,6 +22,6 @@ endif # add_project_arguments('-E', language : ['c', 'cpp']) # add_global_arguments( '-E', language : ['cpp']) -add_project_arguments('-Dgentime', language : ['c', 'cpp']) +add_project_arguments('-Dgen_time', language : ['c', 'cpp']) executable( 'gencpp', sources, include_directories : includes ) diff --git a/test/test.cpp b/test/test.cpp index d615abb..d4deb10 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1,7 +1,7 @@ #include "Bloat.cpp" -#ifdef gentime +#ifdef gen_time #include "gen.cpp" int gen_main() @@ -19,7 +19,7 @@ int gen_main() #endif -#ifdef comptime +#ifdef runtime int main() { return 0;