diff --git a/project/Readme.md b/project/Readme.md index 1ea25f6..7491323 100644 --- a/project/Readme.md +++ b/project/Readme.md @@ -1,6 +1,9 @@ # Documentation -All the library code is contained in two files: `gen.hpp` and `gen.cpp` +The core library is contained within `gen.hpp` and `gen.cpp`. +Things related to the editor and scanner are in their own respective files. (Ex: `gen.scanner.` ) + + ## gen.hpp @@ -11,8 +14,8 @@ Feature Macros: * `GEN_DEFINE_LIBRARY_CORE_CONSTANTS` : Optional typename codes as they are non-standard to C/C++ and not necessary to library usage * `GEN_ENFORCE_STRONG_CODE_TYPES` : Enforces casts to filtered code types. -`GEN_USE_RECURSIVE_AST_DUPLICATION` is available but its not well tested and should not need to be used. -If constructing ASTs properly. There should be no modification of ASTs, and thus this would never become an issue. +`GEN_USE_RECURSIVE_AST_DUPLICATION` is available but its not well tested and should not need to be used. +If constructing ASTs properly. There should be no modification of ASTs, and thus this would never become an issue. (I will probably remove down the line...) Due to the design of `gen.hpp` to support being written alongside runtime intended code (in the same file), all the code is wrapped in a `GEN_TIME` `#ifdef` and then wrapped further in a `gen` namespace to avoid pollution of the global scope. diff --git a/project/gen.cpp b/project/gen.cpp index 47139c5..42c281b 100644 --- a/project/gen.cpp +++ b/project/gen.cpp @@ -14,145 +14,145 @@ #include "gen.hpp" -namespace gen -{ +namespace gen { + #pragma region StaticData - // TODO : Convert global allocation strategy to use the dual-scratch allocator for a contextual scope. - global AllocatorInfo GlobalAllocator; - global Array Global_AllocatorBuckets; +// TODO : Convert global allocation strategy to use the dual-scratch allocator for a contextual scope. +global AllocatorInfo GlobalAllocator; +global Array Global_AllocatorBuckets; - global Array< Pool > CodePools = { nullptr }; - global Array< Arena > StringArenas = { nullptr }; +global Array< Pool > CodePools = { nullptr }; +global Array< Arena > StringArenas = { nullptr }; - global StringTable StringCache; +global StringTable StringCache; - global Arena LexArena; +global Arena LexArena; - global AllocatorInfo Allocator_DataArrays = heap(); - global AllocatorInfo Allocator_CodePool = heap(); - global AllocatorInfo Allocator_Lexer = heap(); - global AllocatorInfo Allocator_StringArena = heap(); - global AllocatorInfo Allocator_StringTable = heap(); - global AllocatorInfo Allocator_TypeTable = heap(); +global AllocatorInfo Allocator_DataArrays = heap(); +global AllocatorInfo Allocator_CodePool = heap(); +global AllocatorInfo Allocator_Lexer = heap(); +global AllocatorInfo Allocator_StringArena = heap(); +global AllocatorInfo Allocator_StringTable = heap(); +global AllocatorInfo Allocator_TypeTable = heap(); #pragma endregion StaticData #pragma region Constants - global CodeType t_auto; - global CodeType t_void; - global CodeType t_int; - global CodeType t_bool; - global CodeType t_char; - global CodeType t_wchar_t; - global CodeType t_class; - global CodeType t_typename; +global CodeType t_auto; +global CodeType t_void; +global CodeType t_int; +global CodeType t_bool; +global CodeType t_char; +global CodeType t_wchar_t; +global CodeType t_class; +global CodeType t_typename; - #ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS - global CodeType t_b32; +#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS +global CodeType t_b32; - global CodeType t_s8; - global CodeType t_s16; - global CodeType t_s32; - global CodeType t_s64; +global CodeType t_s8; +global CodeType t_s16; +global CodeType t_s32; +global CodeType t_s64; - global CodeType t_u8; - global CodeType t_u16; - global CodeType t_u32; - global CodeType t_u64; +global CodeType t_u8; +global CodeType t_u16; +global CodeType t_u32; +global CodeType t_u64; - global CodeType t_sw; - global CodeType t_uw; +global CodeType t_sw; +global CodeType t_uw; - global CodeType t_f32; - global CodeType t_f64; - #endif +global CodeType t_f32; +global CodeType t_f64; +#endif - global Code access_public; - global Code access_protected; - global Code access_private; +global Code access_public; +global Code access_protected; +global Code access_private; - global Code module_global_fragment; - global Code module_private_fragment; +global Code module_global_fragment; +global Code module_private_fragment; - global Code pragma_once; +global Code pragma_once; - global CodeSpecifier spec_const; - global CodeSpecifier spec_consteval; - global CodeSpecifier spec_constexpr; - global CodeSpecifier spec_constinit; - global CodeSpecifier spec_extern_linkage; - global CodeSpecifier spec_global; - global CodeSpecifier spec_inline; - global CodeSpecifier spec_internal_linkage; - global CodeSpecifier spec_local_persist; - global CodeSpecifier spec_mutable; - global CodeSpecifier spec_ptr; - global CodeSpecifier spec_ref; - global CodeSpecifier spec_register; - global CodeSpecifier spec_rvalue; - global CodeSpecifier spec_static_member; - global CodeSpecifier spec_thread_local; - global CodeSpecifier spec_volatile; +global CodeSpecifier spec_const; +global CodeSpecifier spec_consteval; +global CodeSpecifier spec_constexpr; +global CodeSpecifier spec_constinit; +global CodeSpecifier spec_extern_linkage; +global CodeSpecifier spec_global; +global CodeSpecifier spec_inline; +global CodeSpecifier spec_internal_linkage; +global CodeSpecifier spec_local_persist; +global CodeSpecifier spec_mutable; +global CodeSpecifier spec_ptr; +global CodeSpecifier spec_ref; +global CodeSpecifier spec_register; +global CodeSpecifier spec_rvalue; +global CodeSpecifier spec_static_member; +global CodeSpecifier spec_thread_local; +global CodeSpecifier spec_volatile; #pragma endregion Constants #pragma region AST Body Case Macros # define AST_BODY_CLASS_UNALLOWED_TYPES \ - case PlatformAttributes: \ - case Class_Body: \ - case Enum_Body: \ - case Extern_Linkage: \ - case Function_Body: \ - case Function_Fwd: \ - case Global_Body: \ - case Namespace: \ - case Namespace_Body: \ - case Operator: \ - case Operator_Fwd: \ - case Parameters: \ - case Specifiers: \ - case Struct_Body: \ - case Typename: +case PlatformAttributes: \ +case Class_Body: \ +case Enum_Body: \ +case Extern_Linkage: \ +case Function_Body: \ +case Function_Fwd: \ +case Global_Body: \ +case Namespace: \ +case Namespace_Body: \ +case Operator: \ +case Operator_Fwd: \ +case Parameters: \ +case Specifiers: \ +case Struct_Body: \ +case Typename: # define AST_BODY_FUNCTION_UNALLOWED_TYPES \ - case Access_Public: \ - case Access_Protected: \ - case Access_Private: \ - case PlatformAttributes: \ - case Class_Body: \ - case Enum_Body: \ - case Extern_Linkage: \ - case Friend: \ - case Function_Body: \ - 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: \ - case Typename: +case Access_Public: \ +case Access_Protected: \ +case Access_Private: \ +case PlatformAttributes: \ +case Class_Body: \ +case Enum_Body: \ +case Extern_Linkage: \ +case Friend: \ +case Function_Body: \ +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: \ +case Typename: # define AST_BODY_GLOBAL_UNALLOWED_TYPES \ - case Access_Public: \ - case Access_Protected: \ - case Access_Private: \ - case PlatformAttributes: \ - 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: +case Access_Public: \ +case Access_Protected: \ +case Access_Private: \ +case PlatformAttributes: \ +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: # define AST_BODY_EXPORT_UNALLOWED_TYPES AST_BODY_GLOBAL_UNALLOWED_TYPES # define AST_BODY_NAMESPACE_UNALLOWED_TYPES AST_BODY_GLOBAL_UNALLOWED_TYPES @@ -162,1486 +162,1528 @@ namespace gen #pragma endregion AST Body Case Macros #pragma region AST - Code Code::Global; - Code Code::Invalid; +Code Code::Global; +Code Code::Invalid; - AST* AST::duplicate() +AST* AST::duplicate() +{ + using namespace ECode; + + AST* + result = make_code().ast; +#ifndef GEN_USE_RECURSIVE_AST_DUPLICATION + mem_copy( result, this, sizeof( AST ) ); + result->Parent = nullptr; +#else + // TODO : Stress test this... + switch ( Type ) + { + case Invalid: + log_failure("Attempted to duplicate invalid code! - \n%s", Parent ? Parent->debug_str() : Name ); + return nullptr + case Untyped: + case Comment: + case Execution: + case Access_Private: + case Access_Protected: + case Access_Public: + case PlatformAttributes: + case Preprocessor_Include: + case Module: + case Specifiers: + case Using_Namespace: + mem_copy( result, this, sizeof( AST ) ); + break; + + case Extern_Linkage: + case Friend: + mem_copy( result, this, sizeof( AST ) ); + + if (Value) + result->Value = Value->duplicate(); + break; + + case Class: + case Struct: + case Enum: + mem_copy( result, this, sizeof( AST ) ); + + if ( Attributes) + result->Attributes = Attributes->duplicate(); + + if ( ParentType ) + result->ParentType = ParentType->duplicate(); + + result->Body = Body->duplicate(); + break; + + case Enum_Fwd: + case Class_Fwd: + case Struct_Fwd: + mem_copy( result, this, sizeof( AST ) ); + + if ( Attributes) + result->Attributes = Attributes->duplicate(); + + if ( ParentType ) + result->ParentType = ParentType->duplicate(); + break; + + case Function: + case Operator: + case Operator_Member: + mem_copy( result, this, sizeof( AST ) ); + + if ( Attributes) + result->Attributes = Attributes->duplicate(); + + if ( Specs ) + result->ParentType = ParentType->duplicate(); + + if ( ReturnType ) + result->ReturnType = ReturnType->duplicate(); + + if ( Params ) + result->Params = Params->duplicate(); + + result->Body = Body->duplicate(); + break; + + case Function_Fwd: + case Operator_Fwd: + case Operator_Member_Fwd: + mem_copy( result, this, sizeof( AST ) ); + + if ( Attributes) + result->Attributes = Attributes->duplicate(); + + if ( Specs ) + result->ParentType = ParentType->duplicate(); + + if ( ReturnType ) + result->ReturnType = ReturnType->duplicate(); + + if ( Params ) + result->Params = Params->duplicate(); + break; + + case Namespace: + mem_copy( result, this, sizeof( AST ) ); + + result->Body = Body->duplicate(); + break; + + case Operator_Cast: + mem_copy( result, this, sizeof( AST ) ); + + result->ValueType = ValueType->duplicate(); + result->Body = Body->duplicate(); + break; + case Operator_Cast_Fwd: + mem_copy( result, this, sizeof( AST ) ); + + result->ValueType = ValueType->duplicate(); + break; + + case Parameters: + mem_copy( result, this, sizeof( AST ) ); + + result->NumEntries = 0; + result->Last = nullptr; + result->Next = nullptr; + + if ( NumEntries - 1 > 0 ) + { + CodeParam parent = result->cast(); + for ( CodeParam param : Next->cast() ) + { + parent.append( param ); + } + } + break; + + case Template: + mem_copy( result, this, sizeof( AST ) ); + + result->Params = Params->duplicate(); + result->Declaration = Declaration->duplicate(); + break; + + case Typename: + mem_copy( result, this, sizeof( AST ) ); + + if (Attributes) + result->Attributes = Attributes->duplicate(); + + if ( Specs ) + result->Specs = Specs->duplicate(); + + if ( ArrExpr ) + result->ArrExpr = ArrExpr->duplicate(); + break; + + case Typedef: + case Using: + mem_copy( result, this, sizeof( AST ) ); + + if (Attributes) + result->Attributes = Attributes->duplicate(); + + if ( UnderlyingType ) + result->UnderlyingType = UnderlyingType->duplicate(); + break; + + case Union: + mem_copy( result, this, sizeof( AST ) ); + + if ( Attributes) + result->Attributes = Attributes->duplicate(); + + result->Body = Body->duplicate(); + break; + + case Variable: + mem_copy( result, this, sizeof( AST ) ); + + if (Attributes) + result->Attributes = Attributes->duplicate(); + + if ( Specs ) + result->Specs = Specs->duplicate(); + + result->ValueType = UnderlyingType->duplicate(); + + if ( Value ) + result->Value = Value->duplicate(); + break; + + case Class_Body: + case Enum_Body: + case Export_Body: + case Extern_Linkage_Body: + case Function_Body: + case Global_Body: + case Namespace_Body: + case Struct_Body: + case Union_Body: + CodeBody + body = cast(); + body->Name = Name; + body->Type = Type; + for ( Code entry : cast() ) + { + result->append( entry.ast ); + } + break; + } +#endif + + return result; +} + +String AST::to_string() +{ +# define ProcessModuleFlags() \ + if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export )) \ + result.append( "export " ); \ + \ + if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Import )) \ + result.append( "import " ); \ + + local_persist thread_local + char SerializationLevel = 0; + +#if defined(GEN_BENCHMARK) && defined(GEN_BENCHMARK_SERIALIZATION) + u64 time_start = time_rel_ms(); +#endif + + // TODO : Need to refactor so that intermeidate strings are freed conviently. + String result = String::make( GlobalAllocator, "" ); + + switch ( Type ) { using namespace ECode; - AST* - result = make_code().ast; - #ifndef GEN_USE_RECURSIVE_AST_DUPLICATION - mem_copy( result, this, sizeof( AST ) ); - result->Parent = nullptr; - #else - // TODO : Stress test this... - switch ( Type ) + case Invalid: + log_failure("Attempted to serialize invalid code! - %s", Parent ? Parent->debug_str() : Name ); + break; + + case Untyped: + case Execution: + result.append( Content ); + break; + + case Comment: { - case Invalid: - log_failure("Attempted to duplicate invalid code! - \n%s", Parent ? Parent->debug_str() : Name ); - return nullptr - case Untyped: - case Comment: - case Execution: - case Access_Private: - case Access_Protected: - case Access_Public: - case PlatformAttributes: - case Preprocessor_Include: - case Module: - case Specifiers: - case Using_Namespace: - mem_copy( result, this, sizeof( AST ) ); - break; + static char line[MaxCommentLineLength]; - case Extern_Linkage: - case Friend: - mem_copy( result, this, sizeof( AST ) ); - - if (Value) - result->Value = Value->duplicate(); - break; - - case Class: - case Struct: - case Enum: - mem_copy( result, this, sizeof( AST ) ); - - if ( Attributes) - result->Attributes = Attributes->duplicate(); - - if ( ParentType ) - result->ParentType = ParentType->duplicate(); - - result->Body = Body->duplicate(); - break; - - case Enum_Fwd: - case Class_Fwd: - case Struct_Fwd: - mem_copy( result, this, sizeof( AST ) ); - - if ( Attributes) - result->Attributes = Attributes->duplicate(); - - if ( ParentType ) - result->ParentType = ParentType->duplicate(); - break; - - case Function: - case Operator: - case Operator_Member: - mem_copy( result, this, sizeof( AST ) ); - - if ( Attributes) - result->Attributes = Attributes->duplicate(); - - if ( Specs ) - result->ParentType = ParentType->duplicate(); - - if ( ReturnType ) - result->ReturnType = ReturnType->duplicate(); - - if ( Params ) - result->Params = Params->duplicate(); - - result->Body = Body->duplicate(); - break; - - case Function_Fwd: - case Operator_Fwd: - case Operator_Member_Fwd: - mem_copy( result, this, sizeof( AST ) ); - - if ( Attributes) - result->Attributes = Attributes->duplicate(); - - if ( Specs ) - result->ParentType = ParentType->duplicate(); - - if ( ReturnType ) - result->ReturnType = ReturnType->duplicate(); - - if ( Params ) - result->Params = Params->duplicate(); - break; - - case Namespace: - mem_copy( result, this, sizeof( AST ) ); - - result->Body = Body->duplicate(); - break; - - case Operator_Cast: - mem_copy( result, this, sizeof( AST ) ); - - result->ValueType = ValueType->duplicate(); - result->Body = Body->duplicate(); - break; - case Operator_Cast_Fwd: - mem_copy( result, this, sizeof( AST ) ); - - result->ValueType = ValueType->duplicate(); - break; - - case Parameters: - mem_copy( result, this, sizeof( AST ) ); - - result->NumEntries = 0; - result->Last = nullptr; - result->Next = nullptr; - - if ( NumEntries - 1 > 0 ) + s32 left = Content.length(); + s32 index = 0; + do + { + s32 length = 0; + while ( left && Content[index] != '\n' ) { - CodeParam parent = result->cast(); - for ( CodeParam param : Next->cast() ) - { - parent.append( param ); - } + length++; + left--; } - break; - case Template: - mem_copy( result, this, sizeof( AST ) ); + str_copy( line, Content, length ); + line[length] = '\0'; - result->Params = Params->duplicate(); - result->Declaration = Declaration->duplicate(); - break; - - case Typename: - mem_copy( result, this, sizeof( AST ) ); - - if (Attributes) - result->Attributes = Attributes->duplicate(); - - if ( Specs ) - result->Specs = Specs->duplicate(); - - if ( ArrExpr ) - result->ArrExpr = ArrExpr->duplicate(); - break; - - case Typedef: - case Using: - mem_copy( result, this, sizeof( AST ) ); - - if (Attributes) - result->Attributes = Attributes->duplicate(); - - if ( UnderlyingType ) - result->UnderlyingType = UnderlyingType->duplicate(); - break; - - case Union: - mem_copy( result, this, sizeof( AST ) ); - - if ( Attributes) - result->Attributes = Attributes->duplicate(); - - result->Body = Body->duplicate(); - break; - - case Variable: - mem_copy( result, this, sizeof( AST ) ); - - if (Attributes) - result->Attributes = Attributes->duplicate(); - - if ( Specs ) - result->Specs = Specs->duplicate(); - - result->ValueType = UnderlyingType->duplicate(); - - if ( Value ) - result->Value = Value->duplicate(); - break; - - case Class_Body: - case Enum_Body: - case Export_Body: - case Extern_Linkage_Body: - case Function_Body: - case Global_Body: - case Namespace_Body: - case Struct_Body: - case Union_Body: - CodeBody - body = cast(); - body->Name = Name; - body->Type = Type; - for ( Code entry : cast() ) - { - result->append( entry.ast ); - } - break; + result.append_fmt( "// %s", line ); + } + while ( left--, left > 0 ); } - #endif + break; - return result; - } + case Access_Private: + case Access_Protected: + case Access_Public: + result.append( Name ); + break; - String AST::to_string() - { - # define ProcessModuleFlags() \ - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export )) \ - result.append( "export " ); \ - \ - if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Import )) \ - result.append( "import " ); \ + case PlatformAttributes: + result.append( Content ); - local_persist thread_local - char SerializationLevel = 0; - - #if defined(GEN_BENCHMARK) && defined(GEN_BENCHMARK_SERIALIZATION) - u64 time_start = time_rel_ms(); - #endif - - // TODO : Need to refactor so that intermeidate strings are freed conviently. - String result = String::make( GlobalAllocator, "" ); - - switch ( Type ) + case Class: { - using namespace ECode; + ProcessModuleFlags(); - case Invalid: - log_failure("Attempted to serialize invalid code! - %s", Parent ? Parent->debug_str() : Name ); - break; - - case Untyped: - case Execution: - result.append( Content ); - break; - - case Comment: + if ( Attributes || ParentType ) { - static char line[MaxCommentLineLength]; - - s32 left = Content.length(); - s32 index = 0; - do - { - s32 length = 0; - while ( left && Content[index] != '\n' ) - { - length++; - left--; - } - - str_copy( line, Content, length ); - line[length] = '\0'; - - result.append_fmt( "// %s", line ); - } - while ( left--, left > 0 ); - } - break; - - case Access_Private: - case Access_Protected: - case Access_Public: - result.append( Name ); - break; - - case PlatformAttributes: - result.append( Content ); - - case Class: - { - ProcessModuleFlags(); - - if ( Attributes || ParentType ) - { - result.append( "class " ); - - if ( Attributes ) - { - result.append_fmt( "%s ", Attributes->to_string() ); - } - - if ( ParentType ) - { - char const* access_level = to_str( ParentAccess ); - - result.append_fmt( "%s : %s %s\n{\n%s\n};" - , Name - , access_level - , ParentType->to_string() - , Body->to_string() - ); - } - else - { - result.append_fmt( "%s \n{\n%s\n};", Name, Body->to_string() ); - } - } - else - { - result.append_fmt( "class %s\n{\n%s\n};", Name, Body->to_string() ); - } - } - break; - - case Class_Fwd: - { - ProcessModuleFlags(); + result.append( "class " ); if ( Attributes ) - result.append_fmt( "class %s %s;", Attributes->to_string(), Name ); - - else result.append_fmt( "class %s;", Name ); - } - break; - - case Enum: - { - ProcessModuleFlags(); - - if ( Attributes || UnderlyingType ) { - result.append( "enum " ); + result.append_fmt( "%s ", Attributes->to_string() ); + } - if ( Attributes ) - result.append_fmt( "%s ", Attributes->to_string() ); + if ( ParentType ) + { + char const* access_level = to_str( ParentAccess ); - if ( UnderlyingType ) - result.append_fmt( "%s : %s\n{\n%s\n};" - , Name - , UnderlyingType->to_string() - , Body->to_string() - ); - - else result.append_fmt( "%s\n{\n%s\n};" + result.append_fmt( "%s : %s %s\n{\n%s\n};" , Name + , access_level + , ParentType->to_string() , Body->to_string() ); } - else result.append_fmt( "enum %s\n{\n%s\n};" - , Name - , Body->to_string() - ); + else + { + result.append_fmt( "%s \n{\n%s\n};", Name, Body->to_string() ); + } } - break; - - case Enum_Fwd: + else { - ProcessModuleFlags(); + result.append_fmt( "class %s\n{\n%s\n};", Name, Body->to_string() ); + } + } + break; + + case Class_Fwd: + { + ProcessModuleFlags(); + + if ( Attributes ) + result.append_fmt( "class %s %s;", Attributes->to_string(), Name ); + + else result.append_fmt( "class %s;", Name ); + } + break; + + case Enum: + { + ProcessModuleFlags(); + + if ( Attributes || UnderlyingType ) + { + result.append( "enum " ); if ( Attributes ) result.append_fmt( "%s ", Attributes->to_string() ); - result.append_fmt( "enum %s : %s;", Name, UnderlyingType->to_string() ); - } - break; - - case Enum_Class: - { - ProcessModuleFlags(); - - if ( Attributes || UnderlyingType ) - { - result.append( "enum class " ); - - if ( Attributes ) - { - result.append_fmt( "%s ", Attributes->to_string() ); - } - - if ( UnderlyingType ) - { - result.append_fmt( "%s : %s\n{\n%s\n};" - , Name - , UnderlyingType->to_string() - , Body->to_string() - ); - } - else - { - result.append_fmt( "%s\n{\n%s\n};" - , Name - , Body->to_string() - ); - } - } - else - { - result.append_fmt( "enum class %s\n{\n%s\n};" + if ( UnderlyingType ) + result.append_fmt( "%s : %s\n{\n%s\n};" + , Name + , UnderlyingType->to_string() , Body->to_string() ); - } + + else result.append_fmt( "%s\n{\n%s\n};" + , Name + , Body->to_string() + ); } - break; + else result.append_fmt( "enum %s\n{\n%s\n};" + , Name + , Body->to_string() + ); + } + break; - case Enum_Class_Fwd: + case Enum_Fwd: + { + ProcessModuleFlags(); + + if ( Attributes ) + result.append_fmt( "%s ", Attributes->to_string() ); + + result.append_fmt( "enum %s : %s;", Name, UnderlyingType->to_string() ); + } + break; + + case Enum_Class: + { + ProcessModuleFlags(); + + if ( Attributes || UnderlyingType ) { - ProcessModuleFlags(); - result.append( "enum class " ); - if ( Attributes ) - result.append_fmt( "%s ", Attributes->to_string() ); - - result.append_fmt( "%s : %s;", Name, UnderlyingType->to_string() ); - } - break; - - case Export_Body: - { - result.append_fmt( "export\n{\n" ); - - Code curr = { this }; - s32 left = NumEntries; - while ( left-- ) - { - result.append_fmt( "%s\n", curr.to_string() ); - ++curr; - } - - result.append_fmt( "};" ); - } - break; - - case Extern_Linkage: - result.append_fmt( "extern \"%s\"\n{\n%s\n}" - , Name - , Body->to_string() - ); - break; - - case Friend: - result.append_fmt( "friend %s", Declaration->to_string() ); - - if ( result[ result.length() -1 ] != ';' ) - result.append( ";" ); - break; - - case Function: - { - ProcessModuleFlags(); - - if ( Attributes ) - result.append_fmt( "%s ", Attributes->to_string() ); - - if ( Specs ) - result.append_fmt( "%s\n", Specs->to_string() ); - - if ( ReturnType ) - result.append_fmt( "%s %s(", ReturnType->to_string(), Name ); - - else - result.append_fmt( "%s(", Name ); - - if ( Params ) - result.append_fmt( "%s", Params->to_string() ); - - else - result.append( "void" ); - - result.append_fmt( ")\n{\n%s\n}" - , Body->to_string() - ); - } - break; - - case Function_Fwd: - { - ProcessModuleFlags(); - - if ( Attributes ) - result.append_fmt( "%s ", Attributes->to_string() ); - - if ( Specs ) - result.append_fmt( "%s\n", Specs->to_string() ); - - if ( ReturnType ) - result.append_fmt( "%s %s(", ReturnType->to_string(), Name ); - - else - result.append_fmt( "%s(", Name ); - - if ( Params ) - result.append_fmt( "%s", Params->to_string() ); - - else - result.append( "void" ); - - result.append( ");" ); - } - break; - - case Module: - if (((u32(ModuleFlag::Export) & u32(ModuleFlags)) == u32(ModuleFlag::Export))) - result.append("export "); - - if (((u32(ModuleFlag::Import) & u32(ModuleFlags)) == u32(ModuleFlag::Import))) - result.append("import "); - - result.append_fmt( "%s;", Name ); - break; - - case Namespace: - ProcessModuleFlags(); - - result.append_fmt( "namespace %s\n{\n%s}" - , Name - , Body->to_string() - ); - break; - - case Operator: - case Operator_Member: - { - ProcessModuleFlags(); - - if ( Attributes ) - result.append_fmt( "%s ", Attributes->to_string() ); - - if ( Attributes ) - result.append_fmt( "%s\n", Attributes->to_string() ); - - if ( ReturnType ) - result.append_fmt( "%s %s (", ReturnType->to_string(), Name ); - - if ( Params ) - result.append_fmt( "%s", Params->to_string() ); - - else - result.append( "void" ); - - result.append_fmt( ")\n{\n%s\n}" - , Body->to_string() - ); - } - break; - - case Operator_Fwd: - case Operator_Member_Fwd: - { - ProcessModuleFlags(); - - if ( Attributes ) - result.append_fmt( "%s ", Attributes->to_string() ); - - if ( Specs ) - result.append_fmt( "%s", Specs->to_string() ); - - result.append_fmt( "%s %s (", ReturnType->to_string(), Name ); - - if ( Params ) - result.append_fmt( "%s);", Params->to_string() ); - - else - result.append_fmt( "void);" ); - } - break; - - case Operator_Cast: - { - result.append_fmt("operator %s(){\n%s\n}", ValueType->to_string(), Body->to_string() ); - } - break; - - case Operator_Cast_Fwd: - result.append_fmt("operator %s();", ValueType->to_string() ); - break; - - case Parameters: - { - if ( Name ) - result.append_fmt( "%s %s", ValueType->to_string(), Name ); - - else - result.append_fmt( "%s", ValueType->to_string() ); - - if ( Value ) - result.append_fmt( "= %s", Value->to_string() ); - - if ( NumEntries - 1 > 0) - { - for ( CodeParam param : CodeParam { (AST_Param*) Next } ) - { - result.append_fmt( ", %s", param.to_string() ); - } - } - } - break; - - case Preprocessor_Include: - result.append_fmt( "#include \"%s\"", Name ); - break; - - case Specifiers: - { - s32 idx = 0; - s32 left = NumEntries; - while ( left-- ) - { - result.append_fmt( "%s ", (char const*)ESpecifier::to_str( ArrSpecs[idx]) ); - idx++; - } - } - break; - - case Struct: - { - ProcessModuleFlags(); - - if ( Name == nullptr) - { - result.append( "struct\n{\n%s\n};", Body->to_string() ); - break; - } - - if ( Attributes || ParentType ) - { - result.append( "struct " ); - - if ( Attributes ) - result.append_fmt( "%s ", Attributes->to_string() ); - - if ( ParentType ) - { - char const* access_level = to_str( ParentAccess ); - - result.append_fmt( "%s : %s %s\n{\n%s\n};" - , Name - , access_level - , ParentType->to_string() - , Body->to_string() - ); - } - else - { - if ( Name ) - - result.append_fmt( "%s \n{\n%s\n};", Name, Body->to_string() ); - } - } - else - { - result.append_fmt( "struct %s\n{\n%s\n};", Name, Body->to_string() ); - } - } - break; - - case Struct_Fwd: - { - ProcessModuleFlags(); - - if ( Attributes ) - result.append_fmt( "struct %s %s;", Attributes->to_string(), Name ); - - else result.append_fmt( "struct %s;", Name ); - } - break; - - case Template: - { - ProcessModuleFlags(); - - result.append_fmt( "template< %s >\n%s", Params->to_string(), Declaration->to_string() ); - } - break; - - case Typedef: - { - ProcessModuleFlags(); - - result.append( "typedef "); - if ( Attributes ) { result.append_fmt( "%s ", Attributes->to_string() ); } - result.append_fmt( "%s %s", UnderlyingType->to_string(), Name ); - - if ( UnderlyingType->Type == Typename && UnderlyingType->ArrExpr ) + if ( UnderlyingType ) { - result.append_fmt( "[%s];", UnderlyingType->ArrExpr->to_string() ); + result.append_fmt( "%s : %s\n{\n%s\n};" + , Name + , UnderlyingType->to_string() + , Body->to_string() + ); } else - { - result.append( ";" ); - } - } - break; - - case Typename: - { - if ( Attributes || Specs ) - { - if ( Attributes ) - result.append_fmt( "%s ", Attributes->to_string() ); - - if ( Specs ) - result.append_fmt( "%s %s", Name, Specs->to_string() ); - - else - result.append_fmt( "%s", Name ); - } - else - { - result.append_fmt( "%s", Name ); - } - } - break; - - case Union: - { - ProcessModuleFlags(); - - result.append( "union " ); - - if ( Attributes ) - result.append_fmt( "%s ", Attributes->to_string() ); - - if ( Name ) { result.append_fmt( "%s\n{\n%s\n};" , Name , Body->to_string() ); } - else - { - // Anonymous union - result.append_fmt( "\n{\n%s\n};" - , Body->to_string() - ); - } } + else + { + result.append_fmt( "enum class %s\n{\n%s\n};" + , Body->to_string() + ); + } + } + break; + + case Enum_Class_Fwd: + { + ProcessModuleFlags(); + + result.append( "enum class " ); + + if ( Attributes ) + result.append_fmt( "%s ", Attributes->to_string() ); + + result.append_fmt( "%s : %s;", Name, UnderlyingType->to_string() ); + } + break; + + case Export_Body: + { + result.append_fmt( "export\n{\n" ); + + Code curr = { this }; + s32 left = NumEntries; + while ( left-- ) + { + result.append_fmt( "%s\n", curr.to_string() ); + ++curr; + } + + result.append_fmt( "};" ); + } + break; + + case Extern_Linkage: + result.append_fmt( "extern \"%s\"\n{\n%s\n}" + , Name + , Body->to_string() + ); + break; + + case Friend: + result.append_fmt( "friend %s", Declaration->to_string() ); + + if ( result[ result.length() -1 ] != ';' ) + result.append( ";" ); + break; + + case Function: + { + ProcessModuleFlags(); + + if ( Attributes ) + result.append_fmt( "%s ", Attributes->to_string() ); + + if ( Specs ) + result.append_fmt( "%s\n", Specs->to_string() ); + + if ( ReturnType ) + result.append_fmt( "%s %s(", ReturnType->to_string(), Name ); + + else + result.append_fmt( "%s(", Name ); + + if ( Params ) + result.append_fmt( "%s", Params->to_string() ); + + else + result.append( "void" ); + + result.append_fmt( ")\n{\n%s\n}" + , Body->to_string() + ); + } + break; + + case Function_Fwd: + { + ProcessModuleFlags(); + + if ( Attributes ) + result.append_fmt( "%s ", Attributes->to_string() ); + + if ( Specs ) + result.append_fmt( "%s\n", Specs->to_string() ); + + if ( ReturnType ) + result.append_fmt( "%s %s(", ReturnType->to_string(), Name ); + + else + result.append_fmt( "%s(", Name ); + + if ( Params ) + result.append_fmt( "%s", Params->to_string() ); + + else + result.append( "void" ); + + result.append( ");" ); + } + break; + + case Module: + if (((u32(ModuleFlag::Export) & u32(ModuleFlags)) == u32(ModuleFlag::Export))) + result.append("export "); + + if (((u32(ModuleFlag::Import) & u32(ModuleFlags)) == u32(ModuleFlag::Import))) + result.append("import "); + + result.append_fmt( "%s;", Name ); break; - case Using: + case Namespace: + ProcessModuleFlags(); + + result.append_fmt( "namespace %s\n{\n%s}" + , Name + , Body->to_string() + ); + break; + + case Operator: + case Operator_Member: + { + ProcessModuleFlags(); + + if ( Attributes ) + result.append_fmt( "%s ", Attributes->to_string() ); + + if ( Attributes ) + result.append_fmt( "%s\n", Attributes->to_string() ); + + if ( ReturnType ) + result.append_fmt( "%s %s (", ReturnType->to_string(), Name ); + + if ( Params ) + result.append_fmt( "%s", Params->to_string() ); + + else + result.append( "void" ); + + result.append_fmt( ")\n{\n%s\n}" + , Body->to_string() + ); + } + break; + + case Operator_Fwd: + case Operator_Member_Fwd: + { + ProcessModuleFlags(); + + if ( Attributes ) + result.append_fmt( "%s ", Attributes->to_string() ); + + if ( Specs ) + result.append_fmt( "%s", Specs->to_string() ); + + result.append_fmt( "%s %s (", ReturnType->to_string(), Name ); + + if ( Params ) + result.append_fmt( "%s);", Params->to_string() ); + + else + result.append_fmt( "void);" ); + } + break; + + case Operator_Cast: + { + result.append_fmt("operator %s(){\n%s\n}", ValueType->to_string(), Body->to_string() ); + } + break; + + case Operator_Cast_Fwd: + result.append_fmt("operator %s();", ValueType->to_string() ); + break; + + case Parameters: + { + if ( Name ) + result.append_fmt( "%s %s", ValueType->to_string(), Name ); + + else + result.append_fmt( "%s", ValueType->to_string() ); + + if ( Value ) + result.append_fmt( "= %s", Value->to_string() ); + + if ( NumEntries - 1 > 0) { - ProcessModuleFlags(); + for ( CodeParam param : CodeParam { (AST_Param*) Next } ) + { + result.append_fmt( ", %s", param.to_string() ); + } + } + } + break; + + case Preprocessor_Include: + result.append_fmt( "#include \"%s\"", Name ); + break; + + case Specifiers: + { + s32 idx = 0; + s32 left = NumEntries; + while ( left-- ) + { + result.append_fmt( "%s ", (char const*)ESpecifier::to_str( ArrSpecs[idx]) ); + idx++; + } + } + break; + + case Struct: + { + ProcessModuleFlags(); + + if ( Name == nullptr) + { + result.append( "struct\n{\n%s\n};", Body->to_string() ); + break; + } + + if ( Attributes || ParentType ) + { + result.append( "struct " ); if ( Attributes ) result.append_fmt( "%s ", Attributes->to_string() ); - if ( UnderlyingType ) + if ( ParentType ) { - result.append_fmt( "using %s = %s", Name, UnderlyingType->to_string() ); + char const* access_level = to_str( ParentAccess ); - if ( UnderlyingType->ArrExpr ) - result.append_fmt( "[%s]", UnderlyingType->ArrExpr->to_string() ); - - result.append( ";" ); + result.append_fmt( "%s : %s %s\n{\n%s\n};" + , Name + , access_level + , ParentType->to_string() + , Body->to_string() + ); } else - result.append_fmt( "using %s;", Name ); - } - break; - - case Using_Namespace: - result.append_fmt( "using namespace %s;", Name ); - break; - - case Variable: - { - ProcessModuleFlags(); - - if ( Attributes || Specs ) { - if ( Attributes ) - result.append_fmt( "%s ", Specs->to_string() ); + if ( Name ) - if ( Specs ) - result.append_fmt( "%s\n", Specs->to_string() ); - - result.append_fmt( "%s %s", ValueType->to_string(), Name ); - - if ( ValueType->ArrExpr ) - result.append_fmt( "[%s]", ValueType->ArrExpr->to_string() ); - - if ( Value ) - result.append_fmt( " = %s", Value->to_string() ); - - result.append( ";" ); - - break; + result.append_fmt( "%s \n{\n%s\n};", Name, Body->to_string() ); } + } + else + { + result.append_fmt( "struct %s\n{\n%s\n};", Name, Body->to_string() ); + } + } + break; + + case Struct_Fwd: + { + ProcessModuleFlags(); + + if ( Attributes ) + result.append_fmt( "struct %s %s;", Attributes->to_string(), Name ); + + else result.append_fmt( "struct %s;", Name ); + } + break; + + case Template: + { + ProcessModuleFlags(); + + result.append_fmt( "template< %s >\n%s", Params->to_string(), Declaration->to_string() ); + } + break; + + case Typedef: + { + ProcessModuleFlags(); + + result.append( "typedef "); + + if ( Attributes ) + { + result.append_fmt( "%s ", Attributes->to_string() ); + } + + result.append_fmt( "%s %s", UnderlyingType->to_string(), Name ); + + if ( UnderlyingType->Type == Typename && UnderlyingType->ArrExpr ) + { + result.append_fmt( "[%s];", UnderlyingType->ArrExpr->to_string() ); + } + else + { + result.append( ";" ); + } + } + break; + + case Typename: + { + if ( Attributes || Specs ) + { + if ( Attributes ) + result.append_fmt( "%s ", Attributes->to_string() ); + + if ( Specs ) + result.append_fmt( "%s %s", Name, Specs->to_string() ); + + else + result.append_fmt( "%s", Name ); + } + else + { + result.append_fmt( "%s", Name ); + } + } + break; + + case Union: + { + ProcessModuleFlags(); + + result.append( "union " ); + + if ( Attributes ) + result.append_fmt( "%s ", Attributes->to_string() ); + + if ( Name ) + { + result.append_fmt( "%s\n{\n%s\n};" + , Name + , Body->to_string() + ); + } + else + { + // Anonymous union + result.append_fmt( "\n{\n%s\n};" + , Body->to_string() + ); + } + } + break; + + case Using: + { + ProcessModuleFlags(); + + if ( Attributes ) + result.append_fmt( "%s ", Attributes->to_string() ); + + if ( UnderlyingType ) + { + result.append_fmt( "using %s = %s", Name, UnderlyingType->to_string() ); if ( UnderlyingType->ArrExpr ) - result.append_fmt( "%s %s[%s];", UnderlyingType->to_string(), Name, UnderlyingType->ArrExpr->to_string() ); + result.append_fmt( "[%s]", UnderlyingType->ArrExpr->to_string() ); - else - result.append_fmt( "%s %s;", UnderlyingType->to_string(), Name ); + result.append( ";" ); } - break; - - case Class_Body: - case Enum_Body: - case Extern_Linkage_Body: - case Function_Body: - case Global_Body: - case Namespace_Body: - case Struct_Body: - case Union_Body: - { - Code curr = Front->cast(); - s32 left = NumEntries; - while ( left -- ) - { - result.append_fmt( "%s\n", curr.to_string() ); - ++curr; - } - } - break; + else + result.append_fmt( "using %s;", Name ); } + break; - #if defined(GEN_BENCHMARK) && defined(GEN_BENCHMARK_SERIALIZATION) - log_fmt("AST::to_string() time taken: %llu for: %s\n", time_rel_ms() - time_start, result ); - #endif - return result; - #undef ProcessModuleFlags + case Using_Namespace: + result.append_fmt( "using namespace %s;", Name ); + break; + + case Variable: + { + ProcessModuleFlags(); + + if ( Attributes || Specs ) + { + if ( Attributes ) + result.append_fmt( "%s ", Specs->to_string() ); + + if ( Specs ) + result.append_fmt( "%s\n", Specs->to_string() ); + + result.append_fmt( "%s %s", ValueType->to_string(), Name ); + + if ( ValueType->ArrExpr ) + result.append_fmt( "[%s]", ValueType->ArrExpr->to_string() ); + + if ( Value ) + result.append_fmt( " = %s", Value->to_string() ); + + result.append( ";" ); + + break; + } + + if ( UnderlyingType->ArrExpr ) + result.append_fmt( "%s %s[%s];", UnderlyingType->to_string(), Name, UnderlyingType->ArrExpr->to_string() ); + + else + result.append_fmt( "%s %s;", UnderlyingType->to_string(), Name ); + } + break; + + case Class_Body: + case Enum_Body: + case Extern_Linkage_Body: + case Function_Body: + case Global_Body: + case Namespace_Body: + case Struct_Body: + case Union_Body: + { + Code curr = Front->cast(); + s32 left = NumEntries; + while ( left -- ) + { + result.append_fmt( "%s\n", curr.to_string() ); + ++curr; + } + } + break; } - bool AST::is_equal( AST* other ) - { - if ( Type != other->Type ) - return false; - - switch ( Type ) - { - case ECode::Typedef: - case ECode::Typename: - { - if ( Name != other->Name ) - return false; - - return true; - } - } - - if ( Name != other->Name ) - return false; - - return true; - } - - bool AST::validate_body() - { - using namespace ECode; - - #define CheckEntries( Unallowed_Types ) \ - do \ - { \ - for ( Code entry : cast() ) \ - { \ - switch ( entry->Type ) \ - { \ - Unallowed_Types \ - log_failure( "AST::validate_body: Invalid entry in body %s", entry.debug_str() ); \ - return false; \ - } \ - } \ - } \ - while (0); - - switch ( Type ) - { - case Class_Body: - CheckEntries( AST_BODY_CLASS_UNALLOWED_TYPES ); - break; - case Enum_Body: - for ( Code entry : cast() ) - { - if ( entry->Type != Untyped ) - { - log_failure( "AST::validate_body: Invalid entry in enum body (needs to be untyped or comment) %s", entry.debug_str() ); - return false; - } - } - break; - case Export_Body: - CheckEntries( AST_BODY_CLASS_UNALLOWED_TYPES ); - break; - case Extern_Linkage: - CheckEntries( AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES ); - break; - case Function_Body: - CheckEntries( AST_BODY_FUNCTION_UNALLOWED_TYPES ); - break; - case Global_Body: - CheckEntries( AST_BODY_GLOBAL_UNALLOWED_TYPES ); - break; - case Namespace_Body: - CheckEntries( AST_BODY_NAMESPACE_UNALLOWED_TYPES ); - break; - case Struct_Body: - CheckEntries( AST_BODY_STRUCT_UNALLOWED_TYPES ); - break; - case Union_Body: - for ( Code entry : Body->cast() ) - { - if ( entry->Type != Untyped ) - { - log_failure( "AST::validate_body: Invalid entry in union body (needs to be untyped or comment) %s", entry.debug_str() ); - return false; - } - } - break; - - default: - log_failure( "AST::validate_body: Invalid this AST does not have a body %s", debug_str() ); - return false; - } +#if defined(GEN_BENCHMARK) && defined(GEN_BENCHMARK_SERIALIZATION) + log_fmt("AST::to_string() time taken: %llu for: %s\n", time_rel_ms() - time_start, result ); +#endif + return result; +#undef ProcessModuleFlags +} +bool AST::is_equal( AST* other ) +{ + if ( Type != other->Type ) return false; + + switch ( Type ) + { + case ECode::Typedef: + case ECode::Typename: + { + if ( Name != other->Name ) + return false; + + return true; + } } + + if ( Name != other->Name ) + return false; + + return true; +} + +bool AST::validate_body() +{ + using namespace ECode; + +#define CheckEntries( Unallowed_Types ) \ + do \ + { \ + for ( Code entry : cast() ) \ + { \ + switch ( entry->Type ) \ + { \ + Unallowed_Types \ + log_failure( "AST::validate_body: Invalid entry in body %s", entry.debug_str() ); \ + return false; \ + } \ + } \ + } \ + while (0); + + switch ( Type ) + { + case Class_Body: + CheckEntries( AST_BODY_CLASS_UNALLOWED_TYPES ); + break; + case Enum_Body: + for ( Code entry : cast() ) + { + if ( entry->Type != Untyped ) + { + log_failure( "AST::validate_body: Invalid entry in enum body (needs to be untyped or comment) %s", entry.debug_str() ); + return false; + } + } + break; + case Export_Body: + CheckEntries( AST_BODY_CLASS_UNALLOWED_TYPES ); + break; + case Extern_Linkage: + CheckEntries( AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES ); + break; + case Function_Body: + CheckEntries( AST_BODY_FUNCTION_UNALLOWED_TYPES ); + break; + case Global_Body: + CheckEntries( AST_BODY_GLOBAL_UNALLOWED_TYPES ); + break; + case Namespace_Body: + CheckEntries( AST_BODY_NAMESPACE_UNALLOWED_TYPES ); + break; + case Struct_Body: + CheckEntries( AST_BODY_STRUCT_UNALLOWED_TYPES ); + break; + case Union_Body: + for ( Code entry : Body->cast() ) + { + if ( entry->Type != Untyped ) + { + log_failure( "AST::validate_body: Invalid entry in union body (needs to be untyped or comment) %s", entry.debug_str() ); + return false; + } + } + break; + + default: + log_failure( "AST::validate_body: Invalid this AST does not have a body %s", debug_str() ); + return false; + } + + return false; +} #pragma endregion AST #pragma region Gen Interface - internal void* Global_Allocator_Proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ) - { - Arena* last = & Global_AllocatorBuckets.back(); +internal void* Global_Allocator_Proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags ) +{ + Arena* last = & Global_AllocatorBuckets.back(); - switch ( type ) + switch ( type ) + { + case EAllocation_ALLOC: { - case EAllocation_ALLOC: + if ( ( last->TotalUsed + size ) > last->TotalSize ) { - if ( ( last->TotalUsed + size ) > last->TotalSize ) - { - Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); + Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); - if ( bucket.PhysicalStart == nullptr ) - fatal( "Failed to create bucket for Global_AllocatorBuckets"); + if ( bucket.PhysicalStart == nullptr ) + fatal( "Failed to create bucket for Global_AllocatorBuckets"); - if ( ! Global_AllocatorBuckets.append( bucket ) ) - fatal( "Failed to append bucket to Global_AllocatorBuckets"); + if ( ! Global_AllocatorBuckets.append( bucket ) ) + fatal( "Failed to append bucket to Global_AllocatorBuckets"); - last = & Global_AllocatorBuckets.back(); - } - - return alloc_align( * last, size, alignment ); + last = & Global_AllocatorBuckets.back(); } - case EAllocation_FREE: + + return alloc_align( * last, size, alignment ); + } + case EAllocation_FREE: + { + // Doesn't recycle. + } + break; + case EAllocation_FREE_ALL: + { + // Memory::cleanup instead. + } + break; + case EAllocation_RESIZE: + { + if ( last->TotalUsed + size > last->TotalSize ) { - // Doesn't recycle. + Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); + + if ( bucket.PhysicalStart == nullptr ) + fatal( "Failed to create bucket for Global_AllocatorBuckets"); + + if ( ! Global_AllocatorBuckets.append( bucket ) ) + fatal( "Failed to append bucket to Global_AllocatorBuckets"); + + last = & Global_AllocatorBuckets.back(); } - break; - case EAllocation_FREE_ALL: + + void* result = alloc_align( last->Backing, size, alignment ); + + if ( result != nullptr && old_memory != nullptr ) { - // Memory::cleanup instead. + mem_copy( result, old_memory, old_size ); } - break; - case EAllocation_RESIZE: + + return result; + } + } + + return nullptr; +} + +internal void define_constants() +{ + Code::Global = make_code(); + Code::Global->Name = get_cached_string( txt_StrC("Global Code") ); + Code::Global->Content = Code::Global->Name; + + Code::Invalid = make_code(); + Code::Invalid.set_global(); + +# define def_constant_code_type( Type_ ) \ + t_##Type_ = def_type( name(Type_) ); \ + t_##Type_.set_global(); + + def_constant_code_type( auto ); + def_constant_code_type( void ); + def_constant_code_type( int ); + def_constant_code_type( bool ); + def_constant_code_type( char ); + def_constant_code_type( wchar_t ); + def_constant_code_type( class ); + def_constant_code_type( typename ); + +#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS + t_b32 = def_type( name(b32) ); + + def_constant_code_type( s8 ); + def_constant_code_type( s16 ); + def_constant_code_type( s32 ); + def_constant_code_type( s64 ); + + def_constant_code_type( u8 ); + def_constant_code_type( u16 ); + def_constant_code_type( u32 ); + def_constant_code_type( u64 ); + + def_constant_code_type( sw ); + def_constant_code_type( uw ); + + def_constant_code_type( f32 ); + def_constant_code_type( f64 ); +#endif +# undef def_constant_code_type + + access_private = make_code(); + access_private->Type = ECode::Access_Private; + access_private->Name = get_cached_string( txt_StrC("private:") ); + access_private.set_global(); + + access_protected = make_code(); + access_protected->Type = ECode::Access_Protected; + access_protected->Name = get_cached_string( txt_StrC("protected:") ); + access_protected.set_global(); + + access_public = make_code(); + access_public->Type = ECode::Access_Public; + access_public->Name = get_cached_string( txt_StrC("public:") ); + access_public.set_global(); + + module_global_fragment = make_code(); + module_global_fragment->Type = ECode::Untyped; + module_global_fragment->Name = get_cached_string( txt_StrC("module;") ); + module_global_fragment->Content = module_global_fragment->Name; + module_global_fragment.set_global(); + + module_private_fragment = make_code(); + module_private_fragment->Type = ECode::Untyped; + module_private_fragment->Name = get_cached_string( txt_StrC("module : private;") ); + module_private_fragment->Content = module_private_fragment->Name; + module_private_fragment.set_global(); + + pragma_once = make_code(); + pragma_once->Type = ECode::Untyped; + pragma_once->Name = get_cached_string( txt_StrC("#pragma once") ); + pragma_once->Content = pragma_once->Name; + pragma_once.set_global(); + +# pragma push_macro( "global" ) +# pragma push_macro( "internal" ) +# pragma push_macro( "local_persist" ) +# undef global +# undef internal +# undef local_persist + +# define def_constant_spec( Type_, ... ) \ + spec_##Type_ = def_specifiers( num_args(__VA_ARGS__), __VA_ARGS__); \ + spec_##Type_.set_global(); + + def_constant_spec( const, ESpecifier::Const ); + def_constant_spec( consteval, ESpecifier::Consteval ); + def_constant_spec( constexpr, ESpecifier::Constexpr ); + def_constant_spec( constinit, ESpecifier::Constinit ); + def_constant_spec( extern_linkage, ESpecifier::External_Linkage ); + def_constant_spec( global, ESpecifier::Global ); + def_constant_spec( inline, ESpecifier::Inline ); + def_constant_spec( internal_linkage, ESpecifier::Internal_Linkage ); + def_constant_spec( local_persist, ESpecifier::Local_Persist ); + def_constant_spec( mutable, ESpecifier::Mutable ); + def_constant_spec( ptr, ESpecifier::Ptr ); + def_constant_spec( ref, ESpecifier::Ref ); + def_constant_spec( register, ESpecifier::Register ); + def_constant_spec( rvalue, ESpecifier::RValue ); + def_constant_spec( static_member, ESpecifier::Static ); + def_constant_spec( thread_local, ESpecifier::Thread_Local ); + def_constant_spec( volatile, ESpecifier::Volatile) + + spec_local_persist = def_specifiers( 1, ESpecifier::Local_Persist ); + spec_local_persist.set_global(); + +# pragma pop_macro( "global" ) +# pragma pop_macro( "internal" ) +# pragma pop_macro( "local_persist" ) + +# undef def_constant_spec +} + +void init() +{ + // Setup global allocator + { + GlobalAllocator = AllocatorInfo { & Global_Allocator_Proc, nullptr }; + + Global_AllocatorBuckets = Array::init_reserve( heap(), 128 ); + + if ( Global_AllocatorBuckets == nullptr ) + fatal( "Failed to reserve memory for Global_AllocatorBuckets"); + + Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); + + if ( bucket.PhysicalStart == nullptr ) + fatal( "Failed to create first bucket for Global_AllocatorBuckets"); + + Global_AllocatorBuckets.append( bucket ); + + } + + // Setup the arrays + { + CodePools = Array::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); + + if ( CodePools == nullptr ) + fatal( "gen::init: Failed to initialize the CodePools array" ); + + StringArenas = Array::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); + + if ( StringArenas == nullptr ) + fatal( "gen::init: Failed to initialize the StringArenas array" ); + } + + // Setup the code pool and code entries arena. + { + Pool code_pool = Pool::init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); + + if ( code_pool.PhysicalStart == nullptr ) + fatal( "gen::init: Failed to initialize the code pool" ); + + CodePools.append( code_pool ); + + LexArena = Arena::init_from_allocator( Allocator_Lexer, LexAllocator_Size ); + + Arena string_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena ); + + if ( string_arena.PhysicalStart == nullptr ) + fatal( "gen::init: Failed to initialize the string arena" ); + + StringArenas.append( string_arena ); + } + + // Setup the hash tables + { + StringCache = StringTable::init( Allocator_StringTable ); + + if ( StringCache.Entries == nullptr ) + fatal( "gen::init: Failed to initialize the StringCache"); + } + + define_constants(); +} + +void deinit() +{ + uw index = 0; + uw left = CodePools.num(); + do + { + Pool* code_pool = & CodePools[index]; + code_pool->free(); + index++; + } + while ( left--, left ); + + index = 0; + left = StringArenas.num(); + do + { + Arena* string_arena = & StringArenas[index]; + string_arena->free(); + index++; + } + while ( left--, left ); + + StringCache.destroy(); + + CodePools.free(); + StringArenas.free(); + + LexArena.free(); + + index = 0; + left = Global_AllocatorBuckets.num(); + do + { + Arena* bucket = & Global_AllocatorBuckets[ index ]; + bucket->free(); + index++; + } + while ( left--, left ); + + Global_AllocatorBuckets.free(); +} + +void reset() +{ + s32 index = 0; + s32 left = CodePools.num(); + do + { + Pool* code_pool = & CodePools[index]; + code_pool->clear(); + index++; + } + while ( left--, left ); + + index = 0; + left = StringArenas.num(); + do + { + Arena* string_arena = & StringArenas[index]; + string_arena->TotalUsed = 0;; + index++; + } + while ( left--, left ); + + StringCache.clear(); + + define_constants(); +} + +AllocatorInfo get_string_allocator( s32 str_length ) +{ + Arena* last = & StringArenas.back(); + + uw size_req = str_length + sizeof(String::Header) + sizeof(char*); + + if ( last->TotalUsed + size_req > last->TotalSize ) + { + Arena new_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena ); + + if ( ! StringArenas.append( new_arena ) ) + fatal( "gen::get_string_allocator: Failed to allocate a new string arena" ); + + last = & StringArenas.back(); + } + + return * last; +} + +// Will either make or retrive a code string. +StringCached get_cached_string( StrC str ) +{ + s32 hash_length = str.Len > kilobytes(1) ? kilobytes(1) : str.Len; + u64 key = crc32( str.Ptr, hash_length ); + { + StringCached* result = StringCache.get( key ); + + if ( result ) + return * result; + } + + String result = String::make( get_string_allocator( str.Len ), str ); + + StringCache.set( key, result ); + + return result; +} + +/* + Used internally to retireve a Code object form the CodePool. +*/ +Code make_code() +{ + Pool* allocator = & CodePools.back(); + if ( allocator->FreeList == nullptr ) + { + Pool code_pool = Pool::init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); + + if ( code_pool.PhysicalStart == nullptr ) + fatal( "gen::make_code: Failed to allocate a new code pool - CodePool allcoator returned nullptr." ); + + if ( ! CodePools.append( code_pool ) ) + fatal( "gen::make_code: Failed to allocate a new code pool - CodePools failed to append new pool." ); + + allocator = & CodePools.back(); + } + + Code result { rcast( AST*, alloc( * allocator, sizeof(AST) )) }; + + result->Content = { nullptr }; + result->Prev = { nullptr }; + result->Next = { nullptr }; + result->Parent = { nullptr }; + result->Name = { nullptr }; + result->Type = ECode::Invalid; + result->ModuleFlags = ModuleFlag::Invalid; + result->NumEntries = 0; + + return result; +} + +enum class OpValidateResult : u32 +{ + Fail, + Global, + Member +}; + +inline +OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeType ret_type, CodeSpecifier specifier ) +{ + using namespace EOperator; + + if ( op == EOperator::Invalid ) + { + log_failure("gen::def_operator: op cannot be invalid"); + return OpValidateResult::Fail; + } + +#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 OpValidateResult::Fail; \ + } \ + if ( params_code->Type != ECode::Parameters ) \ + { \ + log_failure("gen::def_operator: params is not of Parameters type - %s", params_code.debug_str()); \ + return OpValidateResult::Fail; \ + } + +# define check_param_eq_ret() \ + if ( ! is_member_symbol && params_code->ValueType != 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 OpValidateResult::Fail; \ + } +#pragma endregion Helper Macros + + 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 OpValidateResult::Fail; + } + + bool is_member_symbol = false; + + switch ( op ) + { + # define specs( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__ + case Assign: + check_params(); + + if ( params_code->NumEntries > 1 ) { - if ( last->TotalUsed + size > last->TotalSize ) - { - Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); - - if ( bucket.PhysicalStart == nullptr ) - fatal( "Failed to create bucket for Global_AllocatorBuckets"); - - if ( ! Global_AllocatorBuckets.append( bucket ) ) - fatal( "Failed to append bucket to Global_AllocatorBuckets"); - - last = & Global_AllocatorBuckets.back(); - } - - void* result = alloc_align( last->Backing, size, alignment ); - - if ( result != nullptr && old_memory != nullptr ) - { - mem_copy( result, old_memory, old_size ); - } - - return result; + 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 OpValidateResult::Fail; } - } - - return nullptr; - } - - internal void define_constants() - { - Code::Global = make_code(); - Code::Global->Name = get_cached_string( txt_StrC("Global Code") ); - Code::Global->Content = Code::Global->Name; - - Code::Invalid = make_code(); - Code::Invalid.set_global(); - - # define def_constant_code_type( Type_ ) \ - t_##Type_ = def_type( name(Type_) ); \ - t_##Type_.set_global(); - - def_constant_code_type( auto ); - def_constant_code_type( void ); - def_constant_code_type( int ); - def_constant_code_type( bool ); - def_constant_code_type( char ); - def_constant_code_type( wchar_t ); - def_constant_code_type( class ); - def_constant_code_type( typename ); - - #ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS - t_b32 = def_type( name(b32) ); - - def_constant_code_type( s8 ); - def_constant_code_type( s16 ); - def_constant_code_type( s32 ); - def_constant_code_type( s64 ); - - def_constant_code_type( u8 ); - def_constant_code_type( u16 ); - def_constant_code_type( u32 ); - def_constant_code_type( u64 ); - - def_constant_code_type( sw ); - def_constant_code_type( uw ); - - def_constant_code_type( f32 ); - def_constant_code_type( f64 ); - #endif - # undef def_constant_code_type - - access_private = make_code(); - access_private->Type = ECode::Access_Private; - access_private->Name = get_cached_string( txt_StrC("private:") ); - access_private.set_global(); - - access_protected = make_code(); - access_protected->Type = ECode::Access_Protected; - access_protected->Name = get_cached_string( txt_StrC("protected:") ); - access_protected.set_global(); - - access_public = make_code(); - access_public->Type = ECode::Access_Public; - access_public->Name = get_cached_string( txt_StrC("public:") ); - access_public.set_global(); - - module_global_fragment = make_code(); - module_global_fragment->Type = ECode::Untyped; - module_global_fragment->Name = get_cached_string( txt_StrC("module;") ); - module_global_fragment->Content = module_global_fragment->Name; - module_global_fragment.set_global(); - - module_private_fragment = make_code(); - module_private_fragment->Type = ECode::Untyped; - module_private_fragment->Name = get_cached_string( txt_StrC("module : private;") ); - module_private_fragment->Content = module_private_fragment->Name; - module_private_fragment.set_global(); - - pragma_once = make_code(); - pragma_once->Type = ECode::Untyped; - pragma_once->Name = get_cached_string( txt_StrC("#pragma once") ); - pragma_once->Content = pragma_once->Name; - pragma_once.set_global(); - - # pragma push_macro( "global" ) - # pragma push_macro( "internal" ) - # pragma push_macro( "local_persist" ) - # define global global - # define internal internal - # define local_persist local_persist - - # define def_constant_spec( Type_, ... ) \ - spec_##Type_ = def_specifiers( num_args(__VA_ARGS__), __VA_ARGS__); \ - spec_##Type_.set_global(); - - def_constant_spec( const, ESpecifier::Const ); - def_constant_spec( consteval, ESpecifier::Consteval ); - def_constant_spec( constexpr, ESpecifier::Constexpr ); - def_constant_spec( constinit, ESpecifier::Constinit ); - def_constant_spec( extern_linkage, ESpecifier::External_Linkage ); - def_constant_spec( global, ESpecifier::Global ); - def_constant_spec( inline, ESpecifier::Inline ); - def_constant_spec( internal_linkage, ESpecifier::Internal_Linkage ); - def_constant_spec( local_persist, ESpecifier::Local_Persist ); - def_constant_spec( mutable, ESpecifier::Mutable ); - def_constant_spec( ptr, ESpecifier::Ptr ); - def_constant_spec( ref, ESpecifier::Ref ); - def_constant_spec( register, ESpecifier::Register ); - def_constant_spec( rvalue, ESpecifier::RValue ); - def_constant_spec( static_member, ESpecifier::Static ); - def_constant_spec( thread_local, ESpecifier::Thread_Local ); - def_constant_spec( volatile, ESpecifier::Volatile) - - spec_local_persist = def_specifiers( 1, ESpecifier::Local_Persist ); - spec_local_persist.set_global(); - - # pragma pop_macro( "global" ) - # pragma pop_macro( "internal" ) - # pragma pop_macro( "local_persist" ) - - # undef def_constant_spec - } - - void init() - { - // Setup global allocator - { - GlobalAllocator = AllocatorInfo { & Global_Allocator_Proc, nullptr }; - - Global_AllocatorBuckets = Array::init_reserve( heap(), 128 ); - - if ( Global_AllocatorBuckets == nullptr ) - fatal( "Failed to reserve memory for Global_AllocatorBuckets"); - - Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize ); - - if ( bucket.PhysicalStart == nullptr ) - fatal( "Failed to create first bucket for Global_AllocatorBuckets"); - - Global_AllocatorBuckets.append( bucket ); - - } - - // Setup the arrays - { - CodePools = Array::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); - - if ( CodePools == nullptr ) - fatal( "gen::init: Failed to initialize the CodePools array" ); - - StringArenas = Array::init_reserve( Allocator_DataArrays, InitSize_DataArrays ); - - if ( StringArenas == nullptr ) - fatal( "gen::init: Failed to initialize the StringArenas array" ); - } - - // Setup the code pool and code entries arena. - { - Pool code_pool = Pool::init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); - - if ( code_pool.PhysicalStart == nullptr ) - fatal( "gen::init: Failed to initialize the code pool" ); - - CodePools.append( code_pool ); - - LexArena = Arena::init_from_allocator( Allocator_Lexer, LexAllocator_Size ); - - Arena string_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena ); - - if ( string_arena.PhysicalStart == nullptr ) - fatal( "gen::init: Failed to initialize the string arena" ); - - StringArenas.append( string_arena ); - } - - // Setup the hash tables - { - StringCache = StringTable::init( Allocator_StringTable ); - - if ( StringCache.Entries == nullptr ) - fatal( "gen::init: Failed to initialize the StringCache"); - } - - define_constants(); - } - - void deinit() - { - uw index = 0; - uw left = CodePools.num(); - do - { - Pool* code_pool = & CodePools[index]; - code_pool->free(); - index++; - } - while ( left--, left ); - - index = 0; - left = StringArenas.num(); - do - { - Arena* string_arena = & StringArenas[index]; - string_arena->free(); - index++; - } - while ( left--, left ); - - StringCache.destroy(); - - CodePools.free(); - StringArenas.free(); - - LexArena.free(); - - index = 0; - left = Global_AllocatorBuckets.num(); - do - { - Arena* bucket = & Global_AllocatorBuckets[ index ]; - bucket->free(); - index++; - } - while ( left--, left ); - - Global_AllocatorBuckets.free(); - } - - void reset() - { - s32 index = 0; - s32 left = CodePools.num(); - do - { - Pool* code_pool = & CodePools[index]; - code_pool->clear(); - index++; - } - while ( left--, left ); - - index = 0; - left = StringArenas.num(); - do - { - Arena* string_arena = & StringArenas[index]; - string_arena->TotalUsed = 0;; - index++; - } - while ( left--, left ); - - StringCache.clear(); - - define_constants(); - } - - AllocatorInfo get_string_allocator( s32 str_length ) - { - Arena* last = & StringArenas.back(); - - uw size_req = str_length + sizeof(String::Header) + sizeof(char*); - - if ( last->TotalUsed + size_req > last->TotalSize ) - { - Arena new_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena ); - - if ( ! StringArenas.append( new_arena ) ) - fatal( "gen::get_string_allocator: Failed to allocate a new string arena" ); - - last = & StringArenas.back(); - } - - return * last; - } - - // Will either make or retrive a code string. - StringCached get_cached_string( StrC str ) - { - s32 hash_length = str.Len > kilobytes(1) ? kilobytes(1) : str.Len; - u64 key = crc32( str.Ptr, hash_length ); - { - StringCached* result = StringCache.get( key ); - - if ( result ) - return * result; - } - - String result = String::make( get_string_allocator( str.Len ), str ); - - StringCache.set( key, result ); - - return result; - } - - /* - Used internally to retireve a Code object form the CodePool. - */ - Code make_code() - { - Pool* allocator = & CodePools.back(); - if ( allocator->FreeList == nullptr ) - { - Pool code_pool = Pool::init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); - - if ( code_pool.PhysicalStart == nullptr ) - fatal( "gen::make_code: Failed to allocate a new code pool - CodePool allcoator returned nullptr." ); - - if ( ! CodePools.append( code_pool ) ) - fatal( "gen::make_code: Failed to allocate a new code pool - CodePools failed to append new pool." ); - - allocator = & CodePools.back(); - } - - Code result { rcast( AST*, alloc( * allocator, sizeof(AST) )) }; - - result->Content = { nullptr }; - result->Prev = { nullptr }; - result->Next = { nullptr }; - result->Parent = { nullptr }; - result->Name = { nullptr }; - result->Type = ECode::Invalid; - result->ModuleFlags = ModuleFlag::Invalid; - result->NumEntries = 0; - - return result; - } - - enum class OpValidateResult : u32 - { - Fail, - Global, - Member - }; - - inline - OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeType ret_type, CodeSpecifier specifier ) - { - using namespace EOperator; - - if ( op == EOperator::Invalid ) - { - log_failure("gen::def_operator: op cannot be invalid"); - return OpValidateResult::Fail; - } - - #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 OpValidateResult::Fail; \ - } \ - if ( params_code->Type != ECode::Parameters ) \ - { \ - log_failure("gen::def_operator: params is not of Parameters type - %s", params_code.debug_str()); \ - return OpValidateResult::Fail; \ - } - - # define check_param_eq_ret() \ - if ( ! is_member_symbol && params_code->ValueType != 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 OpValidateResult::Fail; \ - } - #pragma endregion Helper Macros - - 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 OpValidateResult::Fail; - } - - bool is_member_symbol = false; - - switch ( op ) - { - # define specs( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__ - case Assign: - check_params(); - - if ( params_code->NumEntries > 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 OpValidateResult::Fail; - } + is_member_symbol = true; + break; + + case Assign_Add: + case Assign_Subtract: + case Assign_Multiply: + case Assign_Divide: + case Assign_Modulo: + case Assign_BAnd: + case Assign_BOr: + case Assign_BXOr: + case Assign_LShift: + case Assign_RShift: + check_params(); + + if ( params_code->NumEntries == 1 ) is_member_symbol = true; - break; - case Assign_Add: - case Assign_Subtract: - case Assign_Multiply: - case Assign_Divide: - case Assign_Modulo: - case Assign_BAnd: - case Assign_BOr: - case Assign_BXOr: - case Assign_LShift: - case Assign_RShift: - check_params(); + else + check_param_eq_ret(); - if ( params_code->NumEntries == 1 ) - is_member_symbol = true; + if (params_code->NumEntries > 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->NumEntries + , params_code.debug_str() + ); + return OpValidateResult::Fail; + } + break; - else - check_param_eq_ret(); - - if (params_code->NumEntries > 2 ) + case Increment: + case Decrement: + // 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 may not be defined with more than two parametes - param count; %d\n%s" + log_failure("gen::def_operator: operator%s params code provided is not of Parameters type - %s" , to_str(op) - , params_code->NumEntries , params_code.debug_str() ); return OpValidateResult::Fail; } - break; - case Increment: - case Decrement: - // If its not set, it just means its a prefix member op. - if ( params_code ) + switch ( params_code->NumEntries ) { - 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 OpValidateResult::Fail; - } + case 1: + if ( params_code->ValueType.is_equal( t_int ) ) + is_member_symbol = true; - switch ( params_code->NumEntries ) - { - case 1: - if ( params_code->ValueType.is_equal( t_int ) ) - is_member_symbol = true; - - else - check_param_eq_ret(); - break; - - case 2: + else check_param_eq_ret(); + break; - if ( ! params_code.get(1).is_equal( t_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 OpValidateResult::Fail; - } - break; + case 2: + check_param_eq_ret(); - default: - log_failure("gen::def_operator: operator%s recieved unexpected number of parameters recived %d instead of 0-2" - , to_str(op) - , params_code->NumEntries + if ( ! params_code.get(1).is_equal( t_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 OpValidateResult::Fail; - } - } - break; + } + break; - case Unary_Plus: - case Unary_Minus: - case BNot: - 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()); + default: + log_failure("gen::def_operator: operator%s recieved unexpected number of parameters recived %d instead of 0-2" + , to_str(op) + , params_code->NumEntries + ); return OpValidateResult::Fail; - } + } + } + break; - if ( params_code->ValueType.is_equal( ret_type ) ) + case Unary_Plus: + case Unary_Minus: + case BNot: + 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 OpValidateResult::Fail; + } + + if ( params_code->ValueType.is_equal( 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 OpValidateResult::Fail; + } + + if ( params_code->NumEntries > 1 ) + { + log_failure("gen::def_operator: operator%s may not have more than one parameter - param count: %d" + , to_str(op) + , params_code->NumEntries + ); + return OpValidateResult::Fail; + } + } + break; + + case Add: + case Subtract: + case Multiply: + case Divide: + case Modulo: + case BAnd: + case BOr: + case BXOr: + case LShift: + case RShift: + check_params(); + + switch ( params_code->NumEntries ) + { + case 1: + is_member_symbol = true; + break; + + case 2: + if ( ! params_code->ValueType.is_equal( ret_type ) ) { log_failure("gen::def_operator: " "operator%s is non-member symbol yet first paramter does not equal return type\n" @@ -1652,123 +1694,30 @@ namespace gen ); return OpValidateResult::Fail; } + break; - if ( params_code->NumEntries > 1 ) - { - log_failure("gen::def_operator: operator%s may not have more than one parameter - param count: %d" - , to_str(op) - , params_code->NumEntries - ); - return OpValidateResult::Fail; - } - } - break; - - case Add: - case Subtract: - case Multiply: - case Divide: - case Modulo: - case BAnd: - case BOr: - case BXOr: - case LShift: - case RShift: - check_params(); - - switch ( params_code->NumEntries ) - { - case 1: - is_member_symbol = true; - break; - - case 2: - if ( ! params_code->ValueType.is_equal( 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 OpValidateResult::Fail; - } - 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->NumEntries - ); - return OpValidateResult::Fail; - } - break; - - case UnaryNot: - 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 OpValidateResult::Fail; - } - - if ( params_code->NumEntries != 1 ) - { - log_failure("gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 0-1" - , to_str(op) - , params_code->NumEntries - ); - return OpValidateResult::Fail; - } - } - - if ( ! ret_type.is_equal( t_bool )) - { - log_failure("gen::def_operator: operator%s return type must be of type bool - %s" + default: + log_failure("gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 0-2" , to_str(op) - , ret_type.debug_str() + , params_code->NumEntries ); return OpValidateResult::Fail; - } - break; + } + break; - case LAnd: - case LOr: - case LEqual: - case LNot: - case Lesser: - case Greater: - case LesserEqual: - case GreaterEqual: - check_params(); + case UnaryNot: + if ( ! params_code ) + is_member_symbol = true; - switch ( params_code->NumEntries ) + else + { + if ( params_code->Type != ECode::Parameters ) { - 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->NumEntries - ); - return OpValidateResult::Fail; + log_failure("gen::def_operator: params is not of Parameters type - %s", params_code.debug_str()); + return OpValidateResult::Fail; } - break; - case Indirection: - case AddressOf: - case MemberOfPointer: - if ( params_code && params_code->NumEntries > 1) + if ( params_code->NumEntries != 1 ) { log_failure("gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 0-1" , to_str(op) @@ -1776,1297 +1725,1361 @@ namespace gen ); return OpValidateResult::Fail; } - else - { + } + + if ( ! ret_type.is_equal( t_bool )) + { + log_failure("gen::def_operator: operator%s return type must be of type bool - %s" + , to_str(op) + , ret_type.debug_str() + ); + return OpValidateResult::Fail; + } + break; + + case LAnd: + case LOr: + case LEqual: + case LNot: + case Lesser: + case Greater: + case LesserEqual: + case GreaterEqual: + check_params(); + + switch ( params_code->NumEntries ) + { + case 1: is_member_symbol = true; - } - break; + break; - case PtrToMemOfPtr: - if ( params_code ) - { - log_failure("gen::def_operator: operator%s expects no paramters - %s", to_str(op), params_code.debug_str()); + 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->NumEntries + ); return OpValidateResult::Fail; - } - break; + } + break; - case Subscript: - case FunctionCall: - case Comma: - check_params(); - break; - # undef specs - } + case Indirection: + case AddressOf: + case MemberOfPointer: + if ( params_code && params_code->NumEntries > 1) + { + log_failure("gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 0-1" + , to_str(op) + , params_code->NumEntries + ); + return OpValidateResult::Fail; + } + else + { + is_member_symbol = true; + } + break; - return is_member_symbol ? OpValidateResult::Member : OpValidateResult::Global; - # undef check_params - # undef check_ret_type - # undef check_param_eq_ret + case PtrToMemOfPtr: + if ( params_code ) + { + log_failure("gen::def_operator: operator%s expects no paramters - %s", to_str(op), params_code.debug_str()); + return OpValidateResult::Fail; + } + break; + + case Subscript: + case FunctionCall: + case Comma: + check_params(); + break; + # undef specs } - void set_allocator_data_arrays( AllocatorInfo allocator ) - { - Allocator_DataArrays = allocator; - } + return is_member_symbol ? OpValidateResult::Member : OpValidateResult::Global; +# undef check_params +# undef check_ret_type +# undef check_param_eq_ret +} - void set_allocator_code_pool( AllocatorInfo allocator ) - { - Allocator_CodePool = allocator; - } +void set_allocator_data_arrays( AllocatorInfo allocator ) +{ + Allocator_DataArrays = allocator; +} - void set_allocator_lexer( AllocatorInfo allocator ) - { - Allocator_Lexer = allocator; - } +void set_allocator_code_pool( AllocatorInfo allocator ) +{ + Allocator_CodePool = allocator; +} - void set_allocator_string_arena( AllocatorInfo allocator ) - { - Allocator_StringArena = allocator; - } +void set_allocator_lexer( AllocatorInfo allocator ) +{ + Allocator_Lexer = allocator; +} - void set_allocator_string_table( AllocatorInfo allocator ) - { - Allocator_StringArena = allocator; - } +void set_allocator_string_arena( AllocatorInfo allocator ) +{ + Allocator_StringArena = allocator; +} + +void set_allocator_string_table( AllocatorInfo allocator ) +{ + Allocator_StringArena = allocator; +} #pragma region Helper Marcojs - // This snippet is used in nearly all the functions. -# define name_check( Context_, Name_ ) \ - { \ - if ( Name_.Len <= 0 ) \ - { \ - log_failure( "gen::" stringize(Context_) ": Invalid name length provided - %d", Name_.Len ); \ - return CodeInvalid; \ - } \ - \ - if ( Name_.Ptr == nullptr ) \ - { \ - log_failure( "gen::" stringize(Context_) ": name is null" ); \ - return CodeInvalid; \ - } \ +// This snippet is used in nearly all the functions. +#define name_check( Context_, Name_ ) \ +{ \ + if ( Name_.Len <= 0 ) \ + { \ + log_failure( "gen::" stringize(Context_) ": Invalid name length provided - %d", Name_.Len ); \ + return CodeInvalid; \ + } \ + \ + if ( Name_.Ptr == nullptr ) \ + { \ + log_failure( "gen::" stringize(Context_) ": name is null" ); \ + return CodeInvalid; \ + } \ +} + +#define null_check( Context_, Code_ ) \ + if ( ! Code_ ) \ + { \ + log_failure( "gen::" stringize(Context_) ": " stringize(Code_) " provided is null" ); \ + return CodeInvalid; \ } -# define null_check( Context_, Code_ ) \ - if ( ! Code_ ) \ - { \ - log_failure( "gen::" stringize(Context_) ": " stringize(Code_) " provided is null" ); \ - return CodeInvalid; \ - } +#define null_or_invalid_check( Context_, Code_ ) \ +{ \ + if ( ! Code_ ) \ + { \ + log_failure( "gen::" stringize(Context_) ": " stringize(Code_) " provided is null" ); \ + return CodeInvalid; \ + } \ + \ + if ( Code_->is_invalid() ) \ + { \ + log_failure("gen::" stringize(Context_) ": " stringize(Code_) " provided is invalid" ); \ + return CodeInvalid; \ + } \ +} -# define null_or_invalid_check( Context_, Code_ ) \ - { \ - if ( ! Code_ ) \ - { \ - log_failure( "gen::" stringize(Context_) ": " stringize(Code_) " provided is null" ); \ - return CodeInvalid; \ - } \ - \ - if ( Code_->is_invalid() ) \ - { \ - log_failure("gen::" stringize(Context_) ": " stringize(Code_) " provided is invalid" ); \ - return CodeInvalid; \ - } \ - } - -# define not_implemented( Context_ ) \ - log_failure( "gen::%s: This function is not implemented" ); \ - return CodeInvalid; +#define not_implemented( Context_ ) \ + log_failure( "gen::%s: This function is not implemented" ); \ + return CodeInvalid; #pragma endregion Helper Marcos #pragma region Upfront Constructors /* - The implementaiton of the upfront constructors involves bascially doing three things: - * Validate the arguments given to construct the intended type of AST is valid. - * Construct said AST type. - * Lock the AST (set to readonly) and return the valid object. +The implementaiton of the upfront constructors involves bascially doing three things: +* Validate the arguments given to construct the intended type of AST is valid. +* Construct said AST type. +* Lock the AST (set to readonly) and return the valid object. - If any of the validation fails, it triggers a call to log_failure with as much info the give the user so that they can hopefully - identify the issue without having to debug too much (at least they can debug though...) +If any of the validation fails, it triggers a call to log_failure with as much info the give the user so that they can hopefully +identify the issue without having to debug too much (at least they can debug though...) - The largest of the functions is related to operator overload definitions. - The library validates a good protion of their form and thus the argument processing for is quite a bit. +The largest of the functions is related to operator overload definitions. +The library validates a good protion of their form and thus the argument processing for is quite a bit. */ - CodeAttributes def_attributes( StrC content ) +CodeAttributes def_attributes( StrC content ) +{ + if ( content.Len <= 0 || content.Ptr == nullptr ) { - if ( content.Len <= 0 || content.Ptr == nullptr ) - { - log_failure( "gen::def_attributes: Invalid attributes provided" ); - return CodeInvalid; - } - - Code - result = make_code(); - result->Type = ECode::PlatformAttributes; - result->Name = get_cached_string( content ); - result->Content = result->Name; - - return (CodeAttributes) result; + log_failure( "gen::def_attributes: Invalid attributes provided" ); + return CodeInvalid; } - CodeComment def_comment( StrC content ) + Code + result = make_code(); + result->Type = ECode::PlatformAttributes; + result->Name = get_cached_string( content ); + result->Content = result->Name; + + return (CodeAttributes) result; +} + +CodeComment def_comment( StrC content ) +{ + if ( content.Len <= 0 || content.Ptr == nullptr ) { - if ( content.Len <= 0 || content.Ptr == nullptr ) - { - log_failure( "gen::def_comment: Invalid comment provided:" ); - return CodeInvalid; - } - - Code - result = make_code(); - result->Type = ECode::Comment; - result->Name = get_cached_string( content ); - result->Content = result->Name; - - return (CodeComment) result; + log_failure( "gen::def_comment: Invalid comment provided:" ); + return CodeInvalid; } - CodeClass def_class( StrC name - , Code body - , CodeType parent, AccessSpec parent_access - , CodeAttributes attributes - , ModuleFlag mflags ) + Code + result = make_code(); + result->Type = ECode::Comment; + result->Name = get_cached_string( content ); + result->Content = result->Name; + + return (CodeComment) result; +} + +CodeClass def_class( StrC name + , Code body + , CodeType parent, AccessSpec parent_access + , CodeAttributes attributes + , ModuleFlag mflags ) +{ + using namespace ECode; + + name_check( def_class, name ); + + if ( attributes && attributes->Type != PlatformAttributes ) { - using namespace ECode; - - name_check( def_class, name ); - - if ( attributes && attributes->Type != PlatformAttributes ) - { - log_failure( "gen::def_class: attributes was not a 'PlatformAttributes' type: %s", attributes.debug_str() ); - return CodeInvalid; - } - - if ( parent && (parent->Type != Class || parent->Type != Struct || parent->Type != Typename || parent->Type != Untyped) ) - { - log_failure( "gen::def_class: parent provided is not type 'Class', 'Struct', 'Typeanme', or 'Untyped': %s", parent.debug_str() ); - return CodeInvalid; - } - - CodeClass - result = (CodeClass) make_code(); - result->Name = get_cached_string( name ); - result->ModuleFlags = mflags; - - 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 CodeInvalid; - } - - result->Type = Class; - result->Body = body; - } - else - { - result->Type = Class_Fwd; - } - - if ( attributes ) - result->Attributes = attributes; - - if ( parent ) - { - result->ParentAccess = parent_access; - result->ParentType = parent; - } - - return result; + log_failure( "gen::def_class: attributes was not a 'PlatformAttributes' type: %s", attributes.debug_str() ); + return CodeInvalid; } - CodeEnum def_enum( StrC name - , Code body, CodeType type - , EnumT specifier, CodeAttributes attributes - , ModuleFlag mflags ) + if ( parent && (parent->Type != Class || parent->Type != Struct || parent->Type != Typename || parent->Type != Untyped) ) { - using namespace ECode; - - name_check( def_enum, name ); - - if ( type && type->Type != Typename ) - { - log_failure( "gen::def_enum: enum underlying type provided was not of type Typename: %s", type.debug_str() ); - return CodeInvalid; - } - - if ( attributes && attributes->Type != PlatformAttributes ) - { - log_failure( "gen::def_enum: attributes was not a 'PlatformAttributes' type: %s", attributes.debug_str() ); - return CodeInvalid; - } - - CodeEnum - result = (CodeEnum) make_code(); - result->Name = get_cached_string( name ); - result->ModuleFlags = mflags; - - 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 CodeInvalid; - } - - result->Type = specifier == EnumClass ? - Enum_Class : Enum; - - result->Body = body; - } - else - { - result->Type = specifier == EnumClass ? - Enum_Class_Fwd : Enum_Fwd; - } - - if ( attributes ) - result->Attributes = attributes; - - if ( type ) - { - result->UnderlyingType = type; - } - else if ( result->Type != Enum_Class_Fwd && result->Type != Enum_Fwd ) - { - log_failure( "gen::def_enum: enum forward declaration must have an underlying type" ); - return CodeInvalid; - } - - return result; + log_failure( "gen::def_class: parent provided is not type 'Class', 'Struct', 'Typeanme', or 'Untyped': %s", parent.debug_str() ); + return CodeInvalid; } - CodeExec def_execution( StrC content ) + CodeClass + result = (CodeClass) make_code(); + result->Name = get_cached_string( name ); + result->ModuleFlags = mflags; + + if ( body ) { - if ( content.Len <= 0 || content.Ptr == nullptr ) + switch ( body->Type ) { - log_failure( "gen::def_execution: Invalid execution provided" ); - return CodeInvalid; - } - - Code - result = make_code(); - result->Type = ECode::Execution; - result->Name = get_cached_string( content ); - result->Content = result->Name; - - return (CodeExec) result; - } - - CodeExtern def_extern_link( StrC name, Code body ) - { - using namespace ECode; - - name_check( def_extern_linkage, name ); - null_check( def_extern_linkage, body ); - - if ( body->Type != Extern_Linkage_Body && body->Type != Untyped ) - { - log_failure("gen::def_extern_linkage: body is not of extern_linkage or untyped type %s", body->debug_str()); - return CodeInvalid; - } - - CodeExtern - result = (CodeExtern)make_code(); - result->Type = Extern_Linkage; - result->Name = get_cached_string( name ); - result->Body = body; - - return (CodeExtern) result; - } - - CodeFriend def_friend( Code declaration ) - { - using namespace ECode; - - null_check( def_friend, declaration ); - - switch ( declaration->Type ) - { - case Class_Fwd: - case Function_Fwd: - case Operator_Fwd: - case Struct_Fwd: - case Class: - case Function: - case Operator: - case Struct: + case Class_Body: + case Untyped: break; default: - log_failure("gen::def_friend: requires declartion to have class, function, operator, or struct - %s", declaration->debug_str()); + log_failure("gen::def_class: body must be either of Class_Body or Untyped type - %s", body.debug_str()); return CodeInvalid; } - CodeFriend - result = (CodeFriend) make_code(); - result->Type = Friend; - - result->Declaration = declaration; - - return result; + result->Type = Class; + result->Body = body; + } + else + { + result->Type = Class_Fwd; } - CodeFn def_function( StrC name - , CodeParam params , CodeType ret_type, Code body - , CodeSpecifier specifiers, CodeAttributes attributes - , ModuleFlag mflags ) + if ( attributes ) + result->Attributes = attributes; + + if ( parent ) { - using namespace ECode; - - name_check( def_function, name ); - - if ( params && params->Type != Parameters ) - { - log_failure( "gen::def_function: params was not a `Parameters` type: %s", params.debug_str() ); - return CodeInvalid; - } - - if ( ret_type && ret_type->Type != Typename ) - { - log_failure( "gen::def_function: ret_type was not a Typename: %s", ret_type.debug_str() ); - return CodeInvalid; - } - - if ( specifiers && specifiers->Type != Specifiers ) - { - log_failure( "gen::def_function: specifiers was not a `Specifiers` type: %s", specifiers.debug_str() ); - return CodeInvalid; - } - - if ( attributes && attributes->Type != PlatformAttributes ) - { - log_failure( "gen::def_function: attributes was not a `PlatformAttributes` type: %s", attributes.debug_str() ); - return CodeInvalid; - } - - CodeFn - result = (CodeFn) make_code(); - result->Name = get_cached_string( name ); - result->ModuleFlags = mflags; - - if ( body ) - { - switch ( body->Type ) - { - case Function_Body: - case Execution: - case Untyped: - break; - - default: - { - log_failure("gen::def_function: body must be either of Function_Body, Execution, or Untyped type. %s", body->debug_str()); - return CodeInvalid; - } - } - - result->Type = Function; - result->Body = body; - } - else - { - result->Type = Function_Fwd; - } - - if ( attributes ) - result->Attributes = attributes; - - if ( specifiers ) - result->Specs = specifiers; - - if ( ret_type ) - { - result->ReturnType = ret_type; - } - else - { - result->ReturnType = t_void; - } - - if ( params ) - result->Params = params; - - return result; + result->ParentAccess = parent_access; + result->ParentType = parent; } - CodeInclude def_include ( StrC path ) + return result; +} + +CodeEnum def_enum( StrC name + , Code body, CodeType type + , EnumT specifier, CodeAttributes attributes + , ModuleFlag mflags ) +{ + using namespace ECode; + + name_check( def_enum, name ); + + if ( type && type->Type != Typename ) { - if ( path.Len <= 0 || path.Ptr == nullptr ) - { - log_failure( "gen::def_include: Invalid path provided - %d" ); - return CodeInvalid; - } - - Code - result = make_code(); - result->Type = ECode::Preprocessor_Include; - result->Name = get_cached_string( path ); - result->Content = result->Name; - - return (CodeInclude) result; + log_failure( "gen::def_enum: enum underlying type provided was not of type Typename: %s", type.debug_str() ); + return CodeInvalid; } - CodeModule def_module( StrC name, ModuleFlag mflags ) + if ( attributes && attributes->Type != PlatformAttributes ) { - name_check( def_module, name ); - - Code - result = make_code(); - result->Type = ECode::Module; - result->Name = get_cached_string( name ); - result->Content = result->Name; - result->ModuleFlags = mflags; - - return (CodeModule) result; + log_failure( "gen::def_enum: attributes was not a 'PlatformAttributes' type: %s", attributes.debug_str() ); + return CodeInvalid; } - CodeNamespace def_namespace( StrC name, Code body, ModuleFlag mflags ) + CodeEnum + result = (CodeEnum) make_code(); + result->Name = get_cached_string( name ); + result->ModuleFlags = mflags; + + if ( body ) { - using namespace ECode; - - name_check( def_namespace, name ); - null_check( def_namespace, body ); - - if ( body->Type != Namespace_Body && body->Type != Untyped ) + switch ( body->Type ) { - log_failure("gen::def_namespace: body is not of namespace or untyped type %s", body.debug_str()); - return CodeInvalid; - } - - CodeNamespace - result = (CodeNamespace) make_code(); - result->Type = Namespace; - result->Name = get_cached_string( name ); - result->ModuleFlags = mflags; - result->Body = body; - - return result; - } - - CodeOperator def_operator( OperatorT op - , CodeParam params_code, CodeType ret_type, Code body - , CodeSpecifier specifiers, CodeAttributes attributes - , ModuleFlag mflags ) - { - using namespace ECode; - - if ( attributes && attributes->Type != PlatformAttributes ) - { - log_failure( "gen::def_operator: PlatformAttributes was provided but its not of attributes type: %s", attributes.debug_str() ); - return CodeInvalid; - } - - if ( specifiers && specifiers->Type != Specifiers ) - { - log_failure( "gen::def_operator: Specifiers was provided but its not of specifiers type: %s", specifiers.debug_str() ); - return CodeInvalid; - } - - OpValidateResult check_result = operator__validate( op, params_code, ret_type, specifiers ); - - if ( check_result == OpValidateResult::Fail ) - { - return CodeInvalid; - } - - char const* name = str_fmt_buf( "operator %s", to_str(op) ); - - CodeOperator - result = (CodeOperator) make_code(); - result->Name = get_cached_string( { str_len(name), name } ); - result->ModuleFlags = mflags; - - if ( body ) - { - switch ( body->Type ) - { - case Function_Body: - case Execution: - case Untyped: - break; - - default: - { - log_failure("gen::def_operator: body must be either of Function_Body, Execution, or Untyped type. %s", body->debug_str()); - return CodeInvalid; - } - } - - result->Type = check_result == OpValidateResult::Global ? - Operator : Operator_Member; - - result->Body = body; - } - else - { - result->Type = check_result == OpValidateResult::Global ? - Operator_Fwd : Operator_Member_Fwd; - } - - if ( attributes ) - result->Attributes = attributes; - - if ( specifiers ) - result->Specs = specifiers; - - result->ReturnType = ret_type; - - if (params_code) - result->Params = params_code; - - return result; - } - - CodeOpCast def_operator_cast( CodeType type, Code body ) - { - using namespace ECode; - null_check( def_operator_cast, type ); - - if ( type->Type != Typename ) - { - log_failure( "gen::def_operator_cast: type is not a typename - %s", type.debug_str() ); - return CodeInvalid; - } - - CodeOpCast result = (CodeOpCast) make_code(); - - if (body) - { - result->Type = Operator_Cast; - - if ( body->Type != Function_Body && body->Type != Execution ) - { - log_failure( "gen::def_operator_cast: body is not of function body or execution type - %s", body.debug_str() ); - return CodeInvalid; - } - - result->Body = body; - } - else - { - result->Type = Operator_Cast_Fwd; - } - - result->ValueType = type; - return result; - } - - CodeParam def_param( CodeType type, StrC name, Code value ) - { - using namespace ECode; - - name_check( def_param, name ); - null_check( def_param, type ); - - if ( type->Type != Typename ) - { - log_failure( "gen::def_param: type is not a typename - %s", type.debug_str() ); - return CodeInvalid; - } - - if ( value && value->Type != Untyped ) - { - log_failure( "gen::def_param: value is not untyped - %s", value.debug_str() ); - return CodeInvalid; - } - - CodeParam - result = (CodeParam) make_code(); - result->Type = Parameters; - result->Name = get_cached_string( name ); - - result->ValueType = type; - - if ( value ) - result->Value = value; - - result->NumEntries++; - - return result; - } - - CodeSpecifier def_specifier( SpecifierT spec ) - { - CodeSpecifier - result = (CodeSpecifier) make_code(); - result->Type = ECode::Specifiers; - result.append( spec ); - - return result; - } - - CodeStruct def_struct( StrC name - , Code body - , CodeType parent, AccessSpec parent_access - , CodeAttributes attributes - , ModuleFlag mflags ) - { - using namespace ECode; - - if ( attributes && attributes->Type != PlatformAttributes ) - { - log_failure( "gen::def_struct: attributes was not a `PlatformAttributes` type - %s", attributes.debug_str() ); - return CodeInvalid; - } - - if ( parent && parent->Type != Typename ) - { - log_failure( "gen::def_struct: parent was not a `Struct` type - %s", parent.debug_str() ); - return CodeInvalid; - } - - if ( body && body->Type != Struct_Body ) - { - log_failure( "gen::def_struct: body was not a Struct_Body type - %s", body.debug_str() ); - return CodeInvalid; - } - - CodeStruct - result = (CodeStruct) make_code(); - result->ModuleFlags = mflags; - - if ( name ) - result->Name = get_cached_string( name ); - - if ( body ) - { - result->Type = Struct; - result->Body = body; - } - else - { - result->Type = Struct_Fwd; - } - - if ( attributes ) - result->Attributes = attributes; - - if ( parent ) - { - result->ParentAccess = parent_access; - result->ParentType = parent; - } - - return result; - } - - CodeTemplate def_template( CodeParam params, Code declaration, ModuleFlag mflags ) - { - null_check( def_template, declaration ); - - if ( params && params->Type != ECode::Parameters ) - { - log_failure( "gen::def_template: params is not of parameters type - %s", params.debug_str() ); - return CodeInvalid; - } - - switch (declaration->Type ) - { - case ECode::Class: - case ECode::Function: - case ECode::Struct: - case ECode::Variable: - case ECode::Using: + case Enum_Body: + case Untyped: break; default: - log_failure( "gen::def_template: declaration is not of class, function, struct, variable, or using type - %s", declaration.debug_str() ); + log_failure( "gen::def_enum: body must be of Enum_Body or Untyped type %s", body.debug_str()); + return CodeInvalid; } - CodeTemplate - result = (CodeTemplate) make_code(); - result->Type = ECode::Template; - result->ModuleFlags = mflags; - result->Params = params; - result->Declaration = declaration; - - return result; - } - - CodeType def_type( StrC name, Code arrayexpr, CodeSpecifier specifiers, CodeAttributes attributes ) - { - name_check( def_type, name ); - - if ( attributes && attributes->Type != ECode::PlatformAttributes ) - { - log_failure( "gen::def_type: attributes is not of attributes type - %s", attributes.debug_str() ); - return CodeInvalid; - } - - if ( specifiers && specifiers->Type != ECode::Specifiers ) - { - log_failure( "gen::def_type: specifiers is not of specifiers type - %s", specifiers.debug_str() ); - return CodeInvalid; - } - - if ( arrayexpr && arrayexpr->Type != ECode::Untyped ) - { - log_failure( "gen::def_type: arrayexpr is not of untyped type - %s", arrayexpr->debug_str() ); - return CodeInvalid; - } - - CodeType - result = (CodeType) make_code(); - result->Name = get_cached_string( name ); - result->Type = ECode::Typename; - - if ( attributes ) - result->Attributes = attributes; - - if ( specifiers ) - result->Specs = specifiers; - - if ( arrayexpr ) - result->ArrExpr = arrayexpr; - - return result; - } - - CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes, ModuleFlag mflags ) - { - name_check( def_typedef, name ); - null_check( def_typedef, type ); - - if ( type->Type != ECode::Typename ) - { - log_failure( "gen::def_typedef: type was not a Typename - %s", type.debug_str() ); - return CodeInvalid; - } - - if ( attributes && attributes->Type != ECode::PlatformAttributes ) - { - log_failure( "gen::def_typedef: attributes was not a PlatformAttributes - %s", attributes.debug_str() ); - return CodeInvalid; - } - - // Registering the type. - Code registered_type = def_type( name ); - - if ( ! registered_type ) - { - log_failure( "gen::def_typedef: failed to register type" ); - return CodeInvalid; - } - - CodeTypedef - result = (CodeTypedef) make_code(); - result->Name = get_cached_string( name ); - result->Type = ECode::Typedef; - result->ModuleFlags = mflags; - - result->UnderlyingType = type; - - if ( attributes ) - result->Attributes = attributes; - - return result; - } - - CodeUnion def_union( StrC name, Code body, CodeAttributes attributes, ModuleFlag mflags ) - { - null_check( def_union, body ); - - if ( body->Type != ECode::Union_Body ) - { - log_failure( "gen::def_union: body was not a Union_Body type - %s", body.debug_str() ); - return CodeInvalid; - } - - if ( attributes && attributes->Type != ECode::PlatformAttributes ) - { - log_failure( "gen::def_union: attributes was not a PlatformAttributes type - %s", attributes.debug_str() ); - return CodeInvalid; - } - - CodeUnion - result = (CodeUnion) make_code(); - result->ModuleFlags = mflags; - result->Type = ECode::Union; - - if ( name.Ptr ) - result->Name = get_cached_string( name ); + result->Type = specifier == EnumClass ? + Enum_Class : Enum; result->Body = body; - - if ( attributes ) - result->Attributes = attributes; - - return result; + } + else + { + result->Type = specifier == EnumClass ? + Enum_Class_Fwd : Enum_Fwd; } - CodeUsing def_using( StrC name, CodeType type - , CodeAttributes attributes - , ModuleFlag mflags ) + if ( attributes ) + result->Attributes = attributes; + + if ( type ) { - name_check( def_using, name ); - null_check( def_using, type ); - - Code register_type = def_type( name ); - - if ( ! register_type ) - { - log_failure( "gen::def_using: failed to register type" ); - return CodeInvalid; - } - - if ( attributes && attributes->Type != ECode::PlatformAttributes ) - { - log_failure( "gen::def_using: attributes was not a PlatformAttributes type - %s", attributes.debug_str() ); - return CodeInvalid; - } - - CodeUsing - result = (CodeUsing) make_code(); - result->Name = get_cached_string( name ); - result->ModuleFlags = mflags; - result->Type = ECode::Using; - result->UnderlyingType = type; - - if ( attributes ) - result->Attributes = attributes; - - return result; } - - CodeUsing def_using_namespace( StrC name ) + else if ( result->Type != Enum_Class_Fwd && result->Type != Enum_Fwd ) { - name_check( def_using_namespace, name ); - - Code - result = make_code(); - result->Name = get_cached_string( name ); - result->Content = result->Name; - result->Type = ECode::Using_Namespace; - - return (CodeUsing) result; + log_failure( "gen::def_enum: enum forward declaration must have an underlying type" ); + return CodeInvalid; } - CodeVar def_variable( CodeType type, StrC name, Code value - , CodeSpecifier specifiers, CodeAttributes attributes - , ModuleFlag mflags ) + return result; +} + +CodeExec def_execution( StrC content ) +{ + if ( content.Len <= 0 || content.Ptr == nullptr ) { - name_check( def_variable, name ); - null_check( def_variable, type ); - - if ( attributes && attributes->Type != ECode::PlatformAttributes ) - { - log_failure( "gen::def_variable: attributes was not a `PlatformAttributes` type - %s", attributes.debug_str() ); - return CodeInvalid; - } - - if ( specifiers && specifiers->Type != ECode::Specifiers ) - { - log_failure( "gen::def_variable: specifiers was not a `Specifiers` type - %s", specifiers.debug_str() ); - return CodeInvalid; - } - - if ( type->Type != ECode::Typename ) - { - log_failure( "gen::def_variable: type was not a Typename - %s", type.debug_str() ); - return CodeInvalid; - } - - if ( value && value->Type != ECode::Untyped ) - { - log_failure( "gen::def_variable: value was not a `Untyped` type - %s", value.debug_str() ); - return CodeInvalid; - } - - CodeVar - result = (CodeVar) make_code(); - result->Name = get_cached_string( name ); - result->Type = ECode::Variable; - result->ModuleFlags = mflags; - - result->ValueType = type; - - if ( attributes ) - result->Attributes = attributes; - - if ( specifiers ) - result->Specs = specifiers; - - if ( value ) - result->Value = value; - - return result; + log_failure( "gen::def_execution: Invalid execution provided" ); + return CodeInvalid; } + Code + result = make_code(); + result->Type = ECode::Execution; + result->Name = get_cached_string( content ); + result->Content = result->Name; + + return (CodeExec) result; +} + +CodeExtern def_extern_link( StrC name, Code body ) +{ + using namespace ECode; + + name_check( def_extern_linkage, name ); + null_check( def_extern_linkage, body ); + + if ( body->Type != Extern_Linkage_Body && body->Type != Untyped ) + { + log_failure("gen::def_extern_linkage: body is not of extern_linkage or untyped type %s", body->debug_str()); + return CodeInvalid; + } + + CodeExtern + result = (CodeExtern)make_code(); + result->Type = Extern_Linkage; + result->Name = get_cached_string( name ); + result->Body = body; + + return (CodeExtern) result; +} + +CodeFriend def_friend( Code declaration ) +{ + using namespace ECode; + + null_check( def_friend, declaration ); + + switch ( declaration->Type ) + { + case Class_Fwd: + case Function_Fwd: + case Operator_Fwd: + case Struct_Fwd: + case Class: + case Function: + case Operator: + case Struct: + break; + + default: + log_failure("gen::def_friend: requires declartion to have class, function, operator, or struct - %s", declaration->debug_str()); + return CodeInvalid; + } + + CodeFriend + result = (CodeFriend) make_code(); + result->Type = Friend; + + result->Declaration = declaration; + + return result; +} + +CodeFn def_function( StrC name + , CodeParam params , CodeType ret_type, Code body + , CodeSpecifier specifiers, CodeAttributes attributes + , ModuleFlag mflags ) +{ + using namespace ECode; + + name_check( def_function, name ); + + if ( params && params->Type != Parameters ) + { + log_failure( "gen::def_function: params was not a `Parameters` type: %s", params.debug_str() ); + return CodeInvalid; + } + + if ( ret_type && ret_type->Type != Typename ) + { + log_failure( "gen::def_function: ret_type was not a Typename: %s", ret_type.debug_str() ); + return CodeInvalid; + } + + if ( specifiers && specifiers->Type != Specifiers ) + { + log_failure( "gen::def_function: specifiers was not a `Specifiers` type: %s", specifiers.debug_str() ); + return CodeInvalid; + } + + if ( attributes && attributes->Type != PlatformAttributes ) + { + log_failure( "gen::def_function: attributes was not a `PlatformAttributes` type: %s", attributes.debug_str() ); + return CodeInvalid; + } + + CodeFn + result = (CodeFn) make_code(); + result->Name = get_cached_string( name ); + result->ModuleFlags = mflags; + + if ( body ) + { + switch ( body->Type ) + { + case Function_Body: + case Execution: + case Untyped: + break; + + default: + { + log_failure("gen::def_function: body must be either of Function_Body, Execution, or Untyped type. %s", body->debug_str()); + return CodeInvalid; + } + } + + result->Type = Function; + result->Body = body; + } + else + { + result->Type = Function_Fwd; + } + + if ( attributes ) + result->Attributes = attributes; + + if ( specifiers ) + result->Specs = specifiers; + + if ( ret_type ) + { + result->ReturnType = ret_type; + } + else + { + result->ReturnType = t_void; + } + + if ( params ) + result->Params = params; + + return result; +} + +CodeInclude def_include ( StrC path ) +{ + if ( path.Len <= 0 || path.Ptr == nullptr ) + { + log_failure( "gen::def_include: Invalid path provided - %d" ); + return CodeInvalid; + } + + Code + result = make_code(); + result->Type = ECode::Preprocessor_Include; + result->Name = get_cached_string( path ); + result->Content = result->Name; + + return (CodeInclude) result; +} + +CodeModule def_module( StrC name, ModuleFlag mflags ) +{ + name_check( def_module, name ); + + Code + result = make_code(); + result->Type = ECode::Module; + result->Name = get_cached_string( name ); + result->Content = result->Name; + result->ModuleFlags = mflags; + + return (CodeModule) result; +} + +CodeNamespace def_namespace( StrC name, Code body, ModuleFlag mflags ) +{ + using namespace ECode; + + name_check( def_namespace, name ); + null_check( def_namespace, body ); + + 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 CodeInvalid; + } + + CodeNamespace + result = (CodeNamespace) make_code(); + result->Type = Namespace; + result->Name = get_cached_string( name ); + result->ModuleFlags = mflags; + result->Body = body; + + return result; +} + +CodeOperator def_operator( OperatorT op + , CodeParam params_code, CodeType ret_type, Code body + , CodeSpecifier specifiers, CodeAttributes attributes + , ModuleFlag mflags ) +{ + using namespace ECode; + + if ( attributes && attributes->Type != PlatformAttributes ) + { + log_failure( "gen::def_operator: PlatformAttributes was provided but its not of attributes type: %s", attributes.debug_str() ); + return CodeInvalid; + } + + if ( specifiers && specifiers->Type != Specifiers ) + { + log_failure( "gen::def_operator: Specifiers was provided but its not of specifiers type: %s", specifiers.debug_str() ); + return CodeInvalid; + } + + OpValidateResult check_result = operator__validate( op, params_code, ret_type, specifiers ); + + if ( check_result == OpValidateResult::Fail ) + { + return CodeInvalid; + } + + char const* name = str_fmt_buf( "operator %s", to_str(op) ); + + CodeOperator + result = (CodeOperator) make_code(); + result->Name = get_cached_string( { str_len(name), name } ); + result->ModuleFlags = mflags; + + if ( body ) + { + switch ( body->Type ) + { + case Function_Body: + case Execution: + case Untyped: + break; + + default: + { + log_failure("gen::def_operator: body must be either of Function_Body, Execution, or Untyped type. %s", body->debug_str()); + return CodeInvalid; + } + } + + result->Type = check_result == OpValidateResult::Global ? + Operator : Operator_Member; + + result->Body = body; + } + else + { + result->Type = check_result == OpValidateResult::Global ? + Operator_Fwd : Operator_Member_Fwd; + } + + if ( attributes ) + result->Attributes = attributes; + + if ( specifiers ) + result->Specs = specifiers; + + result->ReturnType = ret_type; + + if (params_code) + result->Params = params_code; + + return result; +} + +CodeOpCast def_operator_cast( CodeType type, Code body ) +{ + using namespace ECode; + null_check( def_operator_cast, type ); + + if ( type->Type != Typename ) + { + log_failure( "gen::def_operator_cast: type is not a typename - %s", type.debug_str() ); + return CodeInvalid; + } + + CodeOpCast result = (CodeOpCast) make_code(); + + if (body) + { + result->Type = Operator_Cast; + + if ( body->Type != Function_Body && body->Type != Execution ) + { + log_failure( "gen::def_operator_cast: body is not of function body or execution type - %s", body.debug_str() ); + return CodeInvalid; + } + + result->Body = body; + } + else + { + result->Type = Operator_Cast_Fwd; + } + + result->ValueType = type; + return result; +} + +CodeParam def_param( CodeType type, StrC name, Code value ) +{ + using namespace ECode; + + name_check( def_param, name ); + null_check( def_param, type ); + + if ( type->Type != Typename ) + { + log_failure( "gen::def_param: type is not a typename - %s", type.debug_str() ); + return CodeInvalid; + } + + if ( value && value->Type != Untyped ) + { + log_failure( "gen::def_param: value is not untyped - %s", value.debug_str() ); + return CodeInvalid; + } + + CodeParam + result = (CodeParam) make_code(); + result->Type = Parameters; + result->Name = get_cached_string( name ); + + result->ValueType = type; + + if ( value ) + result->Value = value; + + result->NumEntries++; + + return result; +} + +CodeSpecifier def_specifier( SpecifierT spec ) +{ + CodeSpecifier + result = (CodeSpecifier) make_code(); + result->Type = ECode::Specifiers; + result.append( spec ); + + return result; +} + +CodeStruct def_struct( StrC name + , Code body + , CodeType parent, AccessSpec parent_access + , CodeAttributes attributes + , ModuleFlag mflags ) +{ + using namespace ECode; + + if ( attributes && attributes->Type != PlatformAttributes ) + { + log_failure( "gen::def_struct: attributes was not a `PlatformAttributes` type - %s", attributes.debug_str() ); + return CodeInvalid; + } + + if ( parent && parent->Type != Typename ) + { + log_failure( "gen::def_struct: parent was not a `Struct` type - %s", parent.debug_str() ); + return CodeInvalid; + } + + if ( body && body->Type != Struct_Body ) + { + log_failure( "gen::def_struct: body was not a Struct_Body type - %s", body.debug_str() ); + return CodeInvalid; + } + + CodeStruct + result = (CodeStruct) make_code(); + result->ModuleFlags = mflags; + + if ( name ) + result->Name = get_cached_string( name ); + + if ( body ) + { + result->Type = Struct; + result->Body = body; + } + else + { + result->Type = Struct_Fwd; + } + + if ( attributes ) + result->Attributes = attributes; + + if ( parent ) + { + result->ParentAccess = parent_access; + result->ParentType = parent; + } + + return result; +} + +CodeTemplate def_template( CodeParam params, Code declaration, ModuleFlag mflags ) +{ + null_check( def_template, declaration ); + + if ( params && params->Type != ECode::Parameters ) + { + log_failure( "gen::def_template: params is not of parameters type - %s", params.debug_str() ); + return CodeInvalid; + } + + switch (declaration->Type ) + { + case ECode::Class: + case ECode::Function: + case ECode::Struct: + case ECode::Variable: + case ECode::Using: + break; + + default: + log_failure( "gen::def_template: declaration is not of class, function, struct, variable, or using type - %s", declaration.debug_str() ); + } + + CodeTemplate + result = (CodeTemplate) make_code(); + result->Type = ECode::Template; + result->ModuleFlags = mflags; + result->Params = params; + result->Declaration = declaration; + + return result; +} + +CodeType def_type( StrC name, Code arrayexpr, CodeSpecifier specifiers, CodeAttributes attributes ) +{ + name_check( def_type, name ); + + if ( attributes && attributes->Type != ECode::PlatformAttributes ) + { + log_failure( "gen::def_type: attributes is not of attributes type - %s", attributes.debug_str() ); + return CodeInvalid; + } + + if ( specifiers && specifiers->Type != ECode::Specifiers ) + { + log_failure( "gen::def_type: specifiers is not of specifiers type - %s", specifiers.debug_str() ); + return CodeInvalid; + } + + if ( arrayexpr && arrayexpr->Type != ECode::Untyped ) + { + log_failure( "gen::def_type: arrayexpr is not of untyped type - %s", arrayexpr->debug_str() ); + return CodeInvalid; + } + + CodeType + result = (CodeType) make_code(); + result->Name = get_cached_string( name ); + result->Type = ECode::Typename; + + if ( attributes ) + result->Attributes = attributes; + + if ( specifiers ) + result->Specs = specifiers; + + if ( arrayexpr ) + result->ArrExpr = arrayexpr; + + return result; +} + +CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes, ModuleFlag mflags ) +{ + name_check( def_typedef, name ); + null_check( def_typedef, type ); + + if ( type->Type != ECode::Typename ) + { + log_failure( "gen::def_typedef: type was not a Typename - %s", type.debug_str() ); + return CodeInvalid; + } + + if ( attributes && attributes->Type != ECode::PlatformAttributes ) + { + log_failure( "gen::def_typedef: attributes was not a PlatformAttributes - %s", attributes.debug_str() ); + return CodeInvalid; + } + + // Registering the type. + Code registered_type = def_type( name ); + + if ( ! registered_type ) + { + log_failure( "gen::def_typedef: failed to register type" ); + return CodeInvalid; + } + + CodeTypedef + result = (CodeTypedef) make_code(); + result->Name = get_cached_string( name ); + result->Type = ECode::Typedef; + result->ModuleFlags = mflags; + + result->UnderlyingType = type; + + if ( attributes ) + result->Attributes = attributes; + + return result; +} + +CodeUnion def_union( StrC name, Code body, CodeAttributes attributes, ModuleFlag mflags ) +{ + null_check( def_union, body ); + + if ( body->Type != ECode::Union_Body ) + { + log_failure( "gen::def_union: body was not a Union_Body type - %s", body.debug_str() ); + return CodeInvalid; + } + + if ( attributes && attributes->Type != ECode::PlatformAttributes ) + { + log_failure( "gen::def_union: attributes was not a PlatformAttributes type - %s", attributes.debug_str() ); + return CodeInvalid; + } + + CodeUnion + result = (CodeUnion) make_code(); + result->ModuleFlags = mflags; + result->Type = ECode::Union; + + if ( name.Ptr ) + result->Name = get_cached_string( name ); + + result->Body = body; + + if ( attributes ) + result->Attributes = attributes; + + return result; +} + +CodeUsing def_using( StrC name, CodeType type + , CodeAttributes attributes + , ModuleFlag mflags ) +{ + name_check( def_using, name ); + null_check( def_using, type ); + + Code register_type = def_type( name ); + + if ( ! register_type ) + { + log_failure( "gen::def_using: failed to register type" ); + return CodeInvalid; + } + + if ( attributes && attributes->Type != ECode::PlatformAttributes ) + { + log_failure( "gen::def_using: attributes was not a PlatformAttributes type - %s", attributes.debug_str() ); + return CodeInvalid; + } + + CodeUsing + result = (CodeUsing) make_code(); + result->Name = get_cached_string( name ); + result->ModuleFlags = mflags; + result->Type = ECode::Using; + + result->UnderlyingType = type; + + if ( attributes ) + result->Attributes = attributes; + + return result; +} + +CodeUsing def_using_namespace( StrC name ) +{ + name_check( def_using_namespace, name ); + + Code + result = make_code(); + result->Name = get_cached_string( name ); + result->Content = result->Name; + result->Type = ECode::Using_Namespace; + + return (CodeUsing) result; +} + +CodeVar def_variable( CodeType type, StrC name, Code value + , CodeSpecifier specifiers, CodeAttributes attributes + , ModuleFlag mflags ) +{ + name_check( def_variable, name ); + null_check( def_variable, type ); + + if ( attributes && attributes->Type != ECode::PlatformAttributes ) + { + log_failure( "gen::def_variable: attributes was not a `PlatformAttributes` type - %s", attributes.debug_str() ); + return CodeInvalid; + } + + if ( specifiers && specifiers->Type != ECode::Specifiers ) + { + log_failure( "gen::def_variable: specifiers was not a `Specifiers` type - %s", specifiers.debug_str() ); + return CodeInvalid; + } + + if ( type->Type != ECode::Typename ) + { + log_failure( "gen::def_variable: type was not a Typename - %s", type.debug_str() ); + return CodeInvalid; + } + + if ( value && value->Type != ECode::Untyped ) + { + log_failure( "gen::def_variable: value was not a `Untyped` type - %s", value.debug_str() ); + return CodeInvalid; + } + + CodeVar + result = (CodeVar) make_code(); + result->Name = get_cached_string( name ); + result->Type = ECode::Variable; + result->ModuleFlags = mflags; + + result->ValueType = type; + + if ( attributes ) + result->Attributes = attributes; + + if ( specifiers ) + result->Specs = specifiers; + + if ( value ) + result->Value = value; + + return result; +} + /* - Body related functions typically follow the same implementation pattern. - Opted to use inline helper macros to get the implementaiton done. +Body related functions typically follow the same implementation pattern. +Opted to use inline helper macros to get the implementaiton done. - The implementation pattern is as follows: - * Validate a valid parameter num was provided, or code array - def_body_start or def_body_code_array_start( ) +The implementation pattern is as follows: +* Validate a valid parameter num was provided, or code array + def_body_start or def_body_code_array_start( ) - * Begin the code entry do-while loop, make sure each entry is valid processing its type in the switc - def_body_code_validation_start( ) +* Begin the code entry do-while loop, make sure each entry is valid processing its type in the switc + def_body_code_validation_start( ) - * Define the switch case statements between the macros. +* Define the switch case statements between the macros. - * Add the code entry, finish the closing implemenation for the do-while loop. - def_body_code_validation_end( ) +* Add the code entry, finish the closing implemenation for the do-while loop. + def_body_code_validation_end( ) - * Lock the body AST and return it. +* Lock the body AST and return it. - If a function's implementation deviates from the macros then its just writen it out. +If a function's implementation deviates from the macros then its just writen it out. */ #pragma region Helper Macros for def_**_body functions -# define def_body_start( Name_ ) \ - using namespace ECode; \ - \ - if ( num <= 0 ) \ - { \ - log_failure("gen::" stringize(Name_) ": num cannot be zero or negative"); \ - return CodeInvalid; \ - } +#define def_body_start( Name_ ) \ +using namespace ECode; \ + \ +if ( num <= 0 ) \ +{ \ + log_failure("gen::" stringize(Name_) ": num cannot be zero or negative"); \ + return CodeInvalid; \ +} -# define def_body_code_array_start( Name_ ) \ - using namespace ECode; \ - \ - if ( num <= 0 ) \ - { \ - log_failure("gen::" stringize(Name_) ": num cannot be zero or negative"); \ - return CodeInvalid; \ - } \ - \ - if ( codes == nullptr ) \ - { \ - log_failure("gen::" stringize(Name_)" : Provided a null array of codes"); \ - return CodeInvalid; \ - } +#define def_body_code_array_start( Name_ ) \ +using namespace ECode; \ + \ +if ( num <= 0 ) \ +{ \ + log_failure("gen::" stringize(Name_) ": num cannot be zero or negative"); \ + return CodeInvalid; \ +} \ + \ +if ( codes == nullptr ) \ +{ \ + log_failure("gen::" stringize(Name_)" : Provided a null array of codes"); \ + return CodeInvalid; \ +} -# define def_body_code_validation_start( Name_ ) \ - do \ - { \ - Code_POD pod = va_arg(va, Code_POD); \ - Code entry = pcast(Code, pod); \ - \ - if ( ! entry ) \ - { \ - log_failure("gen::" stringize(Name_) ": Provided an null entry"); \ - return CodeInvalid; \ - } \ - \ - switch ( entry->Type ) \ - { +#define def_body_code_validation_start( Name_ ) \ +do \ +{ \ + Code_POD pod = va_arg(va, Code_POD); \ + Code entry = pcast(Code, pod); \ + \ + if ( ! entry ) \ + { \ + log_failure("gen::" stringize(Name_) ": Provided an null entry"); \ + return CodeInvalid; \ + } \ + \ + switch ( entry->Type ) \ + { -# define def_body_code_array_validation_start( Name_ ) \ - do \ - { \ - Code entry = *codes; codes++; \ - \ - if ( ! entry ) \ - { \ - log_failure("gen::" stringize(Name_) ": Provided an null entry"); \ - return CodeInvalid; \ - } \ - \ - switch ( entry->Type ) \ - { +#define def_body_code_array_validation_start( Name_ ) \ +do \ +{ \ + Code entry = *codes; codes++; \ + \ + if ( ! entry ) \ + { \ + log_failure("gen::" stringize(Name_) ": Provided an null entry"); \ + return CodeInvalid; \ + } \ + \ + switch ( entry->Type ) \ + { -# define def_body_code_validation_end( Name_ ) \ - log_failure("gen::" stringize(Name_) ": Entry type is not allowed: %s", entry.debug_str() ); \ - return CodeInvalid; \ - \ - default: \ - break; \ - } \ - \ - result.append( entry ); \ - } \ - while ( num--, num > 0 ) +#define def_body_code_validation_end( Name_ ) \ + log_failure("gen::" stringize(Name_) ": Entry type is not allowed: %s", entry.debug_str() ); \ + return CodeInvalid; \ + \ + default: \ + break; \ + } \ + \ + result.append( entry ); \ +} \ +while ( num--, num > 0 ) #pragma endregion Helper Macros for def_**_body functions - CodeBody def_class_body( s32 num, ... ) +CodeBody def_class_body( s32 num, ... ) +{ + def_body_start( def_class_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Class_Body; + + va_list va; + va_start(va, num); + def_body_code_validation_start( def_class_body ); + AST_BODY_CLASS_UNALLOWED_TYPES + def_body_code_validation_end( def_class_body ); + va_end(va); + + return result; +} + +CodeBody def_class_body( s32 num, Code* codes ) +{ + def_body_code_array_start( def_class_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Function_Body; + + def_body_code_array_validation_start( def_class_body ); + AST_BODY_CLASS_UNALLOWED_TYPES + def_body_code_validation_end( def_class_body ); + + return result; +} + +CodeBody def_enum_body( s32 num, ... ) +{ + def_body_start( def_enum_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Enum_Body; + + va_list va; + va_start(va, num); + do { - def_body_start( def_class_body ); + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); - CodeBody - result = (CodeBody) make_code(); - result->Type = Class_Body; - - va_list va; - va_start(va, num); - def_body_code_validation_start( def_class_body ); - AST_BODY_CLASS_UNALLOWED_TYPES - def_body_code_validation_end( def_class_body ); - va_end(va); - - return result; - } - - CodeBody def_class_body( s32 num, Code* codes ) - { - def_body_code_array_start( def_class_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Function_Body; - - def_body_code_array_validation_start( def_class_body ); - AST_BODY_CLASS_UNALLOWED_TYPES - def_body_code_validation_end( def_class_body ); - - return result; - } - - CodeBody def_enum_body( s32 num, ... ) - { - def_body_start( def_enum_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Enum_Body; - - va_list va; - va_start(va, num); - do + if ( ! entry ) { - Code_POD pod = va_arg(va, Code_POD); - Code entry = pcast(Code, pod); - - if ( ! entry ) - { - log_failure("gen::def_enum_body: Provided a null entry"); - return CodeInvalid; - } - - if ( entry->Type != Untyped && entry->Type != Comment ) - { - log_failure("gen::def_enum_body: Entry type is not allowed - %s. Must be of untyped or comment type.", entry.debug_str() ); \ - return CodeInvalid; - } - - result.append( entry ); + log_failure("gen::def_enum_body: Provided a null entry"); + return CodeInvalid; } - while ( num--, num > 0 ); - va_end(va); - return (CodeBody) result; - } - - CodeBody def_enum_body( s32 num, Code* codes ) - { - def_body_code_array_start( def_enum_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Enum_Body; - - do + if ( entry->Type != Untyped && entry->Type != Comment ) { - Code entry = *codes; - - if ( ! entry ) - { - log_failure("gen::def_enum_body: Provided a null entry"); - return CodeInvalid; - } - - if ( entry->Type != Untyped && entry->Type != Comment ) - { - log_failure("gen::def_enum_body: Entry type is not allowed: %s", entry.debug_str() ); \ - return CodeInvalid; - } - - result.append( entry ); + log_failure("gen::def_enum_body: Entry type is not allowed - %s. Must be of untyped or comment type.", entry.debug_str() ); \ + return CodeInvalid; } - while ( codes++, num--, num > 0 ); - return result; + result.append( entry ); + } + while ( num--, num > 0 ); + va_end(va); + + return (CodeBody) result; +} + +CodeBody def_enum_body( s32 num, Code* codes ) +{ + def_body_code_array_start( def_enum_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Enum_Body; + + do + { + Code entry = *codes; + + if ( ! entry ) + { + log_failure("gen::def_enum_body: Provided a null entry"); + return CodeInvalid; + } + + if ( entry->Type != Untyped && entry->Type != Comment ) + { + log_failure("gen::def_enum_body: Entry type is not allowed: %s", entry.debug_str() ); \ + return CodeInvalid; + } + + result.append( entry ); + } + while ( codes++, num--, num > 0 ); + + return result; +} + +CodeBody def_export_body( s32 num, ... ) +{ + def_body_start( def_export_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Export_Body; + + va_list va; + va_start(va, num); + def_body_code_validation_start( def_export_body ); + AST_BODY_EXPORT_UNALLOWED_TYPES + def_body_code_validation_end( def_export_body ); + va_end(va); + + return result; +} + +CodeBody def_export_body( s32 num, Code* codes ) +{ + def_body_code_array_start( def_export_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Export_Body; + + def_body_code_array_validation_start( def_export_body ); + AST_BODY_EXPORT_UNALLOWED_TYPES + def_body_code_validation_end( def_export_body ); + + return result; +} + +CodeBody def_extern_link_body( s32 num, ... ) +{ + def_body_start( def_extern_linkage_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Extern_Linkage_Body; + + va_list va; + va_start(va, num); + def_body_code_validation_start( def_extern_linkage_body ); + AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES + def_body_code_validation_end( def_extern_linkage_body ); + va_end(va); + + return result; +} + +CodeBody def_extern_link_body( s32 num, Code* codes ) +{ + def_body_code_array_start( def_extern_linkage_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Extern_Linkage_Body; + + def_body_code_array_validation_start( def_extern_linkage_body ); + AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES + def_body_code_validation_end( def_extern_linkage_body ); + + return result; +} + +CodeBody def_function_body( s32 num, ... ) +{ + def_body_start( def_function_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Function_Body; + + va_list va; + va_start(va, num); + def_body_code_validation_start( def_function_body ); + AST_BODY_FUNCTION_UNALLOWED_TYPES + def_body_code_validation_end( def_function_body ); + va_end(va); + + return result; +} + +CodeBody def_function_body( s32 num, Code* codes ) +{ + def_body_code_array_start( def_function_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Function_Body; + + def_body_code_array_validation_start( def_function_body ); + AST_BODY_FUNCTION_UNALLOWED_TYPES + def_body_code_validation_end( def_function_body ); + + return result; +} + +CodeBody def_global_body( s32 num, ... ) +{ + def_body_start( def_global_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Global_Body; + + va_list va; + va_start(va, num); + def_body_code_validation_start( def_global_body ); + AST_BODY_GLOBAL_UNALLOWED_TYPES + def_body_code_validation_end( def_global_body ); + va_end(va); + + return result; +} + +CodeBody def_global_body( s32 num, Code* codes ) +{ + def_body_code_array_start( def_global_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Global_Body; + + def_body_code_array_validation_start( def_global_body ); + AST_BODY_GLOBAL_UNALLOWED_TYPES + def_body_code_validation_end( def_global_body ); + + return result; +} + +CodeBody def_namespace_body( s32 num, ... ) +{ + def_body_start( def_namespace_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Namespace_Body; + + va_list va; + va_start(va, num); + def_body_code_validation_start( def_namespace_body ); + AST_BODY_NAMESPACE_UNALLOWED_TYPES + def_body_code_validation_end( def_namespace_body ); + va_end(va); + + return result; +} + +CodeBody def_namespace_body( s32 num, Code* codes ) +{ + def_body_code_array_start( def_namespace_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Global_Body; + + def_body_code_array_validation_start( def_namespace_body ); + AST_BODY_NAMESPACE_UNALLOWED_TYPES + def_body_code_validation_end( def_namespace_body ); + + return result; +} + +CodeParam def_params( s32 num, ... ) +{ + def_body_start( def_params ); + + va_list va; + va_start(va, num); + + Code_POD pod = va_arg(va, Code_POD); + CodeParam param = pcast( CodeParam, pod ); + + null_check( def_params, param ); + + if ( param->Type != Parameters ) + { + log_failure( "gen::def_params: param %d is not a Parameters", num - num + 1 ); + return CodeInvalid; } - CodeBody def_export_body( s32 num, ... ) + CodeParam result = (CodeParam) param.duplicate(); + + while ( -- num ) { - def_body_start( def_export_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Export_Body; - - va_list va; - va_start(va, num); - def_body_code_validation_start( def_export_body ); - AST_BODY_EXPORT_UNALLOWED_TYPES - def_body_code_validation_end( def_export_body ); - va_end(va); - - return result; - } - - CodeBody def_export_body( s32 num, Code* codes ) - { - def_body_code_array_start( def_export_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Export_Body; - - def_body_code_array_validation_start( def_export_body ); - AST_BODY_EXPORT_UNALLOWED_TYPES - def_body_code_validation_end( def_export_body ); - - return result; - } - - CodeBody def_extern_link_body( s32 num, ... ) - { - def_body_start( def_extern_linkage_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Extern_Linkage_Body; - - va_list va; - va_start(va, num); - def_body_code_validation_start( def_extern_linkage_body ); - AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES - def_body_code_validation_end( def_extern_linkage_body ); - va_end(va); - - return result; - } - - CodeBody def_extern_link_body( s32 num, Code* codes ) - { - def_body_code_array_start( def_extern_linkage_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Extern_Linkage_Body; - - def_body_code_array_validation_start( def_extern_linkage_body ); - AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES - def_body_code_validation_end( def_extern_linkage_body ); - - return result; - } - - CodeBody def_function_body( s32 num, ... ) - { - def_body_start( def_function_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Function_Body; - - va_list va; - va_start(va, num); - def_body_code_validation_start( def_function_body ); - AST_BODY_FUNCTION_UNALLOWED_TYPES - def_body_code_validation_end( def_function_body ); - va_end(va); - - return result; - } - - CodeBody def_function_body( s32 num, Code* codes ) - { - def_body_code_array_start( def_function_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Function_Body; - - def_body_code_array_validation_start( def_function_body ); - AST_BODY_FUNCTION_UNALLOWED_TYPES - def_body_code_validation_end( def_function_body ); - - return result; - } - - CodeBody def_global_body( s32 num, ... ) - { - def_body_start( def_global_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Global_Body; - - va_list va; - va_start(va, num); - def_body_code_validation_start( def_global_body ); - AST_BODY_GLOBAL_UNALLOWED_TYPES - def_body_code_validation_end( def_global_body ); - va_end(va); - - return result; - } - - CodeBody def_global_body( s32 num, Code* codes ) - { - def_body_code_array_start( def_global_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Global_Body; - - def_body_code_array_validation_start( def_global_body ); - AST_BODY_GLOBAL_UNALLOWED_TYPES - def_body_code_validation_end( def_global_body ); - - return result; - } - - CodeBody def_namespace_body( s32 num, ... ) - { - def_body_start( def_namespace_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Namespace_Body; - - va_list va; - va_start(va, num); - def_body_code_validation_start( def_namespace_body ); - AST_BODY_NAMESPACE_UNALLOWED_TYPES - def_body_code_validation_end( def_namespace_body ); - va_end(va); - - return result; - } - - CodeBody def_namespace_body( s32 num, Code* codes ) - { - def_body_code_array_start( def_namespace_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Global_Body; - - def_body_code_array_validation_start( def_namespace_body ); - AST_BODY_NAMESPACE_UNALLOWED_TYPES - def_body_code_validation_end( def_namespace_body ); - - return result; - } - - CodeParam def_params( s32 num, ... ) - { - def_body_start( def_params ); - - va_list va; - va_start(va, num); - - Code_POD pod = va_arg(va, Code_POD); - CodeParam param = pcast( CodeParam, pod ); - - null_check( def_params, param ); + pod = va_arg(va, Code_POD); + param = pcast( CodeParam, pod ); if ( param->Type != Parameters ) { @@ -3074,221 +3087,208 @@ namespace gen return CodeInvalid; } - CodeParam result = (CodeParam) param.duplicate(); + result.append( param ); + } + va_end(va); - while ( -- num ) - { - pod = va_arg(va, Code_POD); - param = pcast( CodeParam, pod ); + return result; +} - if ( param->Type != Parameters ) - { - log_failure( "gen::def_params: param %d is not a Parameters", num - num + 1 ); - return CodeInvalid; - } +CodeParam def_params( s32 num, CodeParam* codes ) +{ + def_body_code_array_start( def_params ); - result.append( param ); - } - va_end(va); - - return result; +# define check_current() \ + if ( current.ast == nullptr ) \ + { \ + log_failure("gen::def_params: Provide a null code in codes array"); \ + return CodeInvalid; \ + } \ + \ + if (current->Type != Parameters ) \ + { \ + log_failure("gen::def_params: Code in coes array is not of paramter type - %s", current.debug_str() ); \ + return CodeInvalid; \ } - CodeParam def_params( s32 num, CodeParam* codes ) + CodeParam current = (CodeParam) codes->duplicate(); + check_current(); + + CodeParam + result = (CodeParam) make_code(); + result->Name = current->Name; + result->Type = current->Type; + result->ValueType = current->ValueType; + + while( codes++, current = * codes, num--, num > 0 ) { - def_body_code_array_start( def_params ); - - # define check_current() \ - if ( current.ast == nullptr ) \ - { \ - log_failure("gen::def_params: Provide a null code in codes array"); \ - return CodeInvalid; \ - } \ - \ - if (current->Type != Parameters ) \ - { \ - log_failure("gen::def_params: Code in coes array is not of paramter type - %s", current.debug_str() ); \ - return CodeInvalid; \ - } - - CodeParam current = (CodeParam) codes->duplicate(); check_current(); + result.append( current ); + } +# undef check_current - CodeParam - result = (CodeParam) make_code(); - result->Name = current->Name; - result->Type = current->Type; - result->ValueType = current->ValueType; + return result; +} - while( codes++, current = * codes, num--, num > 0 ) - { - check_current(); - result.append( current ); - } - # undef check_current - - return result; +CodeSpecifier def_specifiers( s32 num, ... ) +{ + if ( num <= 0 ) + { + log_failure("gen::def_specifiers: num cannot be zero or less"); + return CodeInvalid; } - CodeSpecifier def_specifiers( s32 num, ... ) + if ( num > AST::ArrSpecs_Cap ) { - if ( num <= 0 ) + log_failure("gen::def_specifiers: num of speciifers to define AST larger than AST specicifier capacity - %d", num); + return CodeInvalid; + } + + CodeSpecifier + result = (CodeSpecifier) make_code(); + result->Type = ECode::Specifiers; + + va_list va; + va_start(va, num); + do + { + SpecifierT type = (SpecifierT)va_arg(va, int); + + result.append( type ); + } + while ( --num, num ); + va_end(va); + + return result; +} + +CodeSpecifier def_specifiers( s32 num, SpecifierT* specs ) +{ + if ( num <= 0 ) + { + log_failure("gen::def_specifiers: num cannot be zero or less"); + return CodeInvalid; + } + + if ( num > AST::ArrSpecs_Cap ) + { + log_failure("gen::def_specifiers: num of speciifers to define AST larger than AST specicifier capacity - %d", num); + return CodeInvalid; + } + + CodeSpecifier + result = (CodeSpecifier) make_code(); + result->Type = ECode::Specifiers; + + s32 idx = 0; + do + { + result.append( specs[idx] ); + idx++; + } + while ( --num, num ); + + return result; +} + +CodeBody def_struct_body( s32 num, ... ) +{ + def_body_start( def_struct_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Struct_Body; + + va_list va; + va_start(va, num); + def_body_code_validation_start( def_struct_body ); + AST_BODY_STRUCT_UNALLOWED_TYPES + def_body_code_validation_end( def_struct_body ); + va_end(va); + + return result; +} + +CodeBody def_struct_body( s32 num, Code* codes ) +{ + def_body_code_array_start( def_struct_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Struct_Body; + + def_body_code_array_validation_start( def_struct_body ); + AST_BODY_STRUCT_UNALLOWED_TYPES + def_body_code_validation_end( def_struct_body ); + + return result; +} + +CodeBody def_union_body( s32 num, ... ) +{ + def_body_start( def_union_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Union_Body; + + va_list va; + va_start(va, num); + do + { + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast( Code, pod ); + + if ( ! entry ) { - log_failure("gen::def_specifiers: num cannot be zero or less"); + log_failure("gen::def_union_body: Provided a null entry"); return CodeInvalid; } - if ( num > AST::ArrSpecs_Cap ) + if ( entry->Type != Untyped && entry->Type != Comment ) { - log_failure("gen::def_specifiers: num of speciifers to define AST larger than AST specicifier capacity - %d", num); + log_failure("gen::def_union_body: Entry type is not allowed - %s. Must be of untyped or comment type.", entry.debug_str() ); \ return CodeInvalid; } - CodeSpecifier - result = (CodeSpecifier) make_code(); - result->Type = ECode::Specifiers; - - va_list va; - va_start(va, num); - do - { - SpecifierT type = (SpecifierT)va_arg(va, int); - - result.append( type ); - } - while ( --num, num ); - va_end(va); - - return result; + result.append( entry ); } + while ( num--, num > 0 ); + va_end(va); - CodeSpecifier def_specifiers( s32 num, SpecifierT* specs ) + return result; +} + +CodeBody def_union_body( s32 num, CodeUnion* codes ) +{ + def_body_code_array_start( def_union_body ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Union_Body; + + do { - if ( num <= 0 ) + Code entry = *codes; + + if ( ! entry ) { - log_failure("gen::def_specifiers: num cannot be zero or less"); + log_failure("gen::def_union_body: Provided a null entry"); return CodeInvalid; } - if ( num > AST::ArrSpecs_Cap ) + if ( entry->Type != Untyped && entry->Type != Comment ) { - log_failure("gen::def_specifiers: num of speciifers to define AST larger than AST specicifier capacity - %d", num); + log_failure("gen::def_union_body: Entry type is not allowed: %s", entry.debug_str() ); return CodeInvalid; } - CodeSpecifier - result = (CodeSpecifier) make_code(); - result->Type = ECode::Specifiers; - - s32 idx = 0; - do - { - result.append( specs[idx] ); - idx++; - } - while ( --num, num ); - - return result; + result.append( entry ); } + while ( codes++, num--, num > 0 ); - CodeBody def_struct_body( s32 num, ... ) - { - def_body_start( def_struct_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Struct_Body; - - va_list va; - va_start(va, num); - def_body_code_validation_start( def_struct_body ); - AST_BODY_STRUCT_UNALLOWED_TYPES - def_body_code_validation_end( def_struct_body ); - va_end(va); - - return result; - } - - CodeBody def_struct_body( s32 num, Code* codes ) - { - def_body_code_array_start( def_struct_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Struct_Body; - - def_body_code_array_validation_start( def_struct_body ); - AST_BODY_STRUCT_UNALLOWED_TYPES - def_body_code_validation_end( def_struct_body ); - - return result; - } - - CodeBody def_union_body( s32 num, ... ) - { - def_body_start( def_union_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Union_Body; - - va_list va; - va_start(va, num); - do - { - Code_POD pod = va_arg(va, Code_POD); - Code entry = pcast( Code, pod ); - - if ( ! entry ) - { - log_failure("gen::def_union_body: Provided a null entry"); - return CodeInvalid; - } - - if ( entry->Type != Untyped && entry->Type != Comment ) - { - log_failure("gen::def_union_body: Entry type is not allowed - %s. Must be of untyped or comment type.", entry.debug_str() ); \ - return CodeInvalid; - } - - result.append( entry ); - } - while ( num--, num > 0 ); - va_end(va); - - return result; - } - - CodeBody def_union_body( s32 num, CodeUnion* codes ) - { - def_body_code_array_start( def_union_body ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = Union_Body; - - do - { - Code entry = *codes; - - if ( ! entry ) - { - log_failure("gen::def_union_body: Provided a null entry"); - return CodeInvalid; - } - - if ( entry->Type != Untyped && entry->Type != Comment ) - { - log_failure("gen::def_union_body: Entry type is not allowed: %s", entry.debug_str() ); - return CodeInvalid; - } - - result.append( entry ); - } - while ( codes++, num--, num > 0 ); - - return (CodeBody) result; - } + return (CodeBody) result; +} # undef name_check # undef null_check @@ -3297,513 +3297,550 @@ namespace gen #pragma region Parsing Constructors /* - These constructors are the most implementation intensive other than the editor or scanner. +These constructors are the most implementation intensive other than the editor or scanner. */ - namespace Parser +namespace Parser +{ +/* + This is a simple lexer that focuses on tokenizing only tokens relevant to the library. + It will not be capable of lexing C++ code with unsupported features. + + For the sake of scanning files, it can scan preprocessor directives +*/ + +# define Define_TokType \ + Entry( Access_Private, "private" ) \ + Entry( Access_Protected, "protected" ) \ + Entry( Access_Public, "public" ) \ + Entry( Access_MemberSymbol, "." ) \ + Entry( Access_StaticSymbol, "::") \ + Entry( Ampersand, "&" ) \ + Entry( Ampersand_DBL, "&&" ) \ + Entry( Assign_Classifer, ":" ) \ + Entry( BraceCurly_Open, "{" ) \ + Entry( BraceCurly_Close, "}" ) \ + Entry( BraceSquare_Open, "[" ) \ + Entry( BraceSquare_Close, "]" ) \ + Entry( Capture_Start, "(" ) \ + Entry( Capture_End, ")" ) \ + Entry( Comment, "__comment__" ) \ + Entry( Char, "__char__" ) \ + Entry( Comma, "," ) \ + Entry( Decl_Class, "class" ) \ + Entry( Decl_Enum, "enum" ) \ + Entry( Decl_Extern_Linkage, "extern" ) \ + Entry( Decl_Friend, "friend" ) \ + Entry( Decl_Module, "module" ) \ + Entry( Decl_Namespace, "namespace" ) \ + Entry( Decl_Operator, "operator" ) \ + Entry( Decl_Struct, "struct" ) \ + Entry( Decl_Template, "template" ) \ + Entry( Decl_Typedef, "typedef" ) \ + Entry( Decl_Using, "using" ) \ + Entry( Decl_Union, "union" ) \ + Entry( Identifier, "__identifier__" ) \ + Entry( Module_Import, "import" ) \ + Entry( Module_Export, "export" ) \ + Entry( Number, "number" ) \ + Entry( Operator, "operator" ) \ + Entry( Preprocessor_Directive, "#") \ + Entry( Preprocessor_Include, "include" ) \ + Entry( Spec_Alignas, "alignas" ) \ + Entry( Spec_Const, "const" ) \ + Entry( Spec_Consteval, "consteval" ) \ + Entry( Spec_Constexpr, "constexpr" ) \ + Entry( Spec_Constinit, "constinit" ) \ + Entry( Spec_Extern, "extern" ) \ + Entry( Spec_Global, "global" ) \ + Entry( Spec_Inline, "inline" ) \ + Entry( Spec_Internal_Linkage, "internal" ) \ + Entry( Spec_LocalPersist, "local_persist" ) \ + Entry( Spec_Mutable, "mutable" ) \ + Entry( Spec_Static, "static" ) \ + Entry( Spec_ThreadLocal, "thread_local" ) \ + Entry( Spec_Volatile, "volatile") \ + Entry( Star, "*" ) \ + Entry( Statement_End, ";" ) \ + Entry( String, "__string__" ) \ + Entry( Type_Unsigned, "unsigned" ) \ + Entry( Type_Signed, "signed" ) \ + Entry( Type_Short, "short" ) \ + Entry( Type_Long, "long" ) \ + Entry( Type_char, "char" ) \ + Entry( Type_int, "int" ) \ + Entry( Type_double, "double" ) + + enum class TokType : u32 { - /* - This is a simple lexer that focuses on tokenizing only tokens relevant to the library. - It will not be capable of lexing C++ code with unsupported features. + # define Entry( Name_, Str_ ) Name_, + Define_TokType + # undef Entry + Attr_Keyword, - For the sake of scanning files, it can scan preprocessor directives - */ + Num, + Invalid + }; - # define Define_TokType \ - Entry( Access_Private, "private" ) \ - Entry( Access_Protected, "protected" ) \ - Entry( Access_Public, "public" ) \ - Entry( Access_MemberSymbol, "." ) \ - Entry( Access_StaticSymbol, "::") \ - Entry( Ampersand, "&" ) \ - Entry( Ampersand_DBL, "&&" ) \ - Entry( Assign_Classifer, ":" ) \ - Entry( BraceCurly_Open, "{" ) \ - Entry( BraceCurly_Close, "}" ) \ - Entry( BraceSquare_Open, "[" ) \ - Entry( BraceSquare_Close, "]" ) \ - Entry( Capture_Start, "(" ) \ - Entry( Capture_End, ")" ) \ - Entry( Comment, "__comment__" ) \ - Entry( Char, "__char__" ) \ - Entry( Comma, "," ) \ - Entry( Decl_Class, "class" ) \ - Entry( Decl_Enum, "enum" ) \ - Entry( Decl_Extern_Linkage, "extern" ) \ - Entry( Decl_Friend, "friend" ) \ - Entry( Decl_Module, "module" ) \ - Entry( Decl_Namespace, "namespace" ) \ - Entry( Decl_Operator, "operator" ) \ - Entry( Decl_Struct, "struct" ) \ - Entry( Decl_Template, "template" ) \ - Entry( Decl_Typedef, "typedef" ) \ - Entry( Decl_Using, "using" ) \ - Entry( Decl_Union, "union" ) \ - Entry( Identifier, "__identifier__" ) \ - Entry( Module_Import, "import" ) \ - Entry( Module_Export, "export" ) \ - Entry( Number, "number" ) \ - Entry( Operator, "operator" ) \ - Entry( Preprocessor_Directive, "#") \ - Entry( Preprocessor_Include, "include" ) \ - Entry( Spec_Alignas, "alignas" ) \ - Entry( Spec_Const, "const" ) \ - Entry( Spec_Consteval, "consteval" ) \ - Entry( Spec_Constexpr, "constexpr" ) \ - Entry( Spec_Constinit, "constinit" ) \ - Entry( Spec_Extern, "extern" ) \ - Entry( Spec_Global, "global" ) \ - Entry( Spec_Inline, "inline" ) \ - Entry( Spec_Internal_Linkage, "internal" ) \ - Entry( Spec_LocalPersist, "local_persist" ) \ - Entry( Spec_Mutable, "mutable" ) \ - Entry( Spec_Static, "static" ) \ - Entry( Spec_ThreadLocal, "thread_local" ) \ - Entry( Spec_Volatile, "volatile") \ - Entry( Star, "*" ) \ - Entry( Statement_End, ";" ) \ - Entry( String, "__string__" ) \ - Entry( Type_Unsigned, "unsigned" ) \ - Entry( Type_Signed, "signed" ) \ - Entry( Type_Short, "short" ) \ - Entry( Type_Long, "long" ) \ - Entry( Type_char, "char" ) \ - Entry( Type_int, "int" ) \ - Entry( Type_double, "double" ) + struct Token + { + char const* Text; + sptr Length; + TokType Type; + bool IsAssign; - enum class TokType : u32 + operator bool() { - # define Entry( Name_, Str_ ) Name_, + return Text && Length && Type != TokType::Invalid; + } + + operator StrC() + { + return { Length, Text }; + } + }; + + internal inline + TokType get_tok_type( char const* word, s32 length ) + { + local_persist + StrC lookup[(u32)TokType::Num] = + { + # define Entry( Name_, Str_ ) { sizeof(Str_), Str_ }, Define_TokType # undef Entry - Attr_Keyword, - Num, - Invalid + { sizeof(Attribute::Keyword), Attribute::Keyword }, }; - struct Token + for ( u32 index = 0; index < (u32)TokType::Num; index++ ) { - char const* Text; - sptr Length; - TokType Type; - bool IsAssign; + s32 lookup_len = lookup[index].Len - 1; + char const* lookup_str = lookup[index].Ptr; - operator bool() - { - return Text && Length && Type != TokType::Invalid; - } + if ( lookup_len != length ) + continue; - operator StrC() - { - return { Length, Text }; - } + if ( str_compare( word, lookup_str, lookup_len ) == 0 ) + return scast(TokType, index); + } + + return TokType::Invalid; + } + + internal inline + char const* str_tok_type( TokType type ) + { + local_persist + char const* lookup[(u32)TokType::Num] = + { + # define Entry( Name_, Str_ ) Str_, + Define_TokType + # undef Entry + + Attribute::Keyword, }; - internal inline - TokType get_tok_type( char const* word, s32 length ) + return lookup[(u32)type]; + } + +# undef Define_TokType + + internal inline + bool tok_is_specifier( Token const& tok ) + { + return (tok.Type <= TokType::Star && tok.Type >= TokType::Spec_Alignas) + || tok.Type == TokType::Ampersand + || tok.Type == TokType::Ampersand_DBL + ; + } + + internal inline + bool tok_is_access_specifier( Token const& tok ) + { + return tok.Type >= TokType::Access_Private && tok.Type <= TokType::Access_Public; + } + + internal inline + AccessSpec tok_to_access_specifier( Token const& tok ) + { + return scast(AccessSpec, tok.Type); + } + + + struct TokArray + { + Array Arr; + s32 Idx; + + bool __eat( TokType type, char const* context ) { - local_persist - StrC lookup[(u32)TokType::Num] = + if ( Arr.num() - Idx <= 0 ) { - # define Entry( Name_, Str_ ) { sizeof(Str_), Str_ }, - Define_TokType - # undef Entry - - { sizeof(Attribute::Keyword), Attribute::Keyword }, - }; - - for ( u32 index = 0; index < (u32)TokType::Num; index++ ) - { - s32 lookup_len = lookup[index].Len - 1; - char const* lookup_str = lookup[index].Ptr; - - if ( lookup_len != length ) - continue; - - if ( str_compare( word, lookup_str, lookup_len ) == 0 ) - return scast(TokType, index); + log_failure( "gen::%s: No tokens left", context ); + return Code::Invalid; } - return TokType::Invalid; + if ( Arr[Idx].Type != type ) + { + String token_str = String::make( GlobalAllocator, { Arr[Idx].Length, Arr[Idx].Text } ); + + log_failure( "gen::%s: expected %s, got %s", context, str_tok_type(type), str_tok_type(Arr[Idx].Type) ); + + return Code::Invalid; + } + + Idx++; + return true; } - internal inline - char const* str_tok_type( TokType type ) + Token& current() { - local_persist - char const* lookup[(u32)TokType::Num] = - { - # define Entry( Name_, Str_ ) Str_, - Define_TokType - # undef Entry - - Attribute::Keyword, - }; - - return lookup[(u32)type]; + return Arr[Idx]; } - # undef Define_TokType - - internal inline - bool tok_is_specifier( Token const& tok ) + Token& previous() { - return (tok.Type <= TokType::Star && tok.Type >= TokType::Spec_Alignas) - || tok.Type == TokType::Ampersand - || tok.Type == TokType::Ampersand_DBL - ; + return Arr[Idx - 1]; } - internal inline - bool tok_is_access_specifier( Token const& tok ) + Token* next() { - return tok.Type >= TokType::Access_Private && tok.Type <= TokType::Access_Public; + return Idx + 1 < Arr.num() ? &Arr[Idx + 1] : nullptr; + } + }; + + TokArray lex( StrC content, bool keep_preprocess_directives = false ) + { + # define current ( * scanner ) + + # define move_forward() \ + left--; \ + scanner++ + + # define SkipWhitespace() \ + while ( left && char_is_space( current ) ) \ + { \ + move_forward(); \ } - internal inline - AccessSpec tok_to_access_specifier( Token const& tok ) - { - return scast(AccessSpec, tok.Type); + # define SkipWhitespace_Checked( Context_, Msg_, ... ) \ + while ( left && char_is_space( current ) ) \ + { \ + move_forward(); \ + } \ + if ( left <= 0 ) \ + { \ + log_failure( "gen::" txt(Context_) ": " Msg_, __VA_ARGS__ ); \ + return { 0, nullptr }; \ } + local_persist thread_local + Array Tokens = { nullptr }; - struct TokArray + s32 left = content.Len; + char const* scanner = content.Ptr; + + char const* word = scanner; + s32 word_length = 0; + + SkipWhitespace(); + if ( left <= 0 ) { - Array Arr; - s32 Idx; + log_failure( "gen::lex: no tokens found (only whitespace provided)" ); + return { { nullptr }, 0 }; + } - bool __eat( TokType type, char const* context ) - { - if ( Arr.num() - Idx <= 0 ) - { - log_failure( "gen::%s: No tokens left", context ); - return Code::Invalid; - } - - if ( Arr[Idx].Type != type ) - { - String token_str = String::make( GlobalAllocator, { Arr[Idx].Length, Arr[Idx].Text } ); - - log_failure( "gen::%s: expected %s, got %s", context, str_tok_type(type), str_tok_type(Arr[Idx].Type) ); - - return Code::Invalid; - } - - Idx++; - return true; - } - - Token& current() - { - return Arr[Idx]; - } - - Token& previous() - { - return Arr[Idx - 1]; - } - - Token* next() - { - return Idx + 1 < Arr.num() ? &Arr[Idx + 1] : nullptr; - } - }; - - TokArray lex( StrC content, bool keep_preprocess_directives = false ) + if ( Tokens ) { - # define current ( * scanner ) + Tokens.free(); + } - # define move_forward() \ - left--; \ - scanner++ + Tokens = Array::init_reserve( LexArena, content.Len / 6 ); - # define SkipWhitespace() \ - while ( left && char_is_space( current ) ) \ - { \ - move_forward(); \ - } - - # define SkipWhitespace_Checked( Context_, Msg_, ... ) \ - while ( left && char_is_space( current ) ) \ - { \ - move_forward(); \ - } \ - if ( left <= 0 ) \ - { \ - log_failure( "gen::" txt(Context_) ": " Msg_, __VA_ARGS__ ); \ - return { 0, nullptr }; \ - } - - local_persist thread_local - Array Tokens = { nullptr }; - - s32 left = content.Len; - char const* scanner = content.Ptr; - - char const* word = scanner; - s32 word_length = 0; + while (left ) + { + Token token = { nullptr, 0, TokType::Invalid, false }; SkipWhitespace(); if ( left <= 0 ) + break; + + switch ( current ) { - log_failure( "gen::lex: no tokens found (only whitespace provided)" ); - return { { nullptr }, 0 }; - } + case '#': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::Preprocessor_Directive; + move_forward(); - if ( Tokens ) - { - Tokens.free(); - } - - Tokens = Array::init_reserve( LexArena, content.Len / 6 ); - - while (left ) - { - Token token = { nullptr, 0, TokType::Invalid, false }; - - SkipWhitespace(); - if ( left <= 0 ) - break; - - switch ( current ) - { - case '#': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Preprocessor_Directive; - move_forward(); - - while (left && current != '\n' ) + while (left && current != '\n' ) + { + if ( current == '\\' ) { - if ( current == '\\' ) + move_forward(); + + if ( current != '\n' && keep_preprocess_directives ) { - move_forward(); - - if ( current != '\n' && keep_preprocess_directives ) - { - log_failure( "gen::lex: invalid preprocessor directive, will still grab but will not compile %s", token.Text ); - } - } - - move_forward(); - token.Length++; - } - goto FoundToken; - - case '.': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Access_MemberSymbol; - - if (left) - move_forward(); - goto FoundToken; - - case '&' : - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Ampersand; - - if (left) - move_forward(); - - if ( current == '&' ) // && - { - token.Length = 2; - token.Type = TokType::Ampersand_DBL; - - if (left) - move_forward(); - } - - goto FoundToken; - - case ':': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Assign_Classifer; - - if (left) - move_forward(); - - if ( current == ':' ) - { - move_forward(); - token.Type = TokType::Access_StaticSymbol; - token.Length++; - } - goto FoundToken; - - case '{': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::BraceCurly_Open; - - if (left) - move_forward(); - goto FoundToken; - - case '}': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::BraceCurly_Close; - - if (left) - move_forward(); - goto FoundToken; - - case '[': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::BraceSquare_Open; - if ( left ) - { - move_forward(); - - if ( current == ']' ) - { - token.Length = 2; - token.Type = TokType::Operator; - move_forward(); + log_failure( "gen::lex: invalid preprocessor directive, will still grab but will not compile %s", token.Text ); } } - goto FoundToken; - - case ']': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::BraceSquare_Close; - - if (left) - move_forward(); - goto FoundToken; - - case '(': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Capture_Start; - - if (left) - move_forward(); - goto FoundToken; - - case ')': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Capture_End; - - if (left) - move_forward(); - goto FoundToken; - - case '\'': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Char; move_forward(); + token.Length++; + } + goto FoundToken; - while ( left && current != '\'' ) + case '.': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::Access_MemberSymbol; + + if (left) + move_forward(); + goto FoundToken; + + case '&' : + token.Text = scanner; + token.Length = 1; + token.Type = TokType::Ampersand; + + if (left) + move_forward(); + + if ( current == '&' ) // && + { + token.Length = 2; + token.Type = TokType::Ampersand_DBL; + + if (left) + move_forward(); + } + + goto FoundToken; + + case ':': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::Assign_Classifer; + + if (left) + move_forward(); + + if ( current == ':' ) + { + move_forward(); + token.Type = TokType::Access_StaticSymbol; + token.Length++; + } + goto FoundToken; + + case '{': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::BraceCurly_Open; + + if (left) + move_forward(); + goto FoundToken; + + case '}': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::BraceCurly_Close; + + if (left) + move_forward(); + goto FoundToken; + + case '[': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::BraceSquare_Open; + if ( left ) + { + move_forward(); + + if ( current == ']' ) + { + token.Length = 2; + token.Type = TokType::Operator; + move_forward(); + } + } + goto FoundToken; + + case ']': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::BraceSquare_Close; + + if (left) + move_forward(); + goto FoundToken; + + case '(': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::Capture_Start; + + if (left) + move_forward(); + goto FoundToken; + + case ')': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::Capture_End; + + if (left) + move_forward(); + goto FoundToken; + + case '\'': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::Char; + + move_forward(); + + while ( left && current != '\'' ) + { + move_forward(); + token.Length++; + } + + if ( left ) + { + move_forward(); + token.Length++; + } + goto FoundToken; + + case ',': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::Comma; + + if (left) + move_forward(); + goto FoundToken; + + case '*': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::Star; + + if (left) + move_forward(); + goto FoundToken; + + case ';': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::Statement_End; + + if (left) + move_forward(); + goto FoundToken; + + case '"': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::String; + + move_forward(); + while ( left ) + { + if ( current == '"' ) + { + move_forward(); + break; + } + + if ( current == '\\' ) { move_forward(); token.Length++; - } - if ( left ) - { - move_forward(); - token.Length++; - } - goto FoundToken; - - case ',': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Comma; - - if (left) - move_forward(); - goto FoundToken; - - case '*': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Star; - - if (left) - move_forward(); - goto FoundToken; - - case ';': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Statement_End; - - if (left) - move_forward(); - goto FoundToken; - - case '"': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::String; - - move_forward(); - while ( left ) - { - if ( current == '"' ) - { - move_forward(); - break; - } - - if ( current == '\\' ) + if ( left ) { move_forward(); token.Length++; - - if ( left ) - { - move_forward(); - token.Length++; - } - continue; } - - move_forward(); - token.Length++; + continue; } - goto FoundToken; - // All other operators we just label as an operator and move forward. - case '=': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Operator; + move_forward(); + token.Length++; + } + goto FoundToken; + + // All other operators we just label as an operator and move forward. + case '=': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::Operator; + token.IsAssign = true; + + if (left) + move_forward(); + + goto FoundToken; + + case '+': + case '%': + case '^': + case '~': + case '!': + case '<': + case '>': + case '|': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::Operator; + + if (left) + move_forward(); + + if ( current == '=' ) + { + token.Length++; token.IsAssign = true; if (left) move_forward(); - - goto FoundToken; - - case '+': - case '%': - case '^': - case '~': - case '!': - case '<': - case '>': - case '|': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Operator; + } + else while ( left && current == *(scanner - 1) && token.Length < 3 ) + { + token.Length++; if (left) move_forward(); + } + goto FoundToken; - if ( current == '=' ) + // Dash is unfortunatlly a bit more complicated... + case '-': + token.Text = scanner; + token.Length = 1; + token.Type = TokType::Operator; + if ( left ) + { + move_forward(); + + if ( current == '>' ) + { + token.Length++; + move_forward(); + + if ( current == '*' ) + { + token.Length++; + move_forward(); + } + } + else if ( current == '=' ) { token.Length++; token.IsAssign = true; @@ -3818,96 +3855,85 @@ namespace gen if (left) move_forward(); } - goto FoundToken; + } + goto FoundToken; - // Dash is unfortunatlly a bit more complicated... - case '-': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Operator; - if ( left ) - { - move_forward(); - - if ( current == '>' ) - { - token.Length++; - move_forward(); - - if ( current == '*' ) - { - token.Length++; - move_forward(); - } - } - else if ( current == '=' ) - { - token.Length++; - token.IsAssign = true; - - if (left) - move_forward(); - } - else while ( left && current == *(scanner - 1) && token.Length < 3 ) - { - token.Length++; - - if (left) - move_forward(); - } - } - goto FoundToken; - - case '/': - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Operator; - - if ( left ) - { - move_forward(); - - if ( current == '/' ) - { - token.Type = TokType::Comment; - - move_forward(); - token.Text = scanner; - token.Length = 0; - - while ( left && current != '\n' ) - { - move_forward(); - token.Length++; - } - } - else if ( current == '*' ) - { - token.Type = TokType::Comment; - - move_forward(); - token.Text = scanner; - token.Length = 0; - - while ( left && ( current != '*' && *(scanner + 1) != '/' ) ) - { - move_forward(); - token.Length++; - } - move_forward(); - move_forward(); - } - } - goto FoundToken; - } - - if ( char_is_alpha( current ) || current == '_' ) - { + case '/': token.Text = scanner; token.Length = 1; - move_forward(); + token.Type = TokType::Operator; - while ( left && ( char_is_alphanumeric(current) || current == '_' ) ) + if ( left ) + { + move_forward(); + + if ( current == '/' ) + { + token.Type = TokType::Comment; + + move_forward(); + token.Text = scanner; + token.Length = 0; + + while ( left && current != '\n' ) + { + move_forward(); + token.Length++; + } + } + else if ( current == '*' ) + { + token.Type = TokType::Comment; + + move_forward(); + token.Text = scanner; + token.Length = 0; + + while ( left && ( current != '*' && *(scanner + 1) != '/' ) ) + { + move_forward(); + token.Length++; + } + move_forward(); + move_forward(); + } + } + goto FoundToken; + } + + if ( char_is_alpha( current ) || current == '_' ) + { + token.Text = scanner; + token.Length = 1; + move_forward(); + + while ( left && ( char_is_alphanumeric(current) || current == '_' ) ) + { + move_forward(); + token.Length++; + } + + goto FoundToken; + } + else if ( char_is_digit(current) ) + { + // This is a very brute force lex, no checks are done for validity of literal. + + token.Text = scanner; + token.Length = 1; + token.Type = TokType::Number; + move_forward(); + + if (left + && ( current == 'x' || current == 'X' + || current == 'b' || current == 'B' + || current == 'o' || current == 'O' ) + ) + { + move_forward(); + token.Length++; + + while ( left && char_is_hex_digit(current) ) { move_forward(); token.Length++; @@ -3915,112 +3941,86 @@ namespace gen goto FoundToken; } - else if ( char_is_digit(current) ) + + while ( left && char_is_digit(current) ) { - // This is a very brute force lex, no checks are done for validity of literal. - - token.Text = scanner; - token.Length = 1; - token.Type = TokType::Number; move_forward(); + token.Length++; + } - if (left - && ( current == 'x' || current == 'X' - || current == 'b' || current == 'B' - || current == 'o' || current == 'O' ) - ) - { - move_forward(); - token.Length++; - - while ( left && char_is_hex_digit(current) ) - { - move_forward(); - token.Length++; - } - - goto FoundToken; - } + if ( left && current == '.' ) + { + move_forward(); + token.Length++; while ( left && char_is_digit(current) ) { move_forward(); token.Length++; } - - if ( left && current == '.' ) - { - move_forward(); - token.Length++; - - while ( left && char_is_digit(current) ) - { - move_forward(); - token.Length++; - } - } - - goto FoundToken; - } - else - { - String context_str = String::fmt_buf( GlobalAllocator, "%s", scanner, min( 100, left ) ); - - log_failure( "Failed to lex token %s", context_str ); - - // Skip to next whitespace since we can't know if anything else is valid until then. - while ( left && ! char_is_space( current ) ) - { - move_forward(); - } } - FoundToken: - - if ( token.Type != TokType::Invalid ) - { - if ( token.Type == TokType::Preprocessor_Directive && keep_preprocess_directives == false ) - continue; - - Tokens.append( token ); - continue; - } - - TokType type = get_tok_type( token.Text, token.Length ); - - if ( type == TokType::Invalid) - type = TokType::Identifier; - - token.Type = type; - Tokens.append( token ); + goto FoundToken; } - - if ( Tokens.num() == 0 ) + else { - log_failure( "Failed to lex any tokens" ); - return { { nullptr }, 0 }; + String context_str = String::fmt_buf( GlobalAllocator, "%s", scanner, min( 100, left ) ); + + log_failure( "Failed to lex token %s", context_str ); + + // Skip to next whitespace since we can't know if anything else is valid until then. + while ( left && ! char_is_space( current ) ) + { + move_forward(); + } } - return { Tokens, 0 }; - # undef current - # undef move_forward - # undef SkipWhitespace - # undef SkipWhitespace_Checked + FoundToken: + + if ( token.Type != TokType::Invalid ) + { + if ( token.Type == TokType::Preprocessor_Directive && keep_preprocess_directives == false ) + continue; + + Tokens.append( token ); + continue; + } + + TokType type = get_tok_type( token.Text, token.Length ); + + if ( type == TokType::Invalid) + type = TokType::Identifier; + + token.Type = type; + Tokens.append( token ); } + + if ( Tokens.num() == 0 ) + { + log_failure( "Failed to lex any tokens" ); + return { { nullptr }, 0 }; + } + + return { Tokens, 0 }; + # undef current + # undef move_forward + # undef SkipWhitespace + # undef SkipWhitespace_Checked } +} #pragma region Helper Macros # define check_parse_args( func, def ) \ - if ( def.Len <= 0 ) \ - { \ - log_failure( "gen::" stringize(func) ": length must greater than 0" ); \ - return CodeInvalid; \ - } \ - if ( def.Ptr == nullptr ) \ - { \ - log_failure( "gen::" stringize(func) ": def was null" ); \ - return CodeInvalid; \ - } +if ( def.Len <= 0 ) \ +{ \ + log_failure( "gen::" stringize(func) ": length must greater than 0" ); \ + return CodeInvalid; \ +} \ +if ( def.Ptr == nullptr ) \ +{ \ + log_failure( "gen::" stringize(func) ": def was null" ); \ + return CodeInvalid; \ +} # define nexttok toks.next() # define currtok toks.current() @@ -4031,143 +4031,200 @@ namespace gen # define check( Type_ ) ( left && currtok.Type == Type_ ) #pragma endregion Helper Macros - struct ParseContext +struct ParseContext +{ + ParseContext* Parent; + char const* Fn; +}; + +internal Code parse_function_body ( Parser::TokArray& toks, char const* context ); +internal Code parse_global_nspace ( Parser::TokArray& toks, char const* context ); + +internal CodeClass parse_class ( Parser::TokArray& toks, char const* context ); +internal CodeEnum parse_enum ( Parser::TokArray& toks, char const* context ); +internal CodeBody parse_export_body ( Parser::TokArray& toks, char const* context ); +internal CodeBody parse_extern_link_body ( Parser::TokArray& toks, char const* context ); +internal CodeExtern parse_exten_link ( Parser::TokArray& toks, char const* context ); +internal CodeFriend parse_friend ( Parser::TokArray& toks, char const* context ); +internal CodeFn parse_function ( Parser::TokArray& toks, char const* context ); +internal CodeNamespace parse_namespace ( Parser::TokArray& toks, char const* context ); +internal CodeOpCast parse_operator_cast ( Parser::TokArray& toks, char const* context ); +internal CodeStruct parse_struct ( Parser::TokArray& toks, char const* context ); +internal CodeVar parse_variable ( Parser::TokArray& toks, char const* context ); +internal CodeTemplate parse_template ( Parser::TokArray& toks, char const* context ); +internal CodeType parse_type ( Parser::TokArray& toks, char const* context ); +internal CodeTypedef parse_typedef ( Parser::TokArray& toks, char const* context ); +internal CodeUnion parse_union ( Parser::TokArray& toks, char const* context ); +internal CodeUsing parse_using ( Parser::TokArray& toks, char const* context ); + +internal inline +Code parse_array_decl( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + + if ( check( TokType::BraceSquare_Open ) ) { - ParseContext* Parent; - char const* Fn; - }; + eat( TokType::BraceSquare_Open ); - internal Code parse_function_body ( Parser::TokArray& toks, char const* context ); - internal Code parse_global_nspace ( Parser::TokArray& toks, char const* context ); - - internal CodeClass parse_class ( Parser::TokArray& toks, char const* context ); - internal CodeEnum parse_enum ( Parser::TokArray& toks, char const* context ); - internal CodeBody parse_export_body ( Parser::TokArray& toks, char const* context ); - internal CodeBody parse_extern_link_body ( Parser::TokArray& toks, char const* context ); - internal CodeExtern parse_exten_link ( Parser::TokArray& toks, char const* context ); - internal CodeFriend parse_friend ( Parser::TokArray& toks, char const* context ); - internal CodeFn parse_function ( Parser::TokArray& toks, char const* context ); - internal CodeNamespace parse_namespace ( Parser::TokArray& toks, char const* context ); - internal CodeOpCast parse_operator_cast ( Parser::TokArray& toks, char const* context ); - internal CodeStruct parse_struct ( Parser::TokArray& toks, char const* context ); - internal CodeVar parse_variable ( Parser::TokArray& toks, char const* context ); - internal CodeTemplate parse_template ( Parser::TokArray& toks, char const* context ); - internal CodeType parse_type ( Parser::TokArray& toks, char const* context ); - internal CodeTypedef parse_typedef ( Parser::TokArray& toks, char const* context ); - internal CodeUnion parse_union ( Parser::TokArray& toks, char const* context ); - internal CodeUsing parse_using ( Parser::TokArray& toks, char const* context ); - - internal inline - Code parse_array_decl( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - - if ( check( TokType::BraceSquare_Open ) ) + if ( left == 0 ) { - eat( TokType::BraceSquare_Open ); - - if ( left == 0 ) - { - log_failure( "%s: Error, unexpected end of typedef definition ( '[]' scope started )", stringize(parse_typedef) ); - return Code::Invalid; - } - - if ( currtok.Type == TokType::BraceSquare_Close ) - { - log_failure( "%s: Error, empty array expression in typedef definition", stringize(parse_typedef) ); - return Code::Invalid; - } - - Token untyped_tok = currtok; - - while ( left && currtok.Type != TokType::BraceSquare_Close ) - { - eat( currtok.Type ); - } - - untyped_tok.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)untyped_tok.Text; - - Code array_expr = untyped_str( untyped_tok ); - - if ( left == 0 ) - { - log_failure( "%s: Error, unexpected end of type definition, expected ]", stringize(parse_typedef) ); - return Code::Invalid; - } - - if ( currtok.Type != TokType::BraceSquare_Close ) - { - log_failure( "%s: Error, expected ] in type definition, not %s", stringize(parse_typedef), str_tok_type( currtok.Type ) ); - return Code::Invalid; - } - - eat( TokType::BraceSquare_Close ); - return array_expr; + log_failure( "%s: Error, unexpected end of typedef definition ( '[]' scope started )", stringize(parse_typedef) ); + return Code::Invalid; } + if ( currtok.Type == TokType::BraceSquare_Close ) + { + log_failure( "%s: Error, empty array expression in typedef definition", stringize(parse_typedef) ); + return Code::Invalid; + } + + Token untyped_tok = currtok; + + while ( left && currtok.Type != TokType::BraceSquare_Close ) + { + eat( currtok.Type ); + } + + untyped_tok.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)untyped_tok.Text; + + Code array_expr = untyped_str( untyped_tok ); + + if ( left == 0 ) + { + log_failure( "%s: Error, unexpected end of type definition, expected ]", stringize(parse_typedef) ); + return Code::Invalid; + } + + if ( currtok.Type != TokType::BraceSquare_Close ) + { + log_failure( "%s: Error, expected ] in type definition, not %s", stringize(parse_typedef), str_tok_type( currtok.Type ) ); + return Code::Invalid; + } + + eat( TokType::BraceSquare_Close ); + return array_expr; + } + + return { nullptr }; +} + +internal inline +Parser::Token parse_identifier( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + Token name = currtok; + + eat( TokType::Identifier ); + + while ( check( TokType::Access_StaticSymbol ) ) + { + eat( TokType::Access_StaticSymbol ); + + if ( left == 0 ) + { + log_failure( "%s: Error, unexpected end of type definition, expected identifier", context ); + return { nullptr, 0, TokType::Invalid }; + } + + if ( currtok.Type != TokType::Identifier ) + { + log_failure( "%s: Error, expected identifier in type definition, not %s", context, str_tok_type( currtok.Type ) ); + return { nullptr, 0, TokType::Invalid }; + } + + name.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)name.Text; + eat( TokType::Identifier ); + } + + return name; +} + +internal +CodeParam parse_params( Parser::TokArray& toks, char const* context, bool use_template_capture = false ) +{ + using namespace Parser; + using namespace ECode; + + if ( ! use_template_capture ) + eat( TokType::Capture_Start ); + + else + { + if ( check ( TokType::Operator ) && currtok.Text[0] == '<' ) + eat( TokType::Operator ); + } + + if ( ! use_template_capture && check(TokType::Capture_End) ) + { + eat( TokType::Capture_End ); return { nullptr }; } - internal inline - Parser::Token parse_identifier( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - Token name = currtok; + CodeType type = { nullptr }; + Code value = { nullptr }; + type = parse_type( toks, context ); + if ( type == Code::Invalid ) + return CodeInvalid; + + Token name = { nullptr, 0, TokType::Invalid, false }; + + if ( check( TokType::Identifier ) ) + { + name = currtok; eat( TokType::Identifier ); - while ( check( TokType::Access_StaticSymbol ) ) + if ( currtok.IsAssign ) { - eat( TokType::Access_StaticSymbol ); + eat( TokType::Operator ); - if ( left == 0 ) + Token value_tok = currtok; + + if ( currtok.Type == TokType::Statement_End ) { - log_failure( "%s: Error, unexpected end of type definition, expected identifier", context ); - return { nullptr, 0, TokType::Invalid }; + log_failure( "gen::%s: Expected value after assignment operator", context ); + return CodeInvalid; } - if ( currtok.Type != TokType::Identifier ) + while ( left && currtok.Type != TokType::Statement_End ) { - log_failure( "%s: Error, expected identifier in type definition, not %s", context, str_tok_type( currtok.Type ) ); - return { nullptr, 0, TokType::Invalid }; + value_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)value_tok.Text; + eat( currtok.Type ); } - name.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)name.Text; - eat( TokType::Identifier ); + value = parse_type( toks, context ); } - - return name; } - internal - CodeParam parse_params( Parser::TokArray& toks, char const* context, bool use_template_capture = false ) + CodeParam + result = (CodeParam) make_code(); + result->Type = Parameters; + + if ( name.Length > 0 ) + result->Name = get_cached_string( name ); + + result->ValueType = type; + + if ( value ) + result->Value = value; + + result->NumEntries++; + + while ( left + && use_template_capture ? + currtok.Type != TokType::Operator && currtok.Text[0] != '>' + : currtok.Type != TokType::Capture_End ) { - using namespace Parser; - using namespace ECode; + eat( TokType::Comma ); - if ( ! use_template_capture ) - eat( TokType::Capture_Start ); - - else - { - if ( check ( TokType::Operator ) && currtok.Text[0] == '<' ) - eat( TokType::Operator ); - } - - if ( ! use_template_capture && check(TokType::Capture_End) ) - { - eat( TokType::Capture_End ); - return { nullptr }; - } - - CodeType type = { nullptr }; - Code value = { nullptr }; + Code type = { nullptr }; + Code value = { nullptr }; type = parse_type( toks, context ); if ( type == Code::Invalid ) return CodeInvalid; - Token name = { nullptr, 0, TokType::Invalid, false }; + name = { nullptr, 0, TokType::Invalid, false }; if ( check( TokType::Identifier ) ) { @@ -4197,816 +4254,1429 @@ namespace gen } CodeParam - result = (CodeParam) make_code(); - result->Type = Parameters; + param = (CodeParam) make_code(); + param->Type = Parameters; if ( name.Length > 0 ) - result->Name = get_cached_string( name ); + param->Name = get_cached_string( name ); - result->ValueType = type; + param->ValueType = type; if ( value ) - result->Value = value; + param->Value = value; - result->NumEntries++; - - while ( left - && use_template_capture ? - currtok.Type != TokType::Operator && currtok.Text[0] != '>' - : currtok.Type != TokType::Capture_End ) - { - eat( TokType::Comma ); - - Code type = { nullptr }; - Code value = { nullptr }; - - type = parse_type( toks, context ); - if ( type == Code::Invalid ) - return CodeInvalid; - - name = { nullptr, 0, TokType::Invalid, false }; - - if ( check( TokType::Identifier ) ) - { - name = currtok; - eat( TokType::Identifier ); - - if ( currtok.IsAssign ) - { - eat( TokType::Operator ); - - Token value_tok = currtok; - - if ( currtok.Type == TokType::Statement_End ) - { - log_failure( "gen::%s: Expected value after assignment operator", context ); - return CodeInvalid; - } - - while ( left && currtok.Type != TokType::Statement_End ) - { - value_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)value_tok.Text; - eat( currtok.Type ); - } - - value = parse_type( toks, context ); - } - } - - CodeParam - param = (CodeParam) make_code(); - param->Type = Parameters; - - if ( name.Length > 0 ) - param->Name = get_cached_string( name ); - - param->ValueType = type; - - if ( value ) - param->Value = value; - - result.append( param ); - } - - if ( ! use_template_capture ) - eat( TokType::Capture_End ); - - else - { - if ( ! check( TokType::Operator) || currtok.Text[0] != '>' ) - { - log_failure("gen::parse_template: expected '<' after 'template' keyword. %s", str_tok_type( currtok.Type )); - return CodeInvalid; - } - eat( TokType::Operator ); - } - - return result; - # undef context + result.append( param ); } - // Function parsing is handled in multiple places because its initial signature is shared with variable parsing - internal inline - CodeFn parse_function_after_name( - ModuleFlag mflags - , CodeAttributes attributes - , CodeSpecifier specifiers - , CodeType ret_type - , StrC name - , Parser::TokArray& toks - , char const* context - ) + if ( ! use_template_capture ) + eat( TokType::Capture_End ); + + else { - using namespace Parser; - - CodeParam params = parse_params( toks, stringize(parse_function) ); - - CodeBody body = { nullptr }; - if ( check( TokType::BraceCurly_Open ) ) + if ( ! check( TokType::Operator) || currtok.Text[0] != '>' ) { - body = parse_function_body( toks, stringize(parse_function) ); - if ( body == Code::Invalid ) - return CodeInvalid; - } - else - { - eat( TokType::Statement_End ); - } - - using namespace ECode; - - CodeFn - result = (CodeFn) make_code(); - result->Name = get_cached_string( name ); - result->ModuleFlags = mflags; - - 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 CodeInvalid; - } - } - - result->Type = Function; - result->Body = body; - } - else - { - result->Type = Function_Fwd; - } - - if ( specifiers ) - result->Specs = specifiers; - - result->ReturnType = ret_type; - - if ( params ) - result->Params = params; - - return result; - } - - internal inline - CodeOperator parse_operator_after_ret_type( ModuleFlag mflags - , CodeAttributes attributes - , CodeSpecifier specifiers - , CodeType ret_type - , Parser::TokArray& toks - , char const* context ) - { - using namespace Parser; - using namespace EOperator; - - // Parse Operator - eat( TokType::Decl_Operator ); - - if ( ! check( TokType::Operator ) ) - { - log_failure( "gen::%s: Expected operator after 'operator' keyword", context ); + log_failure("gen::parse_template: expected '<' after 'template' keyword. %s", str_tok_type( currtok.Type )); return CodeInvalid; } + eat( TokType::Operator ); + } - OperatorT op = Invalid; - switch ( currtok.Text[0] ) + return result; +# undef context +} + +// Function parsing is handled in multiple places because its initial signature is shared with variable parsing +internal inline +CodeFn parse_function_after_name( + ModuleFlag mflags + , CodeAttributes attributes + , CodeSpecifier specifiers + , CodeType ret_type + , StrC name + , Parser::TokArray& toks + , char const* context +) +{ + using namespace Parser; + + CodeParam params = parse_params( toks, stringize(parse_function) ); + + CodeBody body = { nullptr }; + if ( check( TokType::BraceCurly_Open ) ) + { + body = parse_function_body( toks, stringize(parse_function) ); + if ( body == Code::Invalid ) + return CodeInvalid; + } + else + { + eat( TokType::Statement_End ); + } + + using namespace ECode; + + CodeFn + result = (CodeFn) make_code(); + result->Name = get_cached_string( name ); + result->ModuleFlags = mflags; + + if ( body ) + { + switch ( body->Type ) { - case '+': - { - if ( currtok.Text[1] == '=' ) - op = Assign_Add; + case Function_Body: + case Untyped: + break; - else - op = Add; - } - break; - case '-': - { - if ( currtok.Text[1] == '=' ) - op = Assign_Subtract; - - else - op = Subtract; - } - break; - case '*': - { - if ( currtok.Text[1] == '=' ) - op = Assign_Multiply; - - else - { - Token& finder = prevtok; - while ( finder.Type != TokType::Decl_Operator ) - { - if ( finder.Type == TokType::Identifier) - { - op = Indirection; - break; - } - } - - if ( op == Invalid) - op = Multiply; - } - } - break; - case '/': - { - if ( currtok.Text[1] == '=' ) - op = Assign_Divide; - - else - op = Divide; - } - break; - case '%': - { - if ( currtok.Text[1] == '=' ) - op = Assign_Modulo; - - else - op = Modulo; - } - break; - case '&': - { - if ( currtok.Text[1] == '=' ) - op = Assign_BAnd; - - else if ( currtok.Text[1] == '&' ) - op = LAnd; - - else - { - - - if ( op == Invalid ) - op = BAnd; - } - } - break; - case '|': - { - if ( currtok.Text[1] == '=' ) - op = Assign_BOr; - - else if ( currtok.Text[1] == '|' ) - op = LOr; - - else - op = BOr; - } - break; - case '^': - { - if ( currtok.Text[1] == '=' ) - op = Assign_BXOr; - - else - op = BXOr; - } - break; - case '~': - { - op = BNot; - } - break; - case '!': - { - if ( currtok.Text[1] == '=' ) - op = LNot; - - else - op = UnaryNot; - } - break; - case '=': - { - if ( currtok.Text[1] == '=' ) - op = LEqual; - - else - op = Assign; - } - break; - case '<': - { - if ( currtok.Text[1] == '=' ) - op = LEqual; - - else if ( currtok.Text[1] == '<' ) - { - if ( currtok.Text[2] == '=' ) - op = Assign_LShift; - - else - op = LShift; - } - else - op = Lesser; - } - break; - case '>': - { - if ( currtok.Text[1] == '=' ) - op = GreaterEqual; - - else if ( currtok.Text[1] == '>' ) - { - if ( currtok.Text[2] == '=' ) - op = Assign_RShift; - - else - op = RShift; - } - else - op = Greater; - } - break; - case '(': - { - if ( currtok.Text[1] == ')' ) - op = FunctionCall; - - else - op = Invalid; - } - break; - case '[': - { - if ( currtok.Text[1] == ']' ) - op = Subscript; - - else - op = Invalid; - } - break; default: { - break; + log_failure("gen::def_function: body must be either of Function_Body or Untyped type. %s", body.debug_str()); + return CodeInvalid; } } - if ( op == Invalid ) + result->Type = Function; + result->Body = body; + } + else + { + result->Type = Function_Fwd; + } + + if ( specifiers ) + result->Specs = specifiers; + + result->ReturnType = ret_type; + + if ( params ) + result->Params = params; + + return result; +} + +internal inline +CodeOperator parse_operator_after_ret_type( ModuleFlag mflags + , CodeAttributes attributes + , CodeSpecifier specifiers + , CodeType ret_type + , Parser::TokArray& toks + , char const* context ) +{ + using namespace Parser; + using namespace EOperator; + + // Parse Operator + eat( TokType::Decl_Operator ); + + if ( ! check( TokType::Operator ) ) + { + log_failure( "gen::%s: Expected operator after 'operator' keyword", context ); + return CodeInvalid; + } + + OperatorT op = Invalid; + switch ( currtok.Text[0] ) + { + case '+': { - log_failure( "gen::%s: Invalid operator '%s'", context, currtok.Text ); + if ( currtok.Text[1] == '=' ) + op = Assign_Add; + + else + op = Add; + } + break; + case '-': + { + if ( currtok.Text[1] == '=' ) + op = Assign_Subtract; + + else + op = Subtract; + } + break; + case '*': + { + if ( currtok.Text[1] == '=' ) + op = Assign_Multiply; + + else + { + Token& finder = prevtok; + while ( finder.Type != TokType::Decl_Operator ) + { + if ( finder.Type == TokType::Identifier) + { + op = Indirection; + break; + } + } + + if ( op == Invalid) + op = Multiply; + } + } + break; + case '/': + { + if ( currtok.Text[1] == '=' ) + op = Assign_Divide; + + else + op = Divide; + } + break; + case '%': + { + if ( currtok.Text[1] == '=' ) + op = Assign_Modulo; + + else + op = Modulo; + } + break; + case '&': + { + if ( currtok.Text[1] == '=' ) + op = Assign_BAnd; + + else if ( currtok.Text[1] == '&' ) + op = LAnd; + + else + { + + + if ( op == Invalid ) + op = BAnd; + } + } + break; + case '|': + { + if ( currtok.Text[1] == '=' ) + op = Assign_BOr; + + else if ( currtok.Text[1] == '|' ) + op = LOr; + + else + op = BOr; + } + break; + case '^': + { + if ( currtok.Text[1] == '=' ) + op = Assign_BXOr; + + else + op = BXOr; + } + break; + case '~': + { + op = BNot; + } + break; + case '!': + { + if ( currtok.Text[1] == '=' ) + op = LNot; + + else + op = UnaryNot; + } + break; + case '=': + { + if ( currtok.Text[1] == '=' ) + op = LEqual; + + else + op = Assign; + } + break; + case '<': + { + if ( currtok.Text[1] == '=' ) + op = LEqual; + + else if ( currtok.Text[1] == '<' ) + { + if ( currtok.Text[2] == '=' ) + op = Assign_LShift; + + else + op = LShift; + } + else + op = Lesser; + } + break; + case '>': + { + if ( currtok.Text[1] == '=' ) + op = GreaterEqual; + + else if ( currtok.Text[1] == '>' ) + { + if ( currtok.Text[2] == '=' ) + op = Assign_RShift; + + else + op = RShift; + } + else + op = Greater; + } + break; + case '(': + { + if ( currtok.Text[1] == ')' ) + op = FunctionCall; + + else + op = Invalid; + } + break; + case '[': + { + if ( currtok.Text[1] == ']' ) + op = Subscript; + + else + op = Invalid; + } + break; + default: + { + break; + } + } + + if ( op == Invalid ) + { + log_failure( "gen::%s: Invalid operator '%s'", context, currtok.Text ); + return CodeInvalid; + } + + eat( TokType::Operator ); + + // Parse Params + CodeParam params = parse_params( toks, stringize(parse_operator) ); + + // Parse Body + CodeBody body = { nullptr }; + if ( check( TokType::BraceCurly_Open ) ) + { + body = parse_function_body( toks, stringize(parse_function) ); + if ( body == Code::Invalid ) + return CodeInvalid; + } + else + { + eat( TokType::Statement_End ); + } + + // OpValidateResult check_result = operator__validate( op, params, ret_type, specifiers ); + CodeOperator result = def_operator( op, params, ret_type, body, specifiers, attributes, mflags ); + return result; +} + +// Variable parsing is handled in multiple places because its initial signature is shared with function parsing +internal inline +CodeVar parse_variable_after_name( + ModuleFlag mflags + , CodeAttributes attributes + , CodeSpecifier specifiers + , CodeType type + , StrC name + , Parser::TokArray& toks + , char const* context ) +{ + using namespace Parser; + + Code array_expr = parse_array_decl( toks, stringize(parse_variable) ); + + Code expr = { nullptr }; + + if ( currtok.IsAssign ) + { + eat( TokType::Operator ); + + Token expr_tok = currtok; + + if ( currtok.Type == TokType::Statement_End ) + { + log_failure( "gen::parse_variable: expected expression after assignment operator" ); return CodeInvalid; } + while ( left && currtok.Type != TokType::Statement_End ) + { + eat( currtok.Type ); + } + + expr_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)expr_tok.Text; + expr = untyped_str( expr_tok ); + } + + eat( TokType::Statement_End ); + + using namespace ECode; + + CodeVar + result = (CodeVar) make_code(); + result->Type = Variable; + result->Name = get_cached_string( name ); + result->ModuleFlags = mflags; + + result->ValueType = type; + + if (array_expr ) + type->ArrExpr = array_expr; + + if ( attributes ) + result->Attributes = attributes; + + if ( specifiers ) + result->Specs = specifiers; + + if ( expr ) + result->Value = expr; + + return result; +} + +internal inline +Code parse_variable_assignment( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + + Code expr = Code::Invalid; + + if ( currtok.IsAssign ) + { eat( TokType::Operator ); - // Parse Params - CodeParam params = parse_params( toks, stringize(parse_operator) ); + Token expr_tok = currtok; - // Parse Body - CodeBody body = { nullptr }; - if ( check( TokType::BraceCurly_Open ) ) + if ( currtok.Type == TokType::Statement_End ) { - body = parse_function_body( toks, stringize(parse_function) ); - if ( body == Code::Invalid ) - return CodeInvalid; + log_failure( "gen::parse_variable: expected expression after assignment operator" ); + return Code::Invalid; + } + + while ( left && currtok.Type != TokType::Statement_End ) + { + expr_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)expr_tok.Text; + eat( currtok.Type ); + } + + expr = untyped_str( expr_tok ); + } + + return expr; +} + +internal inline +Code parse_operator_function_or_variable( bool expects_function, CodeAttributes attributes, CodeSpecifier specifiers, Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + + Code result = Code::Invalid; + + CodeType type = parse_type( toks, stringize(parse_variable) ); + + if ( type == Code::Invalid ) + return CodeInvalid; + + if ( check( TokType::Operator) ) + { + // Dealing with an operator overload + result = parse_operator_after_ret_type( ModuleFlag::None, attributes, specifiers, type, toks, stringize(parse_template) ); + } + else + { + StrC name = currtok; + eat( TokType::Identifier ); + + if ( check( TokType::Capture_Start) ) + { + // Dealing with a function + + result = parse_function_after_name( ModuleFlag::None, attributes, specifiers, type, name, toks, stringize(parse_template) ); } else { - eat( TokType::Statement_End ); - } - - // OpValidateResult check_result = operator__validate( op, params, ret_type, specifiers ); - CodeOperator result = def_operator( op, params, ret_type, body, specifiers, attributes, mflags ); - return result; - } - - // Variable parsing is handled in multiple places because its initial signature is shared with function parsing - internal inline - CodeVar parse_variable_after_name( - ModuleFlag mflags - , CodeAttributes attributes - , CodeSpecifier specifiers - , CodeType type - , StrC name - , Parser::TokArray& toks - , char const* context ) - { - using namespace Parser; - - Code array_expr = parse_array_decl( toks, stringize(parse_variable) ); - - Code expr = { nullptr }; - - if ( currtok.IsAssign ) - { - eat( TokType::Operator ); - - Token expr_tok = currtok; - - if ( currtok.Type == TokType::Statement_End ) + if ( expects_function ) { - log_failure( "gen::parse_variable: expected expression after assignment operator" ); - return CodeInvalid; - } - - while ( left && currtok.Type != TokType::Statement_End ) - { - eat( currtok.Type ); - } - - expr_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)expr_tok.Text; - expr = untyped_str( expr_tok ); - } - - eat( TokType::Statement_End ); - - using namespace ECode; - - CodeVar - result = (CodeVar) make_code(); - result->Type = Variable; - result->Name = get_cached_string( name ); - result->ModuleFlags = mflags; - - result->ValueType = type; - - if (array_expr ) - type->ArrExpr = array_expr; - - if ( attributes ) - result->Attributes = attributes; - - if ( specifiers ) - result->Specs = specifiers; - - if ( expr ) - result->Value = expr; - - return result; - } - - internal inline - Code parse_variable_assignment( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - - Code expr = Code::Invalid; - - if ( currtok.IsAssign ) - { - eat( TokType::Operator ); - - Token expr_tok = currtok; - - if ( currtok.Type == TokType::Statement_End ) - { - log_failure( "gen::parse_variable: expected expression after assignment operator" ); + log_failure( "gen::parse_template: expected function declaration (consteval was used)" ); return Code::Invalid; } - while ( left && currtok.Type != TokType::Statement_End ) - { - expr_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)expr_tok.Text; - eat( currtok.Type ); - } - - expr = untyped_str( expr_tok ); + // Dealing with a variable + result = parse_variable_after_name( ModuleFlag::None, attributes, specifiers, type, name, toks, stringize(parse_template) ); } - - return expr; } - internal inline - Code parse_operator_function_or_variable( bool expects_function, CodeAttributes attributes, CodeSpecifier specifiers, Parser::TokArray& toks, char const* context ) + return result; +} + +internal +CodeBody parse_class_struct_body( Parser::TokType which, Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + using namespace ECode; + + eat( TokType::BraceCurly_Open ); + + CodeBody + result = (CodeBody) make_code(); + + if ( which == TokType::Decl_Class ) + result->Type = Class_Body; + + else + result->Type = Struct_Body; + + while ( left && currtok.Type != TokType::BraceCurly_Close ) { - using namespace Parser; + Code member = Code::Invalid; + CodeAttributes attributes = { nullptr }; + CodeSpecifier specifiers = { nullptr }; - Code result = Code::Invalid; + bool expects_function = false; - CodeType type = parse_type( toks, stringize(parse_variable) ); + switch ( currtok.Type ) + { + case TokType::Comment: + member = def_comment( currtok ); + eat( TokType::Comment ); + break; + case TokType::Access_Public: + member = access_public; + eat( TokType::Access_Public ); + eat( TokType::Assign_Classifer ); + break; + + case TokType::Access_Protected: + member = access_protected; + eat( TokType::Access_Protected ); + eat( TokType::Assign_Classifer ); + break; + + case TokType::Access_Private: + member = access_private; + eat( TokType::Access_Private ); + eat( TokType::Assign_Classifer ); + break; + + case TokType::Decl_Class: + member = parse_class( toks, context ); + break; + + case TokType::Decl_Enum: + member = parse_enum( toks, context ); + break; + + case TokType::Decl_Friend: + member = parse_friend( toks, context ); + break; + + case TokType::Decl_Operator: + member = parse_operator_cast( toks, context ); + break; + + case TokType::Decl_Struct: + member = parse_struct( toks, context ); + break; + + case TokType::Decl_Template: + member = parse_template( toks, context ); + break; + + case TokType::Decl_Typedef: + member = parse_typedef( toks, context ); + break; + + case TokType::Decl_Union: + member = parse_variable( toks, context ); + break; + + case TokType::Decl_Using: + member = parse_using( toks, context ); + break; + + case TokType::BraceSquare_Open: + case TokType::Attr_Keyword: + { + // Standard attribute + if ( currtok.Type == TokType::BraceSquare_Open ) + { + eat( TokType::BraceSquare_Open ); + + if ( currtok.Type != TokType::BraceSquare_Open ) + { + log_failure( "%s: Error, expected attribute name", context ); + return result; + } + + while ( left && currtok.Type != TokType::BraceSquare_Close ) + { + // TODO : Parse attributes + } + + eat( TokType::BraceSquare_Close ); + eat( TokType::BraceSquare_Close ); + } + + // Platform Specific attribute + eat( TokType::Attr_Keyword ); + eat( TokType::Capture_Start ); + + // TODO : Parse attributes + + eat( TokType::Capture_End ); + } + //! Fallthrough intended + case TokType::Spec_Consteval: + case TokType::Spec_Constexpr: + case TokType::Spec_Constinit: + case TokType::Spec_Inline: + case TokType::Spec_Mutable: + case TokType::Spec_Static: + case TokType::Spec_Volatile: + { + SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; + s32 num_specifiers = 0; + + while ( left && tok_is_specifier( currtok ) ) + { + SpecifierT spec = ESpecifier::to_type( currtok ); + + switch ( spec ) + { + case ESpecifier::Constexpr: + case ESpecifier::Constinit: + case ESpecifier::Inline: + case ESpecifier::Mutable: + case ESpecifier::Static: + case ESpecifier::Volatile: + break; + + case ESpecifier::Consteval: + expects_function = true; + break; + + default: + log_failure( "gen::parse_class_struct_body: invalid specifier " "%s" " for variable", ESpecifier::to_str(spec) ); + return CodeInvalid; + } + + specs_found[num_specifiers] = spec; + num_specifiers++; + eat( currtok.Type ); + } + + if ( num_specifiers ) + { + specifiers = def_specifiers( num_specifiers, specs_found ); + } + } + //! Fallthrough intentional + case TokType::Identifier: + case TokType::Spec_Const: + case TokType::Type_Unsigned: + case TokType::Type_Signed: + case TokType::Type_Short: + case TokType::Type_Long: + { + member = parse_operator_function_or_variable( expects_function, attributes, specifiers, toks, context ); + } + break; + + default: + Token untyped_tok = currtok; + + while ( left && currtok.Type != TokType::BraceCurly_Close ) + { + untyped_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)untyped_tok.Text; + eat( currtok.Type ); + } + + member = untyped_str( untyped_tok ); + break; + } + + if ( member == Code::Invalid ) + { + log_failure( "gen::parse_variable: failed to parse member" ); + return CodeInvalid; + } + + result.append( member ); + } + + eat( TokType::BraceCurly_Close ); + return result; +} + +internal +Code parse_class_struct( Parser::TokType which, Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + + if ( which != TokType::Decl_Class && which != TokType::Decl_Struct ) + { + log_failure( "%s: Error, expected class or struct, not %s", context, str_tok_type( which ) ); + return CodeInvalid; + } + + Token name { nullptr, 0, TokType::Invalid }; + + CodeType parent = { nullptr }; + CodeBody body = { nullptr }; + CodeAttributes attributes = { nullptr }; + ModuleFlag mflags = ModuleFlag::None; + + CodeClass result = CodeInvalid; + + // TODO : Parse module specifiers + + eat( which ); + + // TODO : Parse attributes + + if ( check( TokType::Identifier ) ) + name = parse_identifier( toks, context ); + + AccessSpec access = AccessSpec::Default; + Token parent_tok = { nullptr, 0, TokType::Invalid }; + + if ( check( TokType::Assign_Classifer ) ) + { + eat( TokType::Assign_Classifer ); + + if ( tok_is_access_specifier( currtok ) ) + { + access = tok_to_access_specifier( currtok ); + } + + parent_tok = parse_identifier( toks, context ); + } + + if ( check( TokType::BraceCurly_Open ) ) + { + body = parse_class_struct_body( which, toks, context ); + } + + eat( TokType::Statement_End ); + + if ( parent_tok ) + parent = def_type( parent_tok ); + + if ( which == TokType::Decl_Class ) + result = def_class( name, body, parent, access + // TODO : Set these up later + , NoCode // Attributes + , ModuleFlag::None + ); + + else + result = def_struct( name, body, (CodeType)parent, access + // TODO : Set these up later + , NoCode // Attributes + , ModuleFlag::None + ); + + return result; +} + +internal +Code parse_function_body( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + using namespace ECode; + + eat( TokType::BraceCurly_Open ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = Function_Body; + + Token start = currtok; + + s32 level = 0; + while ( left && ( currtok.Type != TokType::BraceCurly_Close || level > 0 ) ) + { + if ( currtok.Type == TokType::BraceCurly_Open ) + level++; + + else if ( currtok.Type == TokType::BraceCurly_Close && level > 0 ) + level--; + + eat( currtok.Type ); + } + + Token previous = prevtok; + + s32 len = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)start.Text; + + if ( len > 0 ) + { + result.append( def_execution( { len, start.Text } ) ); + } + + eat( TokType::BraceCurly_Close ); + return result; +} + +internal +CodeBody parse_global_nspace( CodeT which, Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + using namespace ECode; + + if ( which != Namespace_Body && which != Global_Body && which != Export_Body && which != Extern_Linkage_Body ) + return CodeInvalid; + + if ( which != Global_Body ) + eat( TokType::BraceCurly_Open ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = which; + + while ( left && currtok.Type != TokType::BraceCurly_Close ) + { + Code member = Code::Invalid; + CodeAttributes attributes = { nullptr }; + CodeSpecifier specifiers = { nullptr }; + + bool expects_function = false; + + switch ( currtok.Type ) + { + case TokType::Comment: + member = def_comment( currtok ); + eat( TokType::Comment ); + break; + + case TokType::Decl_Enum: + member = parse_enum( toks, context); + break; + + case TokType::Decl_Class: + member = parse_class( toks, context ); + break; + + case TokType::Decl_Extern_Linkage: + if ( which == Extern_Linkage_Body ) + log_failure( "gen::parse_global_nspace: nested extern linkage" ); + + member = parse_extern_link_body( toks, context ); + break; + + case TokType::Decl_Namespace: + member = parse_namespace( toks, context ); + break; + + case TokType::Decl_Struct: + member = parse_struct( toks, context ); + break; + + case TokType::Decl_Template: + member = parse_template( toks, context ); + break; + + case TokType::Decl_Typedef: + member = parse_typedef( toks, context ); + break; + + case TokType::Decl_Union: + member = parse_union( toks, context ); + break; + + case TokType::Decl_Using: + member = parse_using( toks, context ); + break; + + case TokType::Module_Export: + if ( which == Export_Body ) + log_failure( "gen::parse_global_nspace: nested export declaration" ); + + member = parse_export_body( toks, context ); + break; + + case TokType::Module_Import: + { + not_implemented( context ); + } + //! Fallthrough intentional + case TokType::BraceSquare_Open: + case TokType::Attr_Keyword: + { + not_implemented( context ); + + // Standard attribute + if ( currtok.Type == TokType::BraceSquare_Open ) + { + eat( TokType::BraceSquare_Open ); + + if ( currtok.Type != TokType::BraceSquare_Open ) + { + log_failure( "%s: Error, expected attribute name", context ); + return result; + } + + while ( left && currtok.Type != TokType::BraceSquare_Close ) + { + // TODO : Parse attributes + } + + eat( TokType::BraceSquare_Close ); + eat( TokType::BraceSquare_Close ); + } + + // Platform Specific attribute + eat( TokType::Attr_Keyword ); + eat( TokType::Capture_Start ); + + // TODO : Parse attributes + + eat( TokType::Capture_End ); + } + //! Fallthrough intentional + case TokType::Spec_Consteval: + case TokType::Spec_Constexpr: + case TokType::Spec_Constinit: + case TokType::Spec_Extern: + case TokType::Spec_Global: + case TokType::Spec_Inline: + case TokType::Spec_Internal_Linkage: + case TokType::Spec_Static: + { + SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; + s32 num_specifiers = 0; + + while ( left && tok_is_specifier( currtok ) ) + { + SpecifierT spec = ESpecifier::to_type( currtok ); + + switch ( spec ) + { + case ESpecifier::Constexpr: + case ESpecifier::Constinit: + case ESpecifier::Inline: + case ESpecifier::Mutable: + case ESpecifier::Static: + case ESpecifier::Volatile: + break; + + case ESpecifier::Consteval: + expects_function = true; + break; + + default: + log_failure( "gen::parse_global_nspace: invalid specifier " "%s" " for variable", ESpecifier::to_str(spec) ); + return CodeInvalid; + } + + specs_found[num_specifiers] = spec; + num_specifiers++; + eat( currtok.Type ); + } + + if ( num_specifiers ) + { + specifiers = def_specifiers( num_specifiers, specs_found ); + } + } + //! Fallthrough intentional + case TokType::Identifier: + case TokType::Spec_Const: + case TokType::Type_Long: + case TokType::Type_Short: + case TokType::Type_Signed: + case TokType::Type_Unsigned: + { + member = parse_operator_function_or_variable( expects_function, attributes, specifiers, toks, context ); + } + } + + if ( member == Code::Invalid ) + { + log_failure( "gen::%s: failed to parse extern linkage member", context ); + return CodeInvalid; + } + + result.append( member ); + } + + if ( which != Global_Body ) + eat( TokType::BraceCurly_Close ); + + return result; +} + +internal +CodeClass parse_class( Parser::TokArray& toks, char const* context ) +{ + return (CodeClass) parse_class_struct( Parser::TokType::Decl_Class, toks, context ); +} + +CodeClass parse_class( StrC def ) +{ + check_parse_args( parse_class, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return (CodeClass) parse_class_struct( TokType::Decl_Class, toks, stringize(parse_class) ); +} + +internal +CodeEnum parse_enum( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + using namespace ECode; + + SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; + s32 num_specifiers = 0; + + Token name = { nullptr, 0, TokType::Invalid }; + Code array_expr = { nullptr }; + CodeType type = { nullptr }; + Token body = { nullptr, 0, TokType::Invalid }; + + char entries_code[ kilobytes(128) ] { 0 }; + s32 entries_length = 0; + + bool is_enum_class = false; + + eat( TokType::Decl_Enum ); + + if ( currtok.Type == TokType::Decl_Class ) + { + eat( TokType::Decl_Class); + is_enum_class = true; + } + + // TODO : Parse attributes + + if ( currtok.Type != TokType::Identifier ) + { + log_failure( "gen::parse_enum: expected identifier for enum name" ); + return CodeInvalid; + } + + name = currtok; + eat( TokType::Identifier ); + + if ( currtok.Type == TokType::Assign_Classifer ) + { + eat( TokType::Assign_Classifer ); + + type = parse_type( toks, stringize(parse_enum) ); if ( type == Code::Invalid ) return CodeInvalid; - - if ( check( TokType::Operator) ) - { - // Dealing with an operator overload - result = parse_operator_after_ret_type( ModuleFlag::None, attributes, specifiers, type, toks, stringize(parse_template) ); - } - else - { - StrC name = currtok; - eat( TokType::Identifier ); - - if ( check( TokType::Capture_Start) ) - { - // Dealing with a function - - result = parse_function_after_name( ModuleFlag::None, attributes, specifiers, type, name, toks, stringize(parse_template) ); - } - else - { - if ( expects_function ) - { - log_failure( "gen::parse_template: expected function declaration (consteval was used)" ); - return Code::Invalid; - } - - // Dealing with a variable - result = parse_variable_after_name( ModuleFlag::None, attributes, specifiers, type, name, toks, stringize(parse_template) ); - } - } - - return result; } - internal - CodeBody parse_class_struct_body( Parser::TokType which, Parser::TokArray& toks, char const* context ) + if ( currtok.Type == TokType::BraceCurly_Open ) { - using namespace Parser; - using namespace ECode; - eat( TokType::BraceCurly_Open ); - CodeBody - result = (CodeBody) make_code(); + body = currtok; - if ( which == TokType::Decl_Class ) - result->Type = Class_Body; - - else - result->Type = Struct_Body; - - while ( left && currtok.Type != TokType::BraceCurly_Close ) + while ( currtok.Type != TokType::BraceCurly_Close ) { - Code member = Code::Invalid; - CodeAttributes attributes = { nullptr }; - CodeSpecifier specifiers = { nullptr }; + eat( TokType::Identifier); - bool expects_function = false; - - switch ( currtok.Type ) + if ( currtok.Type == TokType::Operator && currtok.Text[0] == '=' ) { - case TokType::Comment: - member = def_comment( currtok ); - eat( TokType::Comment ); - break; + eat( TokType::Operator ); - case TokType::Access_Public: - member = access_public; - eat( TokType::Access_Public ); - eat( TokType::Assign_Classifer ); - break; - - case TokType::Access_Protected: - member = access_protected; - eat( TokType::Access_Protected ); - eat( TokType::Assign_Classifer ); - break; - - case TokType::Access_Private: - member = access_private; - eat( TokType::Access_Private ); - eat( TokType::Assign_Classifer ); - break; - - case TokType::Decl_Class: - member = parse_class( toks, context ); - break; - - case TokType::Decl_Enum: - member = parse_enum( toks, context ); - break; - - case TokType::Decl_Friend: - member = parse_friend( toks, context ); - break; - - case TokType::Decl_Operator: - member = parse_operator_cast( toks, context ); - break; - - case TokType::Decl_Struct: - member = parse_struct( toks, context ); - break; - - case TokType::Decl_Template: - member = parse_template( toks, context ); - break; - - case TokType::Decl_Typedef: - member = parse_typedef( toks, context ); - break; - - case TokType::Decl_Union: - member = parse_variable( toks, context ); - break; - - case TokType::Decl_Using: - member = parse_using( toks, context ); - break; - - case TokType::BraceSquare_Open: - case TokType::Attr_Keyword: + while ( currtok.Type != TokType::Comma && currtok.Type != TokType::BraceCurly_Close ) { - // Standard attribute - if ( currtok.Type == TokType::BraceSquare_Open ) - { - eat( TokType::BraceSquare_Open ); - - if ( currtok.Type != TokType::BraceSquare_Open ) - { - log_failure( "%s: Error, expected attribute name", context ); - return result; - } - - while ( left && currtok.Type != TokType::BraceSquare_Close ) - { - // TODO : Parse attributes - } - - eat( TokType::BraceSquare_Close ); - eat( TokType::BraceSquare_Close ); - } - - // Platform Specific attribute - eat( TokType::Attr_Keyword ); - eat( TokType::Capture_Start ); - - // TODO : Parse attributes - - eat( TokType::Capture_End ); + eat( currtok.Type ); } - //! Fallthrough intended - case TokType::Spec_Consteval: - case TokType::Spec_Constexpr: - case TokType::Spec_Constinit: - case TokType::Spec_Inline: - case TokType::Spec_Mutable: - case TokType::Spec_Static: - case TokType::Spec_Volatile: - { - SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; - s32 num_specifiers = 0; - - while ( left && tok_is_specifier( currtok ) ) - { - SpecifierT spec = ESpecifier::to_type( currtok ); - - switch ( spec ) - { - case ESpecifier::Constexpr: - case ESpecifier::Constinit: - case ESpecifier::Inline: - case ESpecifier::Mutable: - case ESpecifier::Static: - case ESpecifier::Volatile: - break; - - case ESpecifier::Consteval: - expects_function = true; - break; - - default: - log_failure( "gen::parse_class_struct_body: invalid specifier " "%s" " for variable", ESpecifier::to_str(spec) ); - return CodeInvalid; - } - - specs_found[num_specifiers] = spec; - num_specifiers++; - eat( currtok.Type ); - } - - if ( num_specifiers ) - { - specifiers = def_specifiers( num_specifiers, specs_found ); - } - } - //! Fallthrough intentional - case TokType::Identifier: - case TokType::Spec_Const: - case TokType::Type_Unsigned: - case TokType::Type_Signed: - case TokType::Type_Short: - case TokType::Type_Long: - { - member = parse_operator_function_or_variable( expects_function, attributes, specifiers, toks, context ); - } - break; - - default: - Token untyped_tok = currtok; - - while ( left && currtok.Type != TokType::BraceCurly_Close ) - { - untyped_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)untyped_tok.Text; - eat( currtok.Type ); - } - - member = untyped_str( untyped_tok ); - break; } - if ( member == Code::Invalid ) + if ( currtok.Type == TokType::Comma ) { - log_failure( "gen::parse_variable: failed to parse member" ); - return CodeInvalid; + eat( TokType::Comma ); } - - result.append( member ); } + body.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)body.Text; + eat( TokType::BraceCurly_Close ); + } + + eat( TokType::Statement_End ); + + using namespace ECode; + + CodeEnum + result = (CodeEnum) make_code(); + + if ( body.Length ) + { + // mem_copy( entries_code, body.Text, body.Length ); + + Code untyped_body = untyped_str( body ); + + result->Type = is_enum_class ? Enum_Class : Enum; + result->Body = untyped_body; + } + else + { + result->Type = is_enum_class ? Enum_Class_Fwd : Enum_Fwd; + } + + result->Name = get_cached_string( name ); + + if ( type ) + result->UnderlyingType = type; + + return result; +} + +CodeEnum parse_enum( StrC def ) +{ + check_parse_args( parse_enum, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return parse_enum( toks, stringize(parse_enum) ); +} + +internal inline +CodeBody parse_export_body( Parser::TokArray& toks, char const* context ) +{ + return parse_global_nspace( ECode::Export_Body, toks, context ); +} + +CodeBody parse_export_body( StrC def ) +{ + check_parse_args( parse_export_body, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return parse_export_body( toks, stringize(parse_export_body) ); +} + +internal inline +CodeBody parse_extern_link_body( Parser::TokArray& toks, char const* context ) +{ + return parse_global_nspace( ECode::Extern_Linkage_Body, toks, context ); +} + +internal +CodeExtern parse_extern_link( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + + eat( TokType::Decl_Extern_Linkage ); + + Token name = currtok; + eat( TokType::String ); + + name.Text += 1; + name.Length -= 1; + + CodeExtern + result = (CodeExtern) make_code(); + result->Type = ECode::Extern_Linkage; + result->Name = get_cached_string( name ); + + Code entry = parse_extern_link_body( toks, context ); + if ( entry == Code::Invalid ) + { + log_failure( "gen::parse_extern_link: failed to parse body" ); return result; } - internal - Code parse_class_struct( Parser::TokType which, Parser::TokArray& toks, char const* context ) + result->Body = entry; + + return result; +} + +CodeExtern parse_extern_link( StrC def ) +{ + check_parse_args( parse_extern_link, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return parse_extern_link( toks, stringize(parse_extern_link) ); +} + +internal +CodeFriend parse_friend( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + using namespace ECode; + + eat( TokType::Decl_Friend ); + + CodeFn function = { nullptr }; + + // Type declaration or return type + CodeType type = parse_type( toks, stringize(parse_friend) ); + if ( type == Code::Invalid ) + return CodeInvalid; + + // Funciton declaration + if ( currtok.Type == TokType::Identifier ) { - using namespace Parser; + // Name + Token name = parse_identifier( toks, stringize(parse_friend) ); - if ( which != TokType::Decl_Class && which != TokType::Decl_Struct ) - { - log_failure( "%s: Error, expected class or struct, not %s", context, str_tok_type( which ) ); - return CodeInvalid; - } + // Parameter list + CodeParam params = parse_params( toks, stringize(parse_friend) ); - Token name { nullptr, 0, TokType::Invalid }; + function = make_code(); + function->Type = Function_Fwd; + function->Name = get_cached_string( name ); + function->ReturnType = type; - CodeType parent = { nullptr }; - CodeBody body = { nullptr }; - CodeAttributes attributes = { nullptr }; - ModuleFlag mflags = ModuleFlag::None; - - CodeClass result = CodeInvalid; - - // TODO : Parse module specifiers - - eat( which ); - - // TODO : Parse attributes - - if ( check( TokType::Identifier ) ) - name = parse_identifier( toks, context ); - - AccessSpec access = AccessSpec::Default; - Token parent_tok = { nullptr, 0, TokType::Invalid }; - - if ( check( TokType::Assign_Classifer ) ) - { - eat( TokType::Assign_Classifer ); - - if ( tok_is_access_specifier( currtok ) ) - { - access = tok_to_access_specifier( currtok ); - } - - parent_tok = parse_identifier( toks, context ); - } - - if ( check( TokType::BraceCurly_Open ) ) - { - body = parse_class_struct_body( which, toks, context ); - } - - eat( TokType::Statement_End ); - - if ( parent_tok ) - parent = def_type( parent_tok ); - - if ( which == TokType::Decl_Class ) - result = def_class( name, body, parent, access - // TODO : Set these up later - , NoCode // Attributes - , ModuleFlag::None - ); - - else - result = def_struct( name, body, (CodeType)parent, access - // TODO : Set these up later - , NoCode // Attributes - , ModuleFlag::None - ); - - return result; + if ( params ) + function->Params = params; } - internal - Code parse_function_body( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - using namespace ECode; + eat( TokType::Statement_End ); + CodeFriend + result = (CodeFriend) make_code(); + result->Type = Friend; + + if ( function ) + result->Declaration = function; + + else + result->Declaration = type; + + return result; +} + +CodeFriend parse_friend( StrC def ) +{ + check_parse_args( parse_friend, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return parse_friend( toks, stringize(parse_friend) ); +} + +internal +CodeFn parse_functon( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + + SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; + s32 num_specifiers = 0; + + CodeAttributes attributes = { nullptr }; + CodeSpecifier specifiers = { nullptr }; + + // TODO : Parse module specifiers + + // TODO : Parse attributes + + while ( left && tok_is_specifier( currtok ) ) + { + SpecifierT spec = ESpecifier::to_type( currtok ); + + switch ( spec ) + { + case ESpecifier::Const: + case ESpecifier::Consteval: + case ESpecifier::Constexpr: + case ESpecifier::External_Linkage: + case ESpecifier::Inline: + case ESpecifier::Static: + break; + + default: + log_failure( "gen::parse_functon: invalid specifier " "%s" " for functon", ESpecifier::to_str(spec) ); + return CodeInvalid; + } + + specs_found[num_specifiers] = spec; + num_specifiers++; + eat( currtok.Type ); + } + + if ( num_specifiers ) + { + specifiers = def_specifiers( num_specifiers, specs_found ); + } + + CodeType ret_type = parse_type( toks, stringize(parse_function) ); + if ( ret_type == Code::Invalid ) + return CodeInvalid; + + Token name = parse_identifier( toks, stringize(parse_function) ); + if ( ! name ) + return CodeInvalid; + + CodeFn result = parse_function_after_name( ModuleFlag::None, attributes, specifiers, ret_type, name, toks, context ); + + return result; +} + +CodeFn parse_function( StrC def ) +{ + using namespace Parser; + + check_parse_args( parse_function, def ); + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return (CodeFn) parse_functon( toks, stringize(parse_function) ); +} + +CodeBody parse_global_body( StrC def ) +{ + check_parse_args( parse_global_body, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return parse_global_nspace( ECode::Global_Body, toks, stringize(parse_global_body) ); +} + +internal +CodeNamespace parse_namespace( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + eat( TokType::Decl_Namespace ); + + Token name = parse_identifier( toks, stringize(parse_namespace) ); + + CodeBody body = parse_global_nspace( ECode::Namespace_Body, toks, stringize(parse_namespace) ); + if ( body == Code::Invalid ) + return CodeInvalid; + + CodeNamespace + result = (CodeNamespace) make_code(); + result->Type = ECode::Namespace; + result->Name = get_cached_string( name ); + + result->Body = body; + + return result; +} + +CodeNamespace parse_namespace( StrC def ) +{ + check_parse_args( parse_namespace, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return parse_namespace( toks, stringize(parse_namespace) ); +} + +internal +CodeOperator parse_operator( Parser::TokArray& toks, char const* context ) +{ + // TODO : Parse Module specifier + + // TODO : Parse Attributes + CodeAttributes attributes = { nullptr }; + + CodeSpecifier specifiers = { nullptr }; + + SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; + s32 num_specifiers = 0; + + while ( left && tok_is_specifier( currtok ) ) + { + SpecifierT spec = ESpecifier::to_type( currtok ); + + switch ( spec ) + { + case ESpecifier::Const: + case ESpecifier::Constexpr: + case ESpecifier::Inline: + case ESpecifier::Static: + break; + + default: + log_failure( "gen::parse_operator: invalid specifier " "%s" " for operator", ESpecifier::to_str(spec) ); + return CodeInvalid; + } + + specs_found[num_specifiers] = spec; + num_specifiers++; + eat( currtok.Type ); + } + + if ( num_specifiers ) + { + specifiers = def_specifiers( num_specifiers, specs_found ); + } + + // Parse Return Type + CodeType ret_type = parse_type( toks, stringize(parse_operator) ); + + CodeOperator result = parse_operator_after_ret_type( ModuleFlag::None, attributes, specifiers, ret_type, toks, context ); + return result; +} + +CodeOperator parse_operator( StrC def ) +{ + check_parse_args( parse_operator, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return (CodeOperator) parse_operator( toks, stringize(parse_operator) ); +} + +CodeOpCast parse_operator_cast( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + + eat( TokType::Decl_Operator ); + + Code type = parse_type( toks, stringize(parse_operator_cast) ); + + eat( TokType::Capture_Start ); + eat( TokType::Capture_End ); + + Code body = { nullptr }; + + if ( check( TokType::BraceCurly_Open) ) + { eat( TokType::BraceCurly_Open ); - CodeBody - result = (CodeBody) make_code(); - result->Type = Function_Body; - - Token start = currtok; + Token body_str = currtok; s32 level = 0; while ( left && ( currtok.Type != TokType::BraceCurly_Close || level > 0 ) ) @@ -5020,1254 +5690,111 @@ namespace gen eat( currtok.Type ); } - Token previous = prevtok; + body_str.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)body_str.Text; - s32 len = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)start.Text; - - if ( len > 0 ) - { - result.append( def_execution( { len, start.Text } ) ); - } + body = untyped_str( body_str ); eat( TokType::BraceCurly_Close ); - return result; } - internal - CodeBody parse_global_nspace( CodeT which, Parser::TokArray& toks, char const* context ) + CodeOpCast result = (CodeOpCast) make_code(); + + if (body) { - using namespace Parser; - using namespace ECode; - - if ( which != Namespace_Body && which != Global_Body && which != Export_Body && which != Extern_Linkage_Body ) - return CodeInvalid; - - if ( which != Global_Body ) - eat( TokType::BraceCurly_Open ); - - CodeBody - result = (CodeBody) make_code(); - result->Type = which; - - while ( left && currtok.Type != TokType::BraceCurly_Close ) - { - Code member = Code::Invalid; - CodeAttributes attributes = { nullptr }; - CodeSpecifier specifiers = { nullptr }; - - bool expects_function = false; - - switch ( currtok.Type ) - { - case TokType::Comment: - member = def_comment( currtok ); - eat( TokType::Comment ); - break; - - case TokType::Decl_Enum: - member = parse_enum( toks, context); - break; - - case TokType::Decl_Class: - member = parse_class( toks, context ); - break; - - case TokType::Decl_Extern_Linkage: - if ( which == Extern_Linkage_Body ) - log_failure( "gen::parse_global_nspace: nested extern linkage" ); - - member = parse_extern_link_body( toks, context ); - break; - - case TokType::Decl_Namespace: - member = parse_namespace( toks, context ); - break; - - case TokType::Decl_Struct: - member = parse_struct( toks, context ); - break; - - case TokType::Decl_Template: - member = parse_template( toks, context ); - break; - - case TokType::Decl_Typedef: - member = parse_typedef( toks, context ); - break; - - case TokType::Decl_Union: - member = parse_union( toks, context ); - break; - - case TokType::Decl_Using: - member = parse_using( toks, context ); - break; - - case TokType::Module_Export: - if ( which == Export_Body ) - log_failure( "gen::parse_global_nspace: nested export declaration" ); - - member = parse_export_body( toks, context ); - break; - - case TokType::Module_Import: - { - not_implemented(); - } - //! Fallthrough intentional - case TokType::BraceSquare_Open: - case TokType::Attr_Keyword: - { - not_implemented(); - - // Standard attribute - if ( currtok.Type == TokType::BraceSquare_Open ) - { - eat( TokType::BraceSquare_Open ); - - if ( currtok.Type != TokType::BraceSquare_Open ) - { - log_failure( "%s: Error, expected attribute name", context ); - return result; - } - - while ( left && currtok.Type != TokType::BraceSquare_Close ) - { - // TODO : Parse attributes - } - - eat( TokType::BraceSquare_Close ); - eat( TokType::BraceSquare_Close ); - } - - // Platform Specific attribute - eat( TokType::Attr_Keyword ); - eat( TokType::Capture_Start ); - - // TODO : Parse attributes - - eat( TokType::Capture_End ); - } - //! Fallthrough intentional - case TokType::Spec_Consteval: - case TokType::Spec_Constexpr: - case TokType::Spec_Constinit: - case TokType::Spec_Extern: - case TokType::Spec_Global: - case TokType::Spec_Inline: - case TokType::Spec_Internal_Linkage: - case TokType::Spec_Static: - { - SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; - s32 num_specifiers = 0; - - while ( left && tok_is_specifier( currtok ) ) - { - SpecifierT spec = ESpecifier::to_type( currtok ); - - switch ( spec ) - { - case ESpecifier::Constexpr: - case ESpecifier::Constinit: - case ESpecifier::Inline: - case ESpecifier::Mutable: - case ESpecifier::Static: - case ESpecifier::Volatile: - break; - - case ESpecifier::Consteval: - expects_function = true; - break; - - default: - log_failure( "gen::parse_global_nspace: invalid specifier " "%s" " for variable", ESpecifier::to_str(spec) ); - return CodeInvalid; - } - - specs_found[num_specifiers] = spec; - num_specifiers++; - eat( currtok.Type ); - } - - if ( num_specifiers ) - { - specifiers = def_specifiers( num_specifiers, specs_found ); - } - } - //! Fallthrough intentional - case TokType::Identifier: - case TokType::Spec_Const: - case TokType::Type_Long: - case TokType::Type_Short: - case TokType::Type_Signed: - case TokType::Type_Unsigned: - { - member = parse_operator_function_or_variable( expects_function, attributes, specifiers, toks, context ); - } - } - - if ( member == Code::Invalid ) - { - log_failure( "gen::%s: failed to parse extern linkage member", context ); - return CodeInvalid; - } - - result.append( member ); - } - - if ( which != Global_Body ) - eat( TokType::BraceCurly_Close ); - - return result; - } - - internal - CodeClass parse_class( Parser::TokArray& toks, char const* context ) - { - return (CodeClass) parse_class_struct( Parser::TokType::Decl_Class, toks, context ); - } - - CodeClass parse_class( StrC def ) - { - check_parse_args( parse_class, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return (CodeClass) parse_class_struct( TokType::Decl_Class, toks, stringize(parse_class) ); - } - - internal - CodeEnum parse_enum( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - using namespace ECode; - - SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; - s32 num_specifiers = 0; - - Token name = { nullptr, 0, TokType::Invalid }; - Code array_expr = { nullptr }; - CodeType type = { nullptr }; - Token body = { nullptr, 0, TokType::Invalid }; - - char entries_code[ kilobytes(128) ] { 0 }; - s32 entries_length = 0; - - bool is_enum_class = false; - - eat( TokType::Decl_Enum ); - - if ( currtok.Type == TokType::Decl_Class ) - { - eat( TokType::Decl_Class); - is_enum_class = true; - } - - // TODO : Parse attributes - - if ( currtok.Type != TokType::Identifier ) - { - log_failure( "gen::parse_enum: expected identifier for enum name" ); - return CodeInvalid; - } - - name = currtok; - eat( TokType::Identifier ); - - if ( currtok.Type == TokType::Assign_Classifer ) - { - eat( TokType::Assign_Classifer ); - - type = parse_type( toks, stringize(parse_enum) ); - if ( type == Code::Invalid ) - return CodeInvalid; - } - - if ( currtok.Type == TokType::BraceCurly_Open ) - { - eat( TokType::BraceCurly_Open ); - - body = currtok; - - while ( currtok.Type != TokType::BraceCurly_Close ) - { - eat( TokType::Identifier); - - if ( currtok.Type == TokType::Operator && currtok.Text[0] == '=' ) - { - eat( TokType::Operator ); - - while ( currtok.Type != TokType::Comma && currtok.Type != TokType::BraceCurly_Close ) - { - eat( currtok.Type ); - } - } - - if ( currtok.Type == TokType::Comma ) - { - eat( TokType::Comma ); - } - } - - body.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)body.Text; - - eat( TokType::BraceCurly_Close ); - } - - eat( TokType::Statement_End ); - - using namespace ECode; - - CodeEnum - result = (CodeEnum) make_code(); - - if ( body.Length ) - { - // mem_copy( entries_code, body.Text, body.Length ); - - Code untyped_body = untyped_str( body ); - - result->Type = is_enum_class ? Enum_Class : Enum; - result->Body = untyped_body; - } - else - { - result->Type = is_enum_class ? Enum_Class_Fwd : Enum_Fwd; - } - - result->Name = get_cached_string( name ); - - if ( type ) - result->UnderlyingType = type; - - return result; - } - - CodeEnum parse_enum( StrC def ) - { - check_parse_args( parse_enum, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return parse_enum( toks, stringize(parse_enum) ); - } - - internal inline - CodeBody parse_export_body( Parser::TokArray& toks, char const* context ) - { - return parse_global_nspace( ECode::Export_Body, toks, context ); - } - - CodeBody parse_export_body( StrC def ) - { - check_parse_args( parse_export_body, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return parse_export_body( toks, stringize(parse_export_body) ); - } - - internal inline - CodeBody parse_extern_link_body( Parser::TokArray& toks, char const* context ) - { - return parse_global_nspace( ECode::Extern_Linkage_Body, toks, context ); - } - - internal - CodeExtern parse_extern_link( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - - eat( TokType::Decl_Extern_Linkage ); - - Token name = currtok; - eat( TokType::String ); - - name.Text += 1; - name.Length -= 1; - - CodeExtern - result = (CodeExtern) make_code(); - result->Type = ECode::Extern_Linkage; - result->Name = get_cached_string( name ); - - Code entry = parse_extern_link_body( toks, context ); - if ( entry == Code::Invalid ) - { - log_failure( "gen::parse_extern_link: failed to parse body" ); - return result; - } - - result->Body = entry; - - return result; - } - - CodeExtern parse_extern_link( StrC def ) - { - check_parse_args( parse_extern_link, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return parse_extern_link( toks, stringize(parse_extern_link) ); - } - - internal - CodeFriend parse_friend( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - using namespace ECode; - - eat( TokType::Decl_Friend ); - - CodeFn function = { nullptr }; - - // Type declaration or return type - CodeType type = parse_type( toks, stringize(parse_friend) ); - if ( type == Code::Invalid ) - return CodeInvalid; - - // Funciton declaration - if ( currtok.Type == TokType::Identifier ) - { - // Name - Token name = parse_identifier( toks, stringize(parse_friend) ); - - // Parameter list - CodeParam params = parse_params( toks, stringize(parse_friend) ); - - function = make_code(); - function->Type = Function_Fwd; - function->Name = get_cached_string( name ); - function->ReturnType = type; - - if ( params ) - function->Params = params; - } - - eat( TokType::Statement_End ); - - CodeFriend - result = (CodeFriend) make_code(); - result->Type = Friend; - - if ( function ) - result->Declaration = function; - - else - result->Declaration = type; - - return result; - } - - CodeFriend parse_friend( StrC def ) - { - check_parse_args( parse_friend, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return parse_friend( toks, stringize(parse_friend) ); - } - - internal - CodeFn parse_functon( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - - SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; - s32 num_specifiers = 0; - - CodeAttributes attributes = { nullptr }; - CodeSpecifier specifiers = { nullptr }; - - // TODO : Parse module specifiers - - // TODO : Parse attributes - - while ( left && tok_is_specifier( currtok ) ) - { - SpecifierT spec = ESpecifier::to_type( currtok ); - - switch ( spec ) - { - case ESpecifier::Const: - case ESpecifier::Consteval: - case ESpecifier::Constexpr: - case ESpecifier::External_Linkage: - case ESpecifier::Inline: - case ESpecifier::Static: - break; - - default: - log_failure( "gen::parse_functon: invalid specifier " "%s" " for functon", ESpecifier::to_str(spec) ); - return CodeInvalid; - } - - specs_found[num_specifiers] = spec; - num_specifiers++; - eat( currtok.Type ); - } - - if ( num_specifiers ) - { - specifiers = def_specifiers( num_specifiers, specs_found ); - } - - CodeType ret_type = parse_type( toks, stringize(parse_function) ); - if ( ret_type == Code::Invalid ) - return CodeInvalid; - - Token name = parse_identifier( toks, stringize(parse_function) ); - if ( ! name ) - return CodeInvalid; - - CodeFn result = parse_function_after_name( ModuleFlag::None, attributes, specifiers, ret_type, name, toks, context ); - - return result; - } - - CodeFn parse_function( StrC def ) - { - using namespace Parser; - - check_parse_args( parse_function, def ); - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return (CodeFn) parse_functon( toks, stringize(parse_function) ); - } - - CodeBody parse_global_body( StrC def ) - { - check_parse_args( parse_global_body, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return parse_global_nspace( ECode::Global_Body, toks, stringize(parse_global_body) ); - } - - internal - CodeNamespace parse_namespace( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - eat( TokType::Decl_Namespace ); - - Token name = parse_identifier( toks, stringize(parse_namespace) ); - - CodeBody body = parse_global_nspace( ECode::Namespace_Body, toks, stringize(parse_namespace) ); - if ( body == Code::Invalid ) - return CodeInvalid; - - CodeNamespace - result = (CodeNamespace) make_code(); - result->Type = ECode::Namespace; - result->Name = get_cached_string( name ); - + result->Type = ECode::Operator_Cast; result->Body = body; - - return result; + } + else + { + result->Type = ECode::Operator_Cast_Fwd; } - CodeNamespace parse_namespace( StrC def ) + result->ValueType = type; + + return result; +} + +CodeOpCast parse_operator_cast( StrC def ) +{ + check_parse_args( parse_operator_cast, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return parse_operator_cast( toks, stringize(parse_operator_cast) ); +} + +internal inline +CodeStruct parse_struct( Parser::TokArray& toks, char const* context ) +{ + return (CodeStruct) parse_class_struct( Parser::TokType::Decl_Struct, toks, stringize(parse_struct) ); +} + +CodeStruct parse_struct( StrC def ) +{ + check_parse_args( parse_struct, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return (CodeStruct) parse_class_struct( TokType::Decl_Struct, toks, stringize(parse_struct) ); +} + +internal +CodeTemplate parse_template( Parser::TokArray& toks, char const* context ) +{ +# define UseTemplateCapture true + + using namespace Parser; + + // TODO : Parse Module specifier + + eat( TokType::Decl_Template ); + + Code params = parse_params( toks, stringize(parse_template), UseTemplateCapture ); + if ( params == Code::Invalid ) + return CodeInvalid; + + Code definition = { nullptr }; + + while ( left ) { - check_parse_args( parse_namespace, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return parse_namespace( toks, stringize(parse_namespace) ); - } - - internal - CodeOperator parse_operator( Parser::TokArray& toks, char const* context ) - { - // TODO : Parse Module specifier - - // TODO : Parse Attributes - CodeAttributes attributes = { nullptr }; - - CodeSpecifier specifiers = { nullptr }; - - SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; - s32 num_specifiers = 0; - - while ( left && tok_is_specifier( currtok ) ) + if ( check( TokType::Decl_Class ) ) { - SpecifierT spec = ESpecifier::to_type( currtok ); - - switch ( spec ) - { - case ESpecifier::Const: - case ESpecifier::Constexpr: - case ESpecifier::Inline: - case ESpecifier::Static: - break; - - default: - log_failure( "gen::parse_operator: invalid specifier " "%s" " for operator", ESpecifier::to_str(spec) ); - return CodeInvalid; - } - - specs_found[num_specifiers] = spec; - num_specifiers++; - eat( currtok.Type ); - } - - if ( num_specifiers ) - { - specifiers = def_specifiers( num_specifiers, specs_found ); - } - - // Parse Return Type - CodeType ret_type = parse_type( toks, stringize(parse_operator) ); - - CodeOperator result = parse_operator_after_ret_type( ModuleFlag::None, attributes, specifiers, ret_type, toks, context ); - return result; - } - - CodeOperator parse_operator( StrC def ) - { - check_parse_args( parse_operator, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return (CodeOperator) parse_operator( toks, stringize(parse_operator) ); - } - - CodeOpCast parse_operator_cast( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - - eat( TokType::Decl_Operator ); - - Code type = parse_type( toks, stringize(parse_operator_cast) ); - - eat( TokType::Capture_Start ); - eat( TokType::Capture_End ); - - Code body = { nullptr }; - - if ( check( TokType::BraceCurly_Open) ) - { - eat( TokType::BraceCurly_Open ); - - Token body_str = currtok; - - s32 level = 0; - while ( left && ( currtok.Type != TokType::BraceCurly_Close || level > 0 ) ) - { - if ( currtok.Type == TokType::BraceCurly_Open ) - level++; - - else if ( currtok.Type == TokType::BraceCurly_Close && level > 0 ) - level--; - - eat( currtok.Type ); - } - - body_str.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)body_str.Text; - - body = untyped_str( body_str ); - - eat( TokType::BraceCurly_Close ); - } - - CodeOpCast result = (CodeOpCast) make_code(); - - if (body) - { - result->Type = ECode::Operator_Cast; - result->Body = body; - } - else - { - result->Type = ECode::Operator_Cast_Fwd; - } - - result->ValueType = type; - - return result; - } - - CodeOpCast parse_operator_cast( StrC def ) - { - check_parse_args( parse_operator_cast, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return parse_operator_cast( toks, stringize(parse_operator_cast) ); - } - - internal inline - CodeStruct parse_struct( Parser::TokArray& toks, char const* context ) - { - return (CodeStruct) parse_class_struct( Parser::TokType::Decl_Struct, toks, stringize(parse_struct) ); - } - - CodeStruct parse_struct( StrC def ) - { - check_parse_args( parse_struct, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return (CodeStruct) parse_class_struct( TokType::Decl_Struct, toks, stringize(parse_struct) ); - } - - internal - CodeTemplate parse_template( Parser::TokArray& toks, char const* context ) - { - # define UseTemplateCapture true - - using namespace Parser; - - // TODO : Parse Module specifier - - eat( TokType::Decl_Template ); - - Code params = parse_params( toks, stringize(parse_template), UseTemplateCapture ); - if ( params == Code::Invalid ) - return CodeInvalid; - - Code definition = { nullptr }; - - while ( left ) - { - if ( check( TokType::Decl_Class ) ) - { - definition = parse_class( toks, stringize(parse_template) ); - break; - } - - if ( check( TokType::Decl_Struct ) ) - { - definition = parse_enum( toks, stringize(parse_template) ); - break; - } - - if ( check( TokType::Decl_Using )) - { - definition = parse_using( toks, stringize(parse_template) ); - break; - } - - // Its either a function or a variable - Token name = { nullptr, 0, TokType::Invalid }; - - - CodeAttributes attributes = { nullptr }; - CodeSpecifier specifiers = { nullptr }; - - // TODO : Parse attributes - - bool expects_function = false; - - SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; - s32 num_specifiers = 0; - - while ( left && tok_is_specifier( currtok ) ) - { - SpecifierT spec = ESpecifier::to_type( currtok ); - - switch ( spec ) - { - case ESpecifier::Const: - case ESpecifier::Constexpr: - case ESpecifier::Constinit: - case ESpecifier::External_Linkage: - case ESpecifier::Global: - case ESpecifier::Inline: - case ESpecifier::Local_Persist: - case ESpecifier::Mutable: - case ESpecifier::Static: - case ESpecifier::Thread_Local: - case ESpecifier::Volatile: - break; - - case ESpecifier::Consteval: - expects_function = true; - break; - - default: - log_failure( "gen::parse_template: invalid specifier %s for variable or function", ESpecifier::to_str( spec ) ); - return CodeInvalid; - } - - // Ignore const it will be handled by the type - if ( spec == ESpecifier::Const ) - continue; - - specs_found[num_specifiers] = spec; - num_specifiers++; - eat( currtok.Type ); - } - - if ( num_specifiers ) - { - specifiers = def_specifiers( num_specifiers, specs_found ); - } - - definition = parse_operator_function_or_variable( expects_function, attributes, specifiers, toks, stringize(parse_template) ); + definition = parse_class( toks, stringize(parse_template) ); break; } - CodeTemplate - result = (CodeTemplate) make_code(); - result->Type = ECode::Template; - result->Params = params; - result->Declaration = definition; - - return result; - # undef UseTemplateCapture - } - - CodeTemplate parse_template( StrC def ) - { - check_parse_args( parse_template, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return parse_template( toks, stringize(parse_template) ); - } - - internal - CodeType parse_type( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - - Token context_tok = prevtok; - - SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; - s32 num_specifiers = 0; - - Token name = { nullptr, 0, TokType::Invalid }; - Token brute_sig = { currtok.Text, 0, TokType::Invalid }; - - while ( left && tok_is_specifier( currtok ) ) + if ( check( TokType::Decl_Struct ) ) { - SpecifierT spec = ESpecifier::to_type( currtok ); - - if ( spec != ESpecifier::Const ) - { - log_failure( "gen::parse_type: Error, invalid specifier used in type definition: %s", currtok.Text ); - return CodeInvalid; - } - - specs_found[num_specifiers] = spec; - num_specifiers++; - eat( currtok.Type ); + definition = parse_enum( toks, stringize(parse_template) ); + break; } - if ( left == 0 ) + if ( check( TokType::Decl_Using )) { - log_failure( "%s: Error, unexpected end of type definition", context ); - return CodeInvalid; + definition = parse_using( toks, stringize(parse_template) ); + break; } - if ( currtok.Type == TokType::Decl_Class - || currtok.Type == TokType::Decl_Enum - || currtok.Type == TokType::Decl_Struct ) - { - name = currtok; - eat( currtok.Type ); - - name.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)name.Text; - eat( TokType::Identifier ); - } - else if ( currtok.Type >= TokType::Type_Unsigned ) - { - name = currtok; - eat( currtok.Type ); - - while (currtok.Type >= TokType::Type_Unsigned) - { - eat( currtok.Type ); - } - - name.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)name.Text; - } - else - { - name = parse_identifier( toks, context ); - if ( ! name ) - return CodeInvalid; - - // Problably dealing with a templated symbol - if ( currtok.Type == TokType::Operator && currtok.Text[0] == '<' && currtok.Length == 1 ) - { - eat( TokType::Operator ); - - s32 level = 0; - while ( left && ( currtok.Text[0] != '>' || level > 0 )) - { - if ( currtok.Text[0] == '<' ) - level++; - - if ( currtok.Text[0] == '>' ) - level--; - - eat( currtok.Type ); - } - - eat( TokType::Operator ); - - // Extend length of name to last token - name.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)name.Text; - } - } - - while ( left && tok_is_specifier( currtok ) ) - { - SpecifierT spec = ESpecifier::to_type( currtok ); - - if ( spec != ESpecifier::Const - && spec != ESpecifier::Ptr - && spec != ESpecifier::Ref - && spec != ESpecifier::RValue ) - { - log_failure( "%s: Error, invalid specifier used in type definition: %s", context, currtok.Text ); - return CodeInvalid; - } - - specs_found[num_specifiers] = spec; - num_specifiers++; - eat( currtok.Type ); - } - - // Not sure if its technically possible to cast ot a function pointer user defined operator cast... - // Supporting it is not worth the effort. - if ( check( TokType::Capture_Start ) && context_tok.Type != TokType::Decl_Operator ) - { - // Its a function type - eat( TokType::Capture_Start ); - - while ( check( TokType::Star ) || currtok.Type == TokType::Spec_Const ) - { - eat( currtok.Type ); - } - - // if its a using statement there will not be an ID. - if ( check( TokType::Identifier ) ) - eat(TokType::Identifier); - - eat( TokType::Capture_End ); - - // Parameters - - eat( TokType::Capture_Start ); - - // TODO : Change this to validate the parameters... - // Bruteforce lex the parameters, no validation. - s32 level = 0; - while ( ! check( TokType::Capture_End ) || level > 0 ) - { - if ( check( TokType::Capture_Start ) ) - level++; - - if ( check( TokType::Capture_End ) ) - level--; - - eat( currtok.Type ); - } - - eat(TokType::Capture_End); - - brute_sig.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)brute_sig.Text; - } - - using namespace ECode; - - CodeType - result = (CodeType) make_code(); - result->Type = Typename; - - if ( brute_sig.Length > 0 ) - { - // Bruteforce all tokens together. - name = brute_sig; - } - else - { - if (num_specifiers) - { - Code specifiers = def_specifiers( num_specifiers, (SpecifierT*)specs_found ); - result->Specs = specifiers; - } - } - - result->Name = get_cached_string( name ); - - return result; - } - - CodeType parse_type( StrC def ) - { - check_parse_args( parse_type, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - CodeType result = parse_type( toks, stringize(parse_type) ); - - return result; - } - - internal - CodeTypedef parse_typedef( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - - Token name = { nullptr, 0, TokType::Invalid }; - Code array_expr = { nullptr }; - Code type = { nullptr }; - - eat( TokType::Decl_Typedef ); - - if ( check( TokType::Decl_Enum ) ) - type = parse_enum( toks, context ); - - else if ( check(TokType::Decl_Struct ) ) - type = parse_enum( toks, context ); - - else if ( check(TokType::Decl_Union) ) - type = parse_union( toks, context ); - - else - type = parse_type( toks, context ); - - if ( ! check( TokType::Identifier ) ) - { - log_failure( "gen::parse_typedef: Error, expected identifier for typedef" ); - return CodeInvalid; - } - - name = currtok; - eat( TokType::Identifier ); - - array_expr = parse_array_decl( toks, context ); - - eat( TokType::Statement_End ); - - using namespace ECode; - - CodeTypedef - result = (CodeTypedef) make_code(); - result->Type = Typedef; - result->Name = get_cached_string( name ); - - result->UnderlyingType = type; - - if ( type->Type == Typename && array_expr && array_expr->Type != Invalid ) - type.cast()->ArrExpr = array_expr; - - return result; - } - - CodeTypedef parse_typedef( StrC def ) - { - check_parse_args( parse_typedef, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return parse_typedef( toks, stringize(parse_typedef) ); - } - - internal - CodeUnion parse_union( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - - // TODO : Parse module spec - - eat( TokType::Decl_Union ); - - // TODO : Parse attributes - CodeAttributes attributes = { nullptr }; - - StrC name = { 0, nullptr }; - - if ( check( TokType::Identifier ) ) - { - name = currtok; - eat( TokType::Identifier ); - } - - CodeBody body = { nullptr }; - - eat( TokType::BraceCurly_Open ); - - body = make_code(); - body->Type = ECode::Union_Body; - - while ( ! check( TokType::BraceCurly_Close ) ) - { - Code entry = parse_variable( toks, context ); - - if ( entry ) - body.append( entry ); - } - - eat( TokType::BraceCurly_Close ); - eat( TokType::Statement_End ); - - CodeUnion - result = (CodeUnion) make_code(); - result->Type = ECode::Union; - - if ( name ) - result->Name = get_cached_string( name ); - - if ( body ) - result->Body = body; - - if ( attributes ) - result->Attributes = attributes; - - return result; - } - - CodeUnion parse_union( StrC def ) - { - check_parse_args( parse_union, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return parse_union( toks, stringize(parse_union) ); - } - - internal - CodeUsing parse_using( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - - SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; - s32 num_specifiers = 0; - - Token name = { nullptr, 0, TokType::Invalid }; - Code array_expr = { nullptr }; - CodeType type = { nullptr }; - - bool is_namespace = false; - - // TODO : Parse module specs - - eat( TokType::Decl_Using ); - - if ( currtok.Type == TokType::Decl_Namespace ) - { - is_namespace = true; - eat( TokType::Decl_Namespace ); - } - - name = currtok; - eat( TokType::Identifier ); - - if ( currtok.IsAssign ) - { - // TODO : Parse Attributes (using type-alias) - - eat( TokType::Operator ); - - type = parse_type( toks, context ); - } - - array_expr = parse_array_decl( toks, context ); - - eat( TokType::Statement_End ); - - using namespace ECode; - - CodeUsing - result = (CodeUsing) make_code(); - result->Name = get_cached_string( name ); - - if ( is_namespace) - { - result->Type = Using_Namespace; - } - else - { - result->Type = Using; - - if ( type ) - result->UnderlyingType = type; - - if ( array_expr ) - type->ArrExpr = array_expr; - } - return result; - } - - CodeUsing parse_using( StrC def ) - { - check_parse_args( parse_using, def ); - using namespace Parser; - - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return parse_using( toks, stringize(parse_using) ); - } - - internal - CodeVar parse_variable( Parser::TokArray& toks, char const* context ) - { - using namespace Parser; - + // Its either a function or a variable Token name = { nullptr, 0, TokType::Invalid }; - SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; - s32 num_specifiers = 0; - CodeAttributes attributes = { nullptr }; - CodeSpecifier specifiers = { nullptr }; - - // TODO : Parse module specifiers + CodeAttributes attributes = { nullptr }; + CodeSpecifier specifiers = { nullptr }; // TODO : Parse attributes + bool expects_function = false; + + SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; + s32 num_specifiers = 0; + while ( left && tok_is_specifier( currtok ) ) { SpecifierT spec = ESpecifier::to_type( currtok ); @@ -6287,12 +5814,16 @@ namespace gen case ESpecifier::Volatile: break; + case ESpecifier::Consteval: + expects_function = true; + break; + default: - log_failure( "gen::parse_variable: invalid specifier %s for variable", ESpecifier::to_str( spec ) ); + log_failure( "gen::parse_template: invalid specifier %s for variable or function", ESpecifier::to_str( spec ) ); return CodeInvalid; } - // Ignore const specifiers, they're handled by the type + // Ignore const it will be handled by the type if ( spec == ESpecifier::Const ) continue; @@ -6306,32 +5837,501 @@ namespace gen specifiers = def_specifiers( num_specifiers, specs_found ); } - CodeType type = parse_type( toks, context ); + definition = parse_operator_function_or_variable( expects_function, attributes, specifiers, toks, stringize(parse_template) ); + break; + } - if ( type == Code::Invalid ) + CodeTemplate + result = (CodeTemplate) make_code(); + result->Type = ECode::Template; + result->Params = params; + result->Declaration = definition; + + return result; +# undef UseTemplateCapture +} + +CodeTemplate parse_template( StrC def ) +{ + check_parse_args( parse_template, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return parse_template( toks, stringize(parse_template) ); +} + +internal +CodeType parse_type( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + + Token context_tok = prevtok; + + SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; + s32 num_specifiers = 0; + + Token name = { nullptr, 0, TokType::Invalid }; + Token brute_sig = { currtok.Text, 0, TokType::Invalid }; + + while ( left && tok_is_specifier( currtok ) ) + { + SpecifierT spec = ESpecifier::to_type( currtok ); + + if ( spec != ESpecifier::Const ) + { + log_failure( "gen::parse_type: Error, invalid specifier used in type definition: %s", currtok.Text ); + return CodeInvalid; + } + + specs_found[num_specifiers] = spec; + num_specifiers++; + eat( currtok.Type ); + } + + if ( left == 0 ) + { + log_failure( "%s: Error, unexpected end of type definition", context ); + return CodeInvalid; + } + + if ( currtok.Type == TokType::Decl_Class + || currtok.Type == TokType::Decl_Enum + || currtok.Type == TokType::Decl_Struct ) + { + name = currtok; + eat( currtok.Type ); + + name.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)name.Text; + eat( TokType::Identifier ); + } + else if ( currtok.Type >= TokType::Type_Unsigned ) + { + name = currtok; + eat( currtok.Type ); + + while (currtok.Type >= TokType::Type_Unsigned) + { + eat( currtok.Type ); + } + + name.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)name.Text; + } + else + { + name = parse_identifier( toks, context ); + if ( ! name ) return CodeInvalid; + // Problably dealing with a templated symbol + if ( currtok.Type == TokType::Operator && currtok.Text[0] == '<' && currtok.Length == 1 ) + { + eat( TokType::Operator ); + + s32 level = 0; + while ( left && ( currtok.Text[0] != '>' || level > 0 )) + { + if ( currtok.Text[0] == '<' ) + level++; + + if ( currtok.Text[0] == '>' ) + level--; + + eat( currtok.Type ); + } + + eat( TokType::Operator ); + + // Extend length of name to last token + name.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)name.Text; + } + } + + while ( left && tok_is_specifier( currtok ) ) + { + SpecifierT spec = ESpecifier::to_type( currtok ); + + if ( spec != ESpecifier::Const + && spec != ESpecifier::Ptr + && spec != ESpecifier::Ref + && spec != ESpecifier::RValue ) + { + log_failure( "%s: Error, invalid specifier used in type definition: %s", context, currtok.Text ); + return CodeInvalid; + } + + specs_found[num_specifiers] = spec; + num_specifiers++; + eat( currtok.Type ); + } + + // Not sure if its technically possible to cast ot a function pointer user defined operator cast... + // Supporting it is not worth the effort. + if ( check( TokType::Capture_Start ) && context_tok.Type != TokType::Decl_Operator ) + { + // Its a function type + eat( TokType::Capture_Start ); + + while ( check( TokType::Star ) || currtok.Type == TokType::Spec_Const ) + { + eat( currtok.Type ); + } + + // if its a using statement there will not be an ID. + if ( check( TokType::Identifier ) ) + eat(TokType::Identifier); + + eat( TokType::Capture_End ); + + // Parameters + + eat( TokType::Capture_Start ); + + // TODO : Change this to validate the parameters... + // Bruteforce lex the parameters, no validation. + s32 level = 0; + while ( ! check( TokType::Capture_End ) || level > 0 ) + { + if ( check( TokType::Capture_Start ) ) + level++; + + if ( check( TokType::Capture_End ) ) + level--; + + eat( currtok.Type ); + } + + eat(TokType::Capture_End); + + brute_sig.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)brute_sig.Text; + } + + using namespace ECode; + + CodeType + result = (CodeType) make_code(); + result->Type = Typename; + + if ( brute_sig.Length > 0 ) + { + // Bruteforce all tokens together. + name = brute_sig; + } + else + { + if (num_specifiers) + { + Code specifiers = def_specifiers( num_specifiers, (SpecifierT*)specs_found ); + result->Specs = specifiers; + } + } + + result->Name = get_cached_string( name ); + + return result; +} + +CodeType parse_type( StrC def ) +{ + check_parse_args( parse_type, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + CodeType result = parse_type( toks, stringize(parse_type) ); + + return result; +} + +internal +CodeTypedef parse_typedef( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + + Token name = { nullptr, 0, TokType::Invalid }; + Code array_expr = { nullptr }; + Code type = { nullptr }; + + eat( TokType::Decl_Typedef ); + + if ( check( TokType::Decl_Enum ) ) + type = parse_enum( toks, context ); + + else if ( check(TokType::Decl_Struct ) ) + type = parse_enum( toks, context ); + + else if ( check(TokType::Decl_Union) ) + type = parse_union( toks, context ); + + else + type = parse_type( toks, context ); + + if ( ! check( TokType::Identifier ) ) + { + log_failure( "gen::parse_typedef: Error, expected identifier for typedef" ); + return CodeInvalid; + } + + name = currtok; + eat( TokType::Identifier ); + + array_expr = parse_array_decl( toks, context ); + + eat( TokType::Statement_End ); + + using namespace ECode; + + CodeTypedef + result = (CodeTypedef) make_code(); + result->Type = Typedef; + result->Name = get_cached_string( name ); + + result->UnderlyingType = type; + + if ( type->Type == Typename && array_expr && array_expr->Type != Invalid ) + type.cast()->ArrExpr = array_expr; + + return result; +} + +CodeTypedef parse_typedef( StrC def ) +{ + check_parse_args( parse_typedef, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return parse_typedef( toks, stringize(parse_typedef) ); +} + +internal +CodeUnion parse_union( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + + // TODO : Parse module spec + + eat( TokType::Decl_Union ); + + // TODO : Parse attributes + CodeAttributes attributes = { nullptr }; + + StrC name = { 0, nullptr }; + + if ( check( TokType::Identifier ) ) + { name = currtok; eat( TokType::Identifier ); - - CodeVar result = parse_variable_after_name( ModuleFlag::None, attributes, specifiers, type, name, toks, context ); - - return result; } - CodeVar parse_variable( StrC def ) + CodeBody body = { nullptr }; + + eat( TokType::BraceCurly_Open ); + + body = make_code(); + body->Type = ECode::Union_Body; + + while ( ! check( TokType::BraceCurly_Close ) ) { - check_parse_args( parse_variable, def ); - using namespace Parser; + Code entry = parse_variable( toks, context ); - TokArray toks = lex( def ); - if ( toks.Arr == nullptr ) - return CodeInvalid; - - return parse_variable( toks, stringize(parse_variable) ); + if ( entry ) + body.append( entry ); } - // Undef helper macros + eat( TokType::BraceCurly_Close ); + eat( TokType::Statement_End ); + + CodeUnion + result = (CodeUnion) make_code(); + result->Type = ECode::Union; + + if ( name ) + result->Name = get_cached_string( name ); + + if ( body ) + result->Body = body; + + if ( attributes ) + result->Attributes = attributes; + + return result; +} + +CodeUnion parse_union( StrC def ) +{ + check_parse_args( parse_union, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return parse_union( toks, stringize(parse_union) ); +} + +internal +CodeUsing parse_using( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + + SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; + s32 num_specifiers = 0; + + Token name = { nullptr, 0, TokType::Invalid }; + Code array_expr = { nullptr }; + CodeType type = { nullptr }; + + bool is_namespace = false; + + // TODO : Parse module specs + + eat( TokType::Decl_Using ); + + if ( currtok.Type == TokType::Decl_Namespace ) + { + is_namespace = true; + eat( TokType::Decl_Namespace ); + } + + name = currtok; + eat( TokType::Identifier ); + + if ( currtok.IsAssign ) + { + // TODO : Parse Attributes (using type-alias) + + eat( TokType::Operator ); + + type = parse_type( toks, context ); + } + + array_expr = parse_array_decl( toks, context ); + + eat( TokType::Statement_End ); + + using namespace ECode; + + CodeUsing + result = (CodeUsing) make_code(); + result->Name = get_cached_string( name ); + + if ( is_namespace) + { + result->Type = Using_Namespace; + } + else + { + result->Type = Using; + + if ( type ) + result->UnderlyingType = type; + + if ( array_expr ) + type->ArrExpr = array_expr; + } + return result; +} + +CodeUsing parse_using( StrC def ) +{ + check_parse_args( parse_using, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return parse_using( toks, stringize(parse_using) ); +} + +internal +CodeVar parse_variable( Parser::TokArray& toks, char const* context ) +{ + using namespace Parser; + + Token name = { nullptr, 0, TokType::Invalid }; + + SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; + s32 num_specifiers = 0; + + CodeAttributes attributes = { nullptr }; + CodeSpecifier specifiers = { nullptr }; + + // TODO : Parse module specifiers + + // TODO : Parse attributes + + while ( left && tok_is_specifier( currtok ) ) + { + SpecifierT spec = ESpecifier::to_type( currtok ); + + switch ( spec ) + { + case ESpecifier::Const: + case ESpecifier::Constexpr: + case ESpecifier::Constinit: + case ESpecifier::External_Linkage: + case ESpecifier::Global: + case ESpecifier::Inline: + case ESpecifier::Local_Persist: + case ESpecifier::Mutable: + case ESpecifier::Static: + case ESpecifier::Thread_Local: + case ESpecifier::Volatile: + break; + + default: + log_failure( "gen::parse_variable: invalid specifier %s for variable", ESpecifier::to_str( spec ) ); + return CodeInvalid; + } + + // Ignore const specifiers, they're handled by the type + if ( spec == ESpecifier::Const ) + continue; + + specs_found[num_specifiers] = spec; + num_specifiers++; + eat( currtok.Type ); + } + + if ( num_specifiers ) + { + specifiers = def_specifiers( num_specifiers, specs_found ); + } + + CodeType type = parse_type( toks, context ); + + if ( type == Code::Invalid ) + return CodeInvalid; + + name = currtok; + eat( TokType::Identifier ); + + CodeVar result = parse_variable_after_name( ModuleFlag::None, attributes, specifiers, type, name, toks, context ); + + return result; +} + +CodeVar parse_variable( StrC def ) +{ + check_parse_args( parse_variable, def ); + using namespace Parser; + + TokArray toks = lex( def ); + if ( toks.Arr == nullptr ) + return CodeInvalid; + + return parse_variable( toks, stringize(parse_variable) ); +} + +// Undef helper macros # undef check_parse_args # undef curr_tok # undef eat @@ -6339,200 +6339,202 @@ namespace gen #pragma endregion Parsing Constructors #pragma region Untyped Constructors - sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va ) +sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va ) +{ + char const* buf_begin = buf; + sw remaining = buf_size; + + static Arena tok_map_arena; + + HashTable tok_map; { - char const* buf_begin = buf; - sw remaining = buf_size; + static char tok_map_mem[ TokenFmt_TokenMap_MemSize ]; - static Arena tok_map_arena; + tok_map_arena = Arena::init_from_memory( tok_map_mem, sizeof(tok_map_mem) ); - HashTable tok_map; + tok_map = HashTable::init( tok_map_arena ); + + s32 left = num_tokens - 1; + + while ( left-- ) { - static char tok_map_mem[ TokenFmt_TokenMap_MemSize ]; + char const* token = va_arg( va, char const* ); + StrC value = va_arg( va, StrC ); - tok_map_arena = Arena::init_from_memory( tok_map_mem, sizeof(tok_map_mem) ); + u32 key = crc32( token, str_len(token) ); - tok_map = HashTable::init( tok_map_arena ); + tok_map.set( key, value ); + } + } - s32 left = num_tokens - 1; + char const* fmt = va_arg( va, char const* ); + char current = *fmt; - while ( left-- ) - { - char const* token = va_arg( va, char const* ); - StrC value = va_arg( va, StrC ); + while ( current ) + { + sw len = 0; - u32 key = crc32( token, str_len(token) ); + while ( current && current != '<' && remaining ) + { + * buf = * fmt; + buf++; + fmt++; + remaining--; - tok_map.set( key, value ); - } + current = * fmt; } - char const* fmt = va_arg( va, char const* ); - char current = *fmt; - - while ( current ) + if ( current == '<' ) { - sw len = 0; + char const* scanner = fmt + 1; - while ( current && current != '<' && remaining ) + s32 tok_len = 0; + + while ( *scanner != '>' ) { - * buf = * fmt; - buf++; - fmt++; - remaining--; - - current = * fmt; + tok_len++; + scanner++; } - if ( current == '<' ) + char const* token = fmt + 1; + + u32 key = crc32( token, tok_len ); + StrC* value = tok_map.get( key ); + + if ( value ) { - char const* scanner = fmt + 1; + sw left = value->Len; + char const* str = value->Ptr; - s32 tok_len = 0; - - while ( *scanner != '>' ) + while ( left-- ) { - tok_len++; - scanner++; + * buf = * str; + buf++; + str++; + remaining--; } - char const* token = fmt + 1; - - u32 key = crc32( token, tok_len ); - StrC* value = tok_map.get( key ); - - if ( value ) - { - sw left = value->Len; - char const* str = value->Ptr; - - while ( left-- ) - { - * buf = * str; - buf++; - str++; - remaining--; - } - - scanner++; - fmt = scanner; - current = * fmt; - continue; - } - - * buf = * fmt; - buf++; - fmt++; - remaining--; - + scanner++; + fmt = scanner; current = * fmt; + continue; } + + * buf = * fmt; + buf++; + fmt++; + remaining--; + + current = * fmt; } - - tok_map.clear(); - tok_map_arena.free(); - - sw result = buf_size - remaining; - - return result; } - Code untyped_str( StrC content ) - { - Code - result = make_code(); - result->Name = get_cached_string( content ); - result->Type = ECode::Untyped; - result->Content = result->Name; + tok_map.clear(); + tok_map_arena.free(); - return result; - } + sw result = buf_size - remaining; - Code untyped_fmt( char const* fmt, ...) - { - local_persist thread_local - char buf[GEN_PRINTF_MAXLEN] = { 0 }; + return result; +} - va_list va; - va_start(va, fmt); - sw length = str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va); - va_end(va); +Code untyped_str( StrC content ) +{ + Code + result = make_code(); + result->Name = get_cached_string( content ); + result->Type = ECode::Untyped; + result->Content = result->Name; - Code - result = make_code(); - result->Name = get_cached_string( { str_len(fmt, MaxNameLength), fmt } ); - result->Type = ECode::Untyped; - result->Content = get_cached_string( { length, buf } ); + return result; +} - return result; - } +Code untyped_fmt( char const* fmt, ...) +{ + local_persist thread_local + char buf[GEN_PRINTF_MAXLEN] = { 0 }; - Code untyped_token_fmt( s32 num_tokens, ... ) - { - local_persist thread_local - char buf[GEN_PRINTF_MAXLEN] = { 0 }; + va_list va; + va_start(va, fmt); + sw length = str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va); + va_end(va); - va_list va; - va_start(va, num_tokens); - sw length = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num_tokens, va); - va_end(va); + Code + result = make_code(); + result->Name = get_cached_string( { str_len(fmt, MaxNameLength), fmt } ); + result->Type = ECode::Untyped; + result->Content = get_cached_string( { length, buf } ); - Code - result = make_code(); - result->Name = get_cached_string( { length, buf } ); - result->Type = ECode::Untyped; - result->Content = result->Name; + return result; +} - return result; - } +Code untyped_token_fmt( s32 num_tokens, ... ) +{ + local_persist thread_local + char buf[GEN_PRINTF_MAXLEN] = { 0 }; + + va_list va; + va_start(va, num_tokens); + sw length = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num_tokens, va); + va_end(va); + + Code + result = make_code(); + result->Name = get_cached_string( { length, buf } ); + result->Type = ECode::Untyped; + result->Content = result->Name; + + return result; +} #pragma endregion Untyped Constructors #pragma endregion Gen Interface #pragma region Builder - void Builder::print( Code code ) +void Builder::print( Code code ) +{ + Buffer.append_fmt( "%s\n", code->to_string() ); +} + +void Builder::print_fmt( char const* fmt, ... ) +{ + sw res; + char buf[ GEN_PRINTF_MAXLEN ] = { 0 }; + + va_list va; + va_start( va, fmt ); + res = str_fmt_va( buf, count_of( buf ) - 1, fmt, va ) - 1; + va_end( va ); + + Buffer.append( buf, res ); +} + +bool Builder::open( char const* path ) +{ + FileError error = file_open_mode( & File, EFileMode_WRITE, path ); + + if ( error != EFileError_NONE ) { - Buffer.append_fmt( "%s\n", code->to_string() ); + log_failure( "gen::File::open - Could not open file: %s", path); + return false; } - void Builder::print_fmt( char const* fmt, ... ) - { - sw res; - char buf[ GEN_PRINTF_MAXLEN ] = { 0 }; + Buffer = String::make_reserve( GlobalAllocator, Builder_StrBufferReserve ); - va_list va; - va_start( va, fmt ); - res = str_fmt_va( buf, count_of( buf ) - 1, fmt, va ) - 1; - va_end( va ); + return true; +} - Buffer.append( buf, res ); - } +void Builder::write() +{ + bool result = file_write( & File, Buffer, Buffer.length() ); - bool Builder::open( char const* path ) - { - FileError error = file_open_mode( & File, EFileMode_WRITE, path ); + if ( result == false ) + log_failure("gen::File::write - Failed to write to file: %s", file_name( & File ) ); - if ( error != EFileError_NONE ) - { - log_failure( "gen::File::open - Could not open file: %s", path); - return false; - } - - Buffer = String::make_reserve( GlobalAllocator, Builder_StrBufferReserve ); - - return true; - } - - void Builder::write() - { - bool result = file_write( & File, Buffer, Buffer.length() ); - - if ( result == false ) - log_failure("gen::File::write - Failed to write to file: %s", file_name( & File ) ); - - file_close( & File ); - Buffer.free(); - } + file_close( & File ); + Buffer.free(); +} #pragma endregion Builder + +// namespace gen } #include "gen.pop_ignores.inline.hpp" diff --git a/project/gen.dep.cpp b/project/gen.dep.cpp index f3a35c6..96287bd 100644 --- a/project/gen.dep.cpp +++ b/project/gen.dep.cpp @@ -39,6 +39,24 @@ # endif # endif +#include + +#ifdef GEN_SYSTEM_MACOS +# include +#endif + +#ifdef GEN_SYSTEM_CYGWIN +# include +#endif + +#if defined( GEN_SYSTEM_WINDOWS ) && ! defined( GEN_COMPILER_GCC ) +# include +#endif + +#if defined( GEN_SYSTEM_LINUX ) +# include +#endif + #ifdef GEN_BENCHMARK // Timing includes #if defined( GEN_SYSTEM_MACOS ) || GEN_SYSTEM_UNIX @@ -63,7 +81,6 @@ #pragma endregion Macros & Includes - namespace gen { #pragma region Debug @@ -2062,9 +2079,15 @@ namespace gen { GEN_ASSERT_NOT_NULL( root ); GEN_ASSERT_NOT_NULL( text ); zero_item( root ); + adt_make_branch( root, allocator, NULL, has_header ? false : true ); - char *p = text, *b = p, *e = p; - sw colc = 0, total_colc = 0; + + char* p = text; + char* b = p; + char* e = p; + + sw colc = 0; + sw total_colc = 0; do { @@ -2074,7 +2097,7 @@ namespace gen { break; ADT_Node row_item = { 0 }; row_item.type = EADT_TYPE_STRING; - #ifndef ZPL_PARSER_DISABLE_ANALYSIS + #ifndef GEN_PARSER_DISABLE_ANALYSIS row_item.name_style = EADT_NAME_STYLE_NO_QUOTES; #endif @@ -2083,7 +2106,7 @@ namespace gen { { p = b = e = p + 1; row_item.string = b; - #ifndef ZPL_PARSER_DISABLE_ANALYSIS + #ifndef GEN_PARSER_DISABLE_ANALYSIS row_item.name_style = EADT_NAME_STYLE_DOUBLE_QUOTE; #endif do @@ -2229,7 +2252,7 @@ namespace gen { { case EADT_TYPE_STRING : { - #ifndef ZPL_PARSER_DISABLE_ANALYSIS + #ifndef GEN_PARSER_DISABLE_ANALYSIS switch ( node->name_style ) { case EADT_NAME_STYLE_DOUBLE_QUOTE : @@ -2244,7 +2267,7 @@ namespace gen { { #endif str_fmt_file( file, "%s", node->string ); - #ifndef ZPL_PARSER_DISABLE_ANALYSIS + #ifndef GEN_PARSER_DISABLE_ANALYSIS } break; } @@ -3244,3 +3267,4 @@ namespace gen { // namespace gen } + diff --git a/project/gen.dep.hpp b/project/gen.dep.hpp index bec7f1b..e02362e 100644 --- a/project/gen.dep.hpp +++ b/project/gen.dep.hpp @@ -10,7 +10,7 @@ # define GEN_ARCH_64_BIT 1 # endif #else -# ifndef GEN_ARCH_32_BIT +# ifndef GEN_ARCH_32_BItxt_StrCaT # define GEN_ARCH_32_BIT 1 # endif #endif @@ -91,6 +91,15 @@ # define GEN_HAS_ATTRIBUTE( attribute ) ( 0 ) #endif +#if defined(GEN_GCC_VERSION_CHECK) +# undef GEN_GCC_VERSION_CHECK +#endif +#if defined(GEN_GCC_VERSION) +# define GEN_GCC_VERSION_CHECK(major,minor,patch) (GEN_GCC_VERSION >= GEN_VERSION_ENCODE(major, minor, patch)) +#else +# define GEN_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + #define GEN_DEF_INLINE static #define GEN_IMPL_INLINE static inline @@ -149,7 +158,7 @@ namespace gen { // Num Arguments (Varadics) #if defined(__GNUC__) || defined(__clang__) // Supports 0-10 arguments - #define num_args_impl( _0, \ + #define num_args_impl( _0, \ _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ N, ... \ @@ -159,8 +168,8 @@ namespace gen { // _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, // ## deletes preceding comma if _VA_ARGS__ is empty (GCC, Clang) - #define num_args(...) \ - num_args_impl(_, ## __VA_ARGS__, \ + #define num_args(...) \ + num_args_impl(_, ## __VA_ARGS__, \ 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, \ 0 \ @@ -170,14 +179,14 @@ namespace gen { // 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, #else // Supports 1-10 arguments - #define num_args_impl( \ - _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + #define num_args_impl( \ + _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ - N, ... \ + N, ... \ ) N - #define num_args(...) \ - num_args_impl( __VA_ARGS__, \ + #define num_args(...) \ + num_args_impl( __VA_ARGS__, \ 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 \ ) @@ -1283,6 +1292,7 @@ struct Array Type* target = Data + idx; mem_move( target + 1, target, (header->Num - idx) * sizeof(Type) ); + header->Num++; return true; } @@ -1309,7 +1319,6 @@ struct Array mem_move( target, src, (header->Num - idx) * sizeof(Type) ); mem_copy( src, items, item_num * sizeof(Type) ); - header->Num += item_num; return true; @@ -1730,378 +1739,378 @@ u64 crc64( void const* data, sw len ); #pragma endregion Hashing #pragma region String - // Constant string with length. - struct StrC - { - sw Len; - char const* Ptr; +// Constant string with length. +struct StrC +{ + sw Len; + char const* Ptr; - operator char const* () const - { - return Ptr; - } + operator char const* () const + { + return Ptr; + } +}; + +#define txt_StrC( text ) \ + StrC { sizeof( text ) - 1, text } + +StrC to_StrC( char const* str ) +{ + return { str_len( str ), str }; +} + +sw StrC_len( char const* str ) +{ + return (sw) ( str - 1 ); +} + +// Dynamic String +// This is directly based off the ZPL string api. +// They used a header pattern +// I kept it for simplicty of porting but its not necessary to keep it that way. +struct String +{ + struct Header + { + AllocatorInfo Allocator; + sw Length; + sw Capacity; }; - #define txt_StrC( text ) \ - (StrC){ sizeof( text ) - 1, text } - - StrC to_StrC( char const* str ) + static + uw grow_formula( uw value ) { - return { str_len( str ), str }; + // Using a very aggressive growth formula to reduce time mem_copying with recursive calls to append in this library. + return 4 * value + 8; } - sw StrC_len( char const* str ) + static + String make( AllocatorInfo allocator, char const* str ) { - return (sw) ( str - 1 ); + sw length = str ? str_len( str ) : 0; + return make_length( allocator, str, length ); } - // Dynamic String - // This is directly based off the ZPL string api. - // They used a header pattern - // I kept it for simplicty of porting but its not necessary to keep it that way. - struct String + static + String make( AllocatorInfo allocator, StrC str ) { - struct Header - { - AllocatorInfo Allocator; - sw Length; - sw Capacity; - }; + return make_length( allocator, str.Ptr, str.Len ); + } - static - uw grow_formula( uw value ) + static + String make_reserve( AllocatorInfo allocator, sw capacity ) + { + constexpr sw header_size = sizeof( Header ); + + s32 alloc_size = header_size + capacity + 1; + void* allocation = alloc( allocator, alloc_size ); + + if ( allocation == nullptr ) + return { nullptr }; + + mem_set( allocation, 0, alloc_size ); + + Header* + header = rcast(Header*, allocation); + header->Allocator = allocator; + header->Capacity = capacity; + header->Length = 0; + + String result = { (char*)allocation + header_size }; + return result; + } + + static + String make_length( AllocatorInfo allocator, char const* str, sw length ) + { + constexpr sw header_size = sizeof( Header ); + + s32 alloc_size = header_size + length + 1; + void* allocation = alloc( allocator, alloc_size ); + + if ( allocation == nullptr ) + return { nullptr }; + + Header& + header = * rcast(Header*, allocation); + header = { allocator, length, length }; + + String result = { rcast( char*, allocation) + header_size }; + + if ( length && str ) + mem_copy( result, str, length ); + else + mem_set( result, 0, alloc_size - header_size ); + + result[ length ] = '\0'; + + return result; + } + + static + String fmt( AllocatorInfo allocator, char* buf, sw buf_size, char const* fmt, ... ); + + static + String fmt_buf( AllocatorInfo allocator, char const* fmt, ... ); + + static + String join( AllocatorInfo allocator, char const** parts, sw num_parts, char const* glue ) + { + String result = make( allocator, "" ); + + for ( sw idx = 0; idx < num_parts; ++idx ) { - // Using a very aggressive growth formula to reduce time mem_copying with recursive calls to append in this library. - return 4 * value + 8; + result.append( parts[ idx ] ); + + if ( idx < num_parts - 1 ) + result.append( glue ); } - static - String make( AllocatorInfo allocator, char const* str ) - { - sw length = str ? str_len( str ) : 0; - return make_length( allocator, str, length ); - } + return result; + } - static - String make( AllocatorInfo allocator, StrC str ) - { - return make_length( allocator, str.Ptr, str.Len ); - } + static + bool are_equal( String lhs, String rhs ) + { + if ( lhs.length() != rhs.length() ) + return false; - static - String make_reserve( AllocatorInfo allocator, sw capacity ) - { - constexpr sw header_size = sizeof( Header ); - - s32 alloc_size = header_size + capacity + 1; - void* allocation = alloc( allocator, alloc_size ); - - if ( allocation == nullptr ) - return { nullptr }; - - mem_set( allocation, 0, alloc_size ); - - Header* - header = rcast(Header*, allocation); - header->Allocator = allocator; - header->Capacity = capacity; - header->Length = 0; - - String result = { (char*)allocation + header_size }; - return result; - } - - static - String make_length( AllocatorInfo allocator, char const* str, sw length ) - { - constexpr sw header_size = sizeof( Header ); - - s32 alloc_size = header_size + length + 1; - void* allocation = alloc( allocator, alloc_size ); - - if ( allocation == nullptr ) - return { nullptr }; - - Header& - header = * rcast(Header*, allocation); - header = { allocator, length, length }; - - String result = { rcast( char*, allocation) + header_size }; - - if ( length && str ) - mem_copy( result, str, length ); - else - mem_set( result, 0, alloc_size - header_size ); - - result[ length ] = '\0'; - - return result; - } - - static - String fmt( AllocatorInfo allocator, char* buf, sw buf_size, char const* fmt, ... ); - - static - String fmt_buf( AllocatorInfo allocator, char const* fmt, ... ); - - static - String join( AllocatorInfo allocator, char const** parts, sw num_parts, char const* glue ) - { - String result = make( allocator, "" ); - - for ( sw idx = 0; idx < num_parts; ++idx ) - { - result.append( parts[ idx ] ); - - if ( idx < num_parts - 1 ) - result.append( glue ); - } - - return result; - } - - static - bool are_equal( String lhs, String rhs ) - { - if ( lhs.length() != rhs.length() ) + for ( sw idx = 0; idx < lhs.length(); ++idx ) + if ( lhs[ idx ] != rhs[ idx ] ) return false; - for ( sw idx = 0; idx < lhs.length(); ++idx ) - if ( lhs[ idx ] != rhs[ idx ] ) - return false; + return true; + } + bool make_space_for( char const* str, sw add_len ) + { + sw available = avail_space(); + + // NOTE: Return if there is enough space left + if ( available >= add_len ) + { return true; } - - bool make_space_for( char const* str, sw add_len ) + else { - sw available = avail_space(); + sw new_len, old_size, new_size; - // NOTE: Return if there is enough space left - if ( available >= add_len ) - { - return true; - } - else - { - sw new_len, old_size, new_size; + void* ptr; + void* new_ptr; - void* ptr; - void* new_ptr; + AllocatorInfo allocator = get_header().Allocator; + Header* header = nullptr; - AllocatorInfo allocator = get_header().Allocator; - Header* header = nullptr; + new_len = grow_formula( length() + add_len ); + ptr = & get_header(); + old_size = size_of( Header ) + length() + 1; + new_size = size_of( Header ) + new_len + 1; - new_len = grow_formula( length() + add_len ); - ptr = & get_header(); - old_size = size_of( Header ) + length() + 1; - new_size = size_of( Header ) + new_len + 1; + new_ptr = resize( allocator, ptr, old_size, new_size ); - new_ptr = resize( allocator, ptr, old_size, new_size ); + if ( new_ptr == nullptr ) + return false; - if ( new_ptr == nullptr ) - return false; + header = zpl_cast( Header* ) new_ptr; + header->Allocator = allocator; + header->Capacity = new_len; - header = zpl_cast( Header* ) new_ptr; - header->Allocator = allocator; - header->Capacity = new_len; + Data = rcast( char*, header + 1 ); - Data = rcast( char*, header + 1 ); - - return str; - } - } - - bool append( char const* str ) - { - return append( str, str_len( str ) ); - } - - bool append( char const* str, sw length ) - { - if ( sptr(str) > 0 ) - { - sw curr_len = this->length(); - - if ( ! make_space_for( str, length ) ) - return false; - - Header& header = get_header(); - - mem_copy( Data + curr_len, str, length ); - - Data[ curr_len + length ] = '\0'; - - header.Length = curr_len + length; - } return str; } + } - bool append( StrC str) + bool append( char const* str ) + { + return append( str, str_len( str ) ); + } + + bool append( char const* str, sw length ) + { + if ( sptr(str) > 0 ) { - return append( str.Ptr, str.Len ); - } + sw curr_len = this->length(); - bool append( const String other ) - { - return append( other.Data, other.length() );; - } - - bool append_fmt( char const* fmt, ... ); - - sw avail_space() const - { - Header const& - header = * rcast( Header const*, Data - sizeof( Header )); - - return header.Capacity - header.Length; - } - - sw capacity() const - { - Header const& - header = * rcast( Header const*, Data - sizeof( Header )); - - return header.Capacity; - } - - void clear() - { - get_header().Length = 0; - } - - String duplicate( AllocatorInfo allocator ) - { - return make_length( allocator, Data, length() ); - } - - void free() - { - if ( ! Data ) - return; + if ( ! make_space_for( str, length ) ) + return false; Header& header = get_header(); - gen::free( header.Allocator, & header ); + mem_copy( Data + curr_len, str, length ); + + Data[ curr_len + length ] = '\0'; + + header.Length = curr_len + length; } + return str; + } - Header& get_header() - { - return *(Header*)(Data - sizeof(Header)); - } - - sw length() const - { - Header const& - header = * rcast( Header const*, Data - sizeof( Header )); - - return header.Length; - } - - void trim( char const* cut_set ) - { - sw len = 0; - - char* start_pos = Data; - char* end_pos = Data + length() - 1; - - while ( start_pos <= end_pos && char_first_occurence( cut_set, *start_pos ) ) - start_pos++; - - while ( end_pos > start_pos && char_first_occurence( cut_set, *end_pos ) ) - end_pos--; - - len = scast( sw, ( start_pos > end_pos ) ? 0 : ( ( end_pos - start_pos ) + 1 ) ); - - if ( Data != start_pos ) - mem_move( Data, start_pos, len ); - - Data[ len ] = '\0'; - - get_header().Length = len; - } - - void trim_space() - { - return trim( " \t\r\n\v\f" ); - } - - // For-range support - - char* begin() - { - return Data; - } - - char* end() - { - Header const& - header = * rcast( Header const*, Data - sizeof( Header )); - - return Data + header.Length; - } - - operator bool() - { - return Data; - } - - operator char* () - { - return Data; - } - - operator char const* () const - { - return Data; - } - - operator StrC() const - { - return - { - length(), - Data - }; - } - - // Used with cached strings - // Essentially makes the string a string view. - String const& operator = ( String const& other ) const - { - if ( this == & other ) - return *this; - - String& this_ = ccast( String, *this ); - - this_.Data = other.Data; - - return this_; - } - - char& operator [] ( sw index ) - { - return Data[ index ]; - } - - char const& operator [] ( sw index ) const - { - return Data[ index ]; - } - - char* Data = nullptr; - }; - - struct String_POD + bool append( StrC str) { - char* Data; + return append( str.Ptr, str.Len ); + } - operator String() + bool append( const String other ) + { + return append( other.Data, other.length() );; + } + + bool append_fmt( char const* fmt, ... ); + + sw avail_space() const + { + Header const& + header = * rcast( Header const*, Data - sizeof( Header )); + + return header.Capacity - header.Length; + } + + sw capacity() const + { + Header const& + header = * rcast( Header const*, Data - sizeof( Header )); + + return header.Capacity; + } + + void clear() + { + get_header().Length = 0; + } + + String duplicate( AllocatorInfo allocator ) + { + return make_length( allocator, Data, length() ); + } + + void free() + { + if ( ! Data ) + return; + + Header& header = get_header(); + + gen::free( header.Allocator, & header ); + } + + Header& get_header() + { + return *(Header*)(Data - sizeof(Header)); + } + + sw length() const + { + Header const& + header = * rcast( Header const*, Data - sizeof( Header )); + + return header.Length; + } + + void trim( char const* cut_set ) + { + sw len = 0; + + char* start_pos = Data; + char* end_pos = Data + length() - 1; + + while ( start_pos <= end_pos && char_first_occurence( cut_set, *start_pos ) ) + start_pos++; + + while ( end_pos > start_pos && char_first_occurence( cut_set, *end_pos ) ) + end_pos--; + + len = scast( sw, ( start_pos > end_pos ) ? 0 : ( ( end_pos - start_pos ) + 1 ) ); + + if ( Data != start_pos ) + mem_move( Data, start_pos, len ); + + Data[ len ] = '\0'; + + get_header().Length = len; + } + + void trim_space() + { + return trim( " \t\r\n\v\f" ); + } + + // For-range support + + char* begin() + { + return Data; + } + + char* end() + { + Header const& + header = * rcast( Header const*, Data - sizeof( Header )); + + return Data + header.Length; + } + + operator bool() + { + return Data; + } + + operator char* () + { + return Data; + } + + operator char const* () const + { + return Data; + } + + operator StrC() const + { + return { - return * rcast(String*, this); - } - }; - static_assert( sizeof( String_POD ) == sizeof( String ), "String is not a POD" ); + length(), + Data + }; + } + + // Used with cached strings + // Essentially makes the string a string view. + String const& operator = ( String const& other ) const + { + if ( this == & other ) + return *this; + + String& this_ = ccast( String, *this ); + + this_.Data = other.Data; + + return this_; + } + + char& operator [] ( sw index ) + { + return Data[ index ]; + } + + char const& operator [] ( sw index ) const + { + return Data[ index ]; + } + + char* Data = nullptr; +}; + +struct String_POD +{ + char* Data; + + operator String() + { + return * rcast(String*, this); + } +}; +static_assert( sizeof( String_POD ) == sizeof( String ), "String is not a POD" ); #pragma endregion String #pragma region File Handling @@ -2336,7 +2345,7 @@ GEN_DEF_INLINE s64 file_tell( FileInfo* file ); * @param buffer Buffer to read from * @param size Size to read */ -b32 file_write( FileInfo* file, void const* buffer, sw size ); +GEN_DEF_INLINE b32 file_write( FileInfo* file, void const* buffer, sw size ); /** * Writes to file at a specific offset @@ -2543,7 +2552,7 @@ struct ADT_Node /* properties */ ADT_Type type : 4; u8 props : 4; -#ifndef ZPL_PARSER_DISABLE_ANALYSIS +#ifndef GEN_PARSER_DISABLE_ANALYSIS u8 cfg_mode : 1; u8 name_style : 2; u8 assign_style : 2; @@ -2566,7 +2575,7 @@ struct ADT_Node s64 integer; }; -#ifndef ZPL_PARSER_DISABLE_ANALYSIS +#ifndef GEN_PARSER_DISABLE_ANALYSIS /* number analysis */ s32 base; s32 base2; diff --git a/project/gen.editor.hpp b/project/gen.editor.hpp index 2d7ca6d..6b8f900 100644 --- a/project/gen.editor.hpp +++ b/project/gen.editor.hpp @@ -1,6 +1,6 @@ #pragma once -#include "gen.hpp" +#include "gen.scanner.hpp" namespace gen { @@ -52,9 +52,9 @@ struct Editor static void set_allocator( AllocatorInfo allocator ); - Array(FileInfo) Files; + Array Files; String Buffer; - Array(RequestEntry) Requests; + Array Requests; void add_files( s32 num, char const** files ); @@ -66,7 +66,7 @@ struct Editor void refactor( char const* file_path, char const* specification_path ); # endif - bool process_requests( Array(Receipt) out_receipts ); + bool process_requests( Array out_receipts ); }; // namespace gen diff --git a/project/gen.hpp b/project/gen.hpp index 7449e9f..e36bbcb 100644 --- a/project/gen.hpp +++ b/project/gen.hpp @@ -14,7 +14,7 @@ #include "gen.push_ignores.inline.hpp" -//! If its desired to roll your own dependencies, define GENCPP_PROVIDE_DEPENDENCIES before including this file. +//! If its desired to roll your own dependencies, define GEN_ROLL_OWN_DEPENDENCIES before including this file. // Dependencies are derived from the c-zpl library: https://github.com/zpl-c/zpl #ifndef GEN_ROLL_OWN_DEPENDENCIES # include "gen.dep.hpp" @@ -240,9 +240,9 @@ namespace ESpecifier # pragma push_macro( "global" ) # pragma push_macro( "internal" ) # pragma push_macro( "local_persist" ) - # define global global - # define internal internal - # define local_persist local_persist + # undef global + # undef internal + # undef local_persist # define Entry( Spec_, Code_ ) { sizeof(stringize(Code_)), stringize(Code_) }, Define_Specifiers @@ -348,7 +348,7 @@ namespace Attribute constexpr char const* API_Import = stringize( GEN_API_Import_Code ); constexpr char const* Keyword = stringize( GEN_Attribute_Keyword); -#elif GEN_HAS_ATTRIBUTE( visibility ) || GEN_GCC_VERSION_CHECK( 3, 3, 0 ) || GEN_INTEL_VERSION_CHECK( 13, 0, 0 ) +#elif GEN_HAS_ATTRIBUTE( visibility ) || GEN_GCC_VERSION_CHECK( 3, 3, 0 ) # define GEN_API_Export_Code __attribute__ ((visibility ("default"))) # define GEN_API_Import_Code __attribute__ ((visibility ("default"))) # define GEN_Attribute_Keyword __attribute__ @@ -1244,7 +1244,7 @@ static_assert( sizeof(AST_Type) == sizeof(AST), "ERROR: AST_Type is not the same struct AST_Typedef { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ]; + char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ]; struct { CodeAttributes Attributes; @@ -1253,13 +1253,13 @@ struct AST_Typedef char _PAD_PROPERTIES_[ sizeof(AST*) * 2 ]; }; }; - Code Prev; - Code Next; - Code Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - char _PAD_UNUSED_[ sizeof(u32) ]; + Code Prev; + Code Next; + Code Parent; + StringCached Name; + CodeT Type; + ModuleFlag ModuleFlags; + char _PAD_UNUSED_[ sizeof(u32) ]; }; static_assert( sizeof(AST_Typedef) == sizeof(AST), "ERROR: AST_Typedef is not the same size as AST"); diff --git a/project/gen.scanner.hpp b/project/gen.scanner.hpp index c89c747..6b7c0f0 100644 --- a/project/gen.scanner.hpp +++ b/project/gen.scanner.hpp @@ -29,15 +29,16 @@ struct Scanner static void set_allocator( AllocatorInfo allocator ); - Array(FileInfo) Files; + Array Files; String Buffer; - Array(RequestEntry) Requests; + Array Requests; void add_files( s32 num, char const** files ); void add( SymbolInfo signature, Policy policy ); - bool process_requests( Array(Receipt) out_receipts ); + bool process_requests( Array out_receipts ); }; -k + +// namespace gen } \ No newline at end of file