From 9a6deb12cc2fdfc235296ba3701837e1958febc9 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Mon, 1 May 2023 14:12:07 -0400 Subject: [PATCH] More design/major changes Found flaws with design while the parser If I want to support modules I needed to add separaration from the usual specifiers. Same with attributes, decided to minimize my parsing complexity of attributes. Added a banned header (will not have that be there for the release version --- project/Banned.define.hpp | 35 ++ project/Banned.undef.hpp | 35 ++ project/Bloat.hpp | 3 + project/gen.cpp | 909 +++++++++++++++++++++++++++----------- project/gen.hpp | 446 ++++++++++++------- 5 files changed, 1018 insertions(+), 410 deletions(-) create mode 100644 project/Banned.define.hpp create mode 100644 project/Banned.undef.hpp diff --git a/project/Banned.define.hpp b/project/Banned.define.hpp new file mode 100644 index 0000000..62bafd5 --- /dev/null +++ b/project/Banned.define.hpp @@ -0,0 +1,35 @@ +// Standard Allocation +#define new static_assert( false, "Banned keyword used: " new ) +#define delete static_assert( false, "Banned keyword used: " delete ) + +// Standard Coroutines +#define co_await static_assert( false, "Banned keyword used: " co_await ) +#define co_return static_assert( false, "Banned keyword used: " co_return ) +#define co_yield static_assert( false, "Banned keyword used: " co_yield ) + +// Standard Exceptions +#define atomic_cancel static_assert( false, "Banned keyword used: " atomic_cancel ) +#define atomic_commit static_assert( false, "Banned keyword used: " atomic_commit ) +#define atomic_noexcept static_assert( false, "Banned keyword used: " atomic_noexcept ) +#define catch static_assert( false, "Banned keyword used: " catch ) +#define noexcept static_assert( false, "Banned keyword used: " noexcept ) +#define throw static_assert( false, "Banned keyword used: " throw ) +#define try static_assert( false, "Banned keyword used: " try ) + +// Standard RTTI +#define decltype static_assert( false, "Banned keyword used: " decltype ) +#define reflexpr static_assert( false, "Banned keyword used: " reflexpr ) +#define typeid static_assert( false, "Banned keyword used: " typeid ) + +// Object-Oriented Dynamic Dispatch +#define final static_assert( false, "Banned keyword used: " final ) +#define override static_assert( false, "Banned keyword used: " override ) +#define virtual static_assert( false, "Banned keyword used: " virtual ) + +// Private Access Specifier +#define private static_assert( false, "Banned keyword used: " private ) + +// Template Meta-programming +#define concept static_assert( false, "Banned keyword used: " concept ) +#define requires static_assert( false, "Banned keyword used: " requires ) +#define template static_assert( false, "Banned keyword used: " template ) diff --git a/project/Banned.undef.hpp b/project/Banned.undef.hpp new file mode 100644 index 0000000..d7cd0b9 --- /dev/null +++ b/project/Banned.undef.hpp @@ -0,0 +1,35 @@ +// Standard Allocation +#undef new +#undef delete + +// Standard Coroutines +#undef co_await +#undef co_return +#undef co_yield + +// Standard Exceptions +#undef atomic_cancel +#undef atomic_commit +#undef atomic_noexcept +#undef catch +#undef noexcept +#undef throw +#undef try + +// Standard RTTI +#undef decltype +#undef reflexpr +#undef typeid + +// Object-Oriented Dynamic Dispatch +#undef final +#undef override +#undef virtual + +// Private Access Specifier +#undef private + +// Template Meta-programming +#undef concept +#undef requires +#undef template diff --git a/project/Bloat.hpp b/project/Bloat.hpp index 320af7f..378cd8b 100644 --- a/project/Bloat.hpp +++ b/project/Bloat.hpp @@ -105,6 +105,9 @@ using zpl::str_len; #endif +#include "Banned.define.hpp" + + #if defined(__GNUC__) || defined(__clang__) // Supports 0-10 arguments #define macro_num_args_impl( _0, \ diff --git a/project/gen.cpp b/project/gen.cpp index eac5995..77805bd 100644 --- a/project/gen.cpp +++ b/project/gen.cpp @@ -63,6 +63,7 @@ namespace gen #pragma region AST Body Case Macros # define AST_BODY_CLASS_UNALLOWED_TYPES \ + case Attributes: \ case Class_Body: \ case Enum_Body: \ case Extern_Linkage: \ @@ -83,6 +84,7 @@ namespace gen case Access_Public: \ case Access_Protected: \ case Access_Private: \ + case Attributes: \ case Class_Body: \ case Enum_Body: \ case Extern_Linkage: \ @@ -105,6 +107,7 @@ namespace gen case Access_Public: \ case Access_Protected: \ case Access_Private: \ + case Attributes: \ case Class_Body: \ case Enum_Body: \ case Execution: \ @@ -119,57 +122,11 @@ namespace gen case Struct_Body: \ case Typename: -# define AST_BODY_NAMESPACE_UNALLOWED_TYPES \ - case Access_Public: \ - case Access_Protected: \ - case Access_Private: \ - case Class_Body: \ - case Enum_Body: \ - case Execution: \ - case Friend: \ - case Function_Body: \ - case Global_Body: \ - case Namespace_Body: \ - case Operator_Member: \ - case Operator_Member_Fwd: \ - case Parameters: \ - case Specifiers: \ - case Struct_Body: \ - case Typename: +# define AST_BODY_EXPORT_UNALLOWED_TYPES AST_BODY_GLOBAL_UNALLOWED_TYPES +# define AST_BODY_NAMESPACE_UNALLOWED_TYPES AST_BODY_GLOBAL_UNALLOWED_TYPES +# define AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES AST_BODY_GLOBAL_UNALLOWED_TYPES -# define AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES \ - case Access_Public: \ - case Access_Protected: \ - case Access_Private: \ - case Class_Body: \ - case Enum_Body: \ - case Execution: \ - case Friend: \ - case Function_Body: \ - case Global_Body: \ - case Namespace_Body: \ - case Operator_Member: \ - case Operator_Member_Fwd: \ - case Parameters: \ - case Specifiers: \ - case Struct_Body: \ - case Typename: - -# define AST_BODY_STRUCT_UNALLOWED_TYPES \ - case Enum_Body: \ - case Extern_Linkage: \ - case Execution: \ - case Function_Body: \ - case Global_Body: \ - case Namespace: \ - case Namespace_Body: \ - case Operator: \ - case Operator_Fwd: \ - case Parameters: \ - case Specifiers: \ - case Struct_Body: \ - case Typename: \ - case Using_Namespace: +# define AST_BODY_STRUCT_UNALLOWED_TYPES AST_BODY_CLASS_UNALLOWED_TYPES #pragma endregion AST Body Case Macros #pragma region AST @@ -202,16 +159,24 @@ namespace gen log_failure( "AST::add: Cannot add an AST to an untyped AST." ); return false; - case Access_Public: - log_failure( "AST::add: Cannot add an AST to a public access specifier." ); + case Comment: + log_failure( "AST::add: Cannot add an AST to a comment." ); + return false; + + case Access_Private: + log_failure( "AST::add: Cannot add an AST to a private access specifier." ); return false; case Access_Protected: log_failure( "AST::add: Cannot add an AST to a protected access specifier." ); return false; - case Access_Private: - log_failure( "AST::add: Cannot add an AST to a private access specifier." ); + case Access_Public: + log_failure( "AST::add: Cannot add an AST to a public access specifier." ); + return false; + + case Attributes: + log_failure( "AST::add: Cannot add an AST to an attribute." ); return false; case Class: @@ -244,6 +209,33 @@ namespace gen log_failure( "AST::add: Cannot add an AST to an enum forward declaration." ); return false; + case Enum_Body: + if ( other->Type != Untyped ) + { + log_failure( "AST::add: Cannot add an AST which is not untyped to an enum body." ); + return false; + } + break; + + case Execution: + log_failure( "AST::add: Cannot add an AST to an execution block." ); + return false; + break; + + case Export_Body: + switch ( other->Type ) + { + AST_BODY_EXPORT_UNALLOWED_TYPES + { + log_failure( "AST::add: Cannot add %s to an export body.", other->type_str() ); + return false; + } + + default: + break; + } + break; + case Extern_Linkage: log_failure( "AST::add: Cannot add an AST to an extern linkage, only to its body." ); return false; @@ -261,14 +253,6 @@ namespace gen break; } - case Enum_Body: - if ( other->Type != Untyped ) - { - log_failure( "AST::add: Cannot add an AST which is not untyped to an enum body." ); - return false; - } - break; - case Enum_Class: log_failure( "AST::add: Cannot add an AST to an enum class, only to its body" ); return false; @@ -317,6 +301,10 @@ namespace gen } break; + case Module: + log_failure( "AST::add: Cannot add an AST to a module, only to its body" ); + return false; + case Namespace: if ( Type != Global_Body ) { @@ -350,6 +338,10 @@ namespace gen log_failure( "AST::add: Cannot add to a parameter list, use AST::add_param instead" ); return false; + case Preprocessor_Include: + log_failure( "AST::add: Cannot add an AST to a preprocessor include." ); + return false; + case Specifiers: log_failure( "AST::add: Cannot add to a specifier, use AST::add_specifier instead." ); return false; @@ -384,9 +376,24 @@ namespace gen log_failure( "AST::add: Cannot add to a typename." ); return false; + case Union: + log_failure( "AST::add: Cannot add to a union, only to its body." ); + return false; + + case Union_Body: + if ( other->Type != Untyped ) + { + log_failure( "AST::add: Cannot add an AST which is not untyped to a union body." ); + return false; + } + case Using: log_failure( "AST::add: Cannot add to a using statement." ); return false; + + case Using_Namespace: + log_failure( "AST::add: Cannot add to a using namespace statement." ); + return false; } array_append( Entries, other ); @@ -407,7 +414,6 @@ namespace gen result = make_code(); result->Parent = Parent; result->Name = Name; - result->Comment = Comment; result->Type = Type; result->Op = Op; result->Readonly = Readonly; @@ -418,9 +424,13 @@ namespace gen break; case Untyped: + case Comment: + case Preprocessor_Include: case Access_Public: case Access_Protected: case Access_Private: + case Attributes: + case Module: // Can just be the same, as its a cached string. result->Content = Content; return result; @@ -435,6 +445,8 @@ namespace gen case Enum_Body: case Enum_Class: case Enum_Class_Fwd: + case Export_Body: + case Execution: case Extern_Linkage: case Extern_Linkage_Body: case Friend: @@ -456,6 +468,8 @@ namespace gen case Variable: case Typedef: case Typename: + case Union: + case Union_Body: case Using: case Using_Namespace: s32 index = 0; @@ -476,9 +490,6 @@ namespace gen { String result = string_make( g_allocator, "" ); - if ( Comment ) - result = string_append_fmt( result, "// %s\n", Comment ); - switch ( Type ) { using namespace ECode; @@ -491,14 +502,39 @@ namespace gen result = string_append_length( result, Content, string_length( ccast(String, Content)) ); break; - case Access_Public: - case Access_Protected: + case Comment: + { + static char line[MaxCommentLineLength]; + + s32 left = string_length( ccast(String, Content) ); + s32 index = 0; + do + { + s32 length = 0; + while ( left && Content[index] != '\n' ) + length++; + + zpl::str_copy( line, Content, length ); + line[length] = '\0'; + + result = string_append_fmt( result, "// %s\n", line ); + } + while ( left--, left ); + } + break; + case Access_Private: + case Access_Protected: + case Access_Public: result = string_append_length( result, Name, string_length( ccast(String, Name)) ) ; break; + case Attributes: + result = string_append_fmt( result, "%s", Content ); + case Class: { + result = string_append_fmt( result, "class"); s32 idx = 1; @@ -578,6 +614,26 @@ namespace gen result = string_append_fmt( result, "enum class %s : %s;\n", Name, underlying_type()->to_string() ); break; + case Execution: + result = string_append_fmt( result, "%s\n", Entries[0]->to_string() ); + break; + + case Export_Body: + { + result = string_append_fmt( result, "export\n{\n" ); + + s32 index = 0; + s32 left = num_entries(); + while ( left -- ) + { + result = string_append_fmt( result, "%s\n", Entries[index]->to_string() ); + index++; + } + + result = string_append_fmt( result, "};\n" ); + } + break; + case Extern_Linkage: result = string_append_fmt( result, "extern %s\n{\n%s\n};\n", Name, body()->to_string() ); break; @@ -660,6 +716,13 @@ namespace gen } break; + case Module: + // TODO: Add export condition + // if ( ) + + result = string_append_fmt( result, "module %s", Content ); + break; + case Namespace: result = string_append_fmt( result, "namespace %s\n{\n%s\n};\n", Name, body()->to_string() ); break; @@ -733,6 +796,10 @@ namespace gen } break; + case Preprocessor_Include: + result = string_append_fmt( result, "#include %s\n", Name ); + break; + case Specifiers: { s32 idx = 0; @@ -806,6 +873,10 @@ namespace gen result = string_append_fmt( result, "%s %s", Name, Entries[0]->to_string() ); break; + case Union: + result = string_append_fmt( result, "union %s\n{\n%s\n};\n", Name, body()->to_string() ); + break; + case Using: // TODO: Check for array expression @@ -820,7 +891,6 @@ namespace gen result = string_append_fmt( result, "using namespace %s", Name ); break; - case Class_Body: case Enum_Body: case Extern_Linkage_Body: @@ -828,6 +898,7 @@ namespace gen case Global_Body: case Namespace_Body: case Struct_Body: + case Union_Body: { s32 index = 0; s32 left = num_entries(); @@ -1511,7 +1582,43 @@ namespace gen I decided to validate a good protion of their form and thus the argument processing for is quite a bit. */ - Code def_class( s32 length, char const* name, Code parent, Code specifiers, Code body ) + Code def_comment( s32 length, char const* content ) + { + if ( length <= 0 || content == nullptr ) + { + log_failure( "gen::def_comment: Invalid comment provided", length ); + return Code::Invalid; + } + + Code + result = make_code(); + result->Type = ECode::Comment; + result->Name = get_cached_string( content, length ); + result->Content = result->Name; + + result.lock(); + return result; + } + + Code def_attributes( s32 length, char const* content ) + { + if ( length <= 0 || content == nullptr ) + { + log_failure( "gen::def_attributes: Invalid attributes provided", length ); + return Code::Invalid; + } + + Code + result = make_code(); + result->Type = ECode::Attributes; + result->Name = get_cached_string( content, length ); + result->Content = result->Name; + + result.lock(); + return result; + } + + Code def_class( s32 length, char const* name, Code body, Code parent, AccessSpec parent_access, Code specifiers, Code attributes, ModuleFlag mflags ) { using namespace ECode; @@ -1618,27 +1725,25 @@ namespace gen return result; } - Code def_execution( Code untyped_code ) + Code def_execution( s32 length, char const* content ) { - null_check( def_execution, untyped_code ); - - if ( untyped_code->Type != ECode::Untyped ) + if ( length <= 0 || content == nullptr ) { - log_failure( "gen::def_execution: untyped_code is not of untyped type - %s", untyped_code->debug_str() ); + log_failure( "gen::def_execution: Invalid execution provided", length ); return Code::Invalid; } Code - result = make_code(); - result->Type = ECode::Execution; - - result->add_entry( untyped_code ); + result = make_code(); + result->Type = ECode::Execution; + result->Name = get_cached_string( content, length ); + result->Content = result->Name; result.lock(); return result; } - Code def_extern_linkage( s32 length, char const* name, Code body ) + Code def_extern_link( s32 length, char const* name, Code body ) { using namespace ECode; @@ -1767,6 +1872,24 @@ namespace gen return result; } + Code def_include ( s32 length, char const* path ) + { + if ( length <= 0 || path == nullptr ) + { + log_failure( "gen::def_include: Invalid path provided - %d", length ); + return Code::Invalid; + } + + Code + result = make_code(); + result->Type = ECode::Preprocessor_Include; + result->Name = get_cached_string( path, length ); + result->Content = result->Name; + + result.lock(); + return result; + } + Code def_namespace( s32 length, char const* name, Code body ) { using namespace ECode; @@ -1921,46 +2044,6 @@ namespace gen return result; } - Code def_variable( Code type, u32 length, char const* name, Code value, Code specifiers ) - { - name_check( def_variable, length, name ); - null_check( def_variable, type ); - - if ( specifiers && specifiers->Type != ECode::Specifiers ) - { - log_failure( "gen::def_variable: specifiers was not a `Specifiers` type" ); - return Code::Invalid; - } - - if ( type->Type != ECode::Typename ) - { - log_failure( "gen::def_variable: type was not a Typename" ); - return Code::Invalid; - } - - if ( value && value->Type != ECode::Untyped ) - { - log_failure( "gen::def_variable: value was not a `Untyped` type" ); - return Code::Invalid; - } - - Code - result = make_code(); - result->Name = get_cached_string( name, length ); - result->Type = ECode::Variable; - - result->add_entry( type ); - - if ( specifiers ) - result->add_entry( specifiers ); - - if ( value ) - result->add_entry( value ); - - result.lock(); - return result; - } - Code def_typedef( u32 length, char const* name, Code type ) { name_check( def_typedef, length, name ); @@ -2080,6 +2163,46 @@ namespace gen return result; } + Code def_variable( Code type, u32 length, char const* name, Code value, Code specifiers ) + { + name_check( def_variable, length, name ); + null_check( def_variable, type ); + + if ( specifiers && specifiers->Type != ECode::Specifiers ) + { + log_failure( "gen::def_variable: specifiers was not a `Specifiers` type" ); + return Code::Invalid; + } + + if ( type->Type != ECode::Typename ) + { + log_failure( "gen::def_variable: type was not a Typename" ); + return Code::Invalid; + } + + if ( value && value->Type != ECode::Untyped ) + { + log_failure( "gen::def_variable: value was not a `Untyped` type" ); + return Code::Invalid; + } + + Code + result = make_code(); + result->Name = get_cached_string( name, length ); + result->Type = ECode::Variable; + + result->add_entry( type ); + + if ( specifiers ) + result->add_entry( specifiers ); + + if ( value ) + result->add_entry( value ); + + result.lock(); + return result; + } + /* Body related functions typically follow the same implementation pattern. So I opted to use inline helper macros to get the implementaiton done. @@ -2255,7 +2378,42 @@ namespace gen return result; } - Code def_extern_linkage_body( s32 num, ... ) + Code def_export_body( s32 num, ... ) + { + def_body_start( def_export_body ); + + Code + result = make_code(); + result->Type = Export_Body; + + va_list va; + va_start(va, num); + def_body_code_validation_start( def_export_body, va_arg(va, Code) ); + AST_BODY_EXPORT_UNALLOWED_TYPES + def_body_code_validation_end( def_export_body ); + va_end(va); + + result.lock(); + return result; + } + + Code def_export_body( s32 num, Code* codes ) + { + def_body_code_array_start( def_export_body ); + + Code + result = make_code(); + result->Type = Export_Body; + + def_body_code_validation_start( def_export_body, *codes; codes++ ); + AST_BODY_EXPORT_UNALLOWED_TYPES + def_body_code_validation_end( def_export_body ); + + result.lock(); + return result; + } + + Code def_extern_link_body( s32 num, ... ) { def_body_start( def_extern_linkage_body ); @@ -2274,7 +2432,7 @@ namespace gen return result; } - Code def_extern_linkage_body( s32 num, Code* codes ) + Code def_extern_link_body( s32 num, Code* codes ) { def_body_code_array_start( def_extern_linkage_body ); @@ -2695,6 +2853,34 @@ namespace gen return result; } + Code make_export_body( s32 length, char const* name ) + { + using namespace ECode; + + Code + result = make_code(); + result->Type = Export_Body; + + if ( name && length > 0 ) + result->Name = get_cached_string( name, length ); + + return result; + } + + Code make_extern_linkage( s32 length, char const* name ) + { + using namespace ECode; + + name_check( make_extern_linkage, length, name); + + Code + result = make_code(); + result->Type = Extern_Linkage; + result->Name = get_cached_string( name, length ); + + return result; + } + Code make_function( s32 length, char const* name , Code specifiers , Code params @@ -2896,9 +3082,9 @@ namespace gen // Any angle brackets found will be considered an operator token. # define Define_TokType \ - Entry( Access_Public, "public" ) \ - Entry( Access_Protected, "protected" ) \ Entry( Access_Private, "private" ) \ + Entry( Access_Protected, "protected" ) \ + Entry( Access_Public, "public" ) \ Entry( Access_MemberSymbol, "." ) \ Entry( Access_StaticSymbol, "::") \ Entry( Ampersand, "&" ) \ @@ -2916,14 +3102,18 @@ namespace gen Entry( Decl_Class, "class" ) \ Entry( Decl_Enum, "enum" ) \ Entry( Decl_Friend, "friend" ) \ + Entry( Decl_Module, "module" ) \ Entry( Decl_Namespace, "namespace" ) \ Entry( Decl_Struct, "struct" ) \ Entry( Decl_Typedef, "typedef" ) \ Entry( Decl_Using, "using" ) \ Entry( Decl_Union, "union" ) \ Entry( Identifier, "__SymID__" ) \ + Entry( Module_Import, "import" ) \ + Entry( Module_Export, "export" ) \ Entry( Number, "number" ) \ Entry( Operator, "operator" ) \ + Entry( Spec_API_Macro, API_Macro_Code ) \ Entry( Spec_API, txt(API_Keyword) ) \ Entry( Spec_Alignas, "alignas" ) \ Entry( Spec_CLinkage, "extern \"C\"" ) \ @@ -2931,11 +3121,8 @@ namespace gen Entry( Spec_Consteval, "consteval" ) \ Entry( Spec_Constexpr, "constexpr" ) \ Entry( Spec_Constinit, "constinit" ) \ - Entry( Spec_Export, "export" ) \ Entry( Spec_Extern, "extern" ) \ - Entry( Spec_Import, "import" ) \ Entry( Spec_Inline, "inline" ) \ - Entry( Spec_Module, "module" ) \ Entry( Spec_Static, "static" ) \ Entry( Spec_ThreadLocal, "thread_local" ) \ Entry( Spec_Volatile, "volatile") \ @@ -3013,12 +3200,24 @@ namespace gen ; } + inline + bool tok_is_access_specifier( Token const& tok ) + { + return tok.Type >= TokType::Access_Private && tok.Type <= TokType::Access_Public; + } + + inline + AccessSpec tok_to_access_specifier( Token const& tok ) + { + return scast(AccessSpec, tok.Type); + } + Arena LexAllocator; struct TokArray { - s32 Idx; Array(Token) Arr; + s32 Idx; inline bool __eat( TokType type, char const* context ) @@ -3073,7 +3272,7 @@ namespace gen if ( LexAllocator.physical_start == nullptr ) { log_failure( "gen::lex: failed to allocate memory for parsing constructor's lexer"); - return { 0, nullptr }; + return { nullptr, 0 }; } do_once_end @@ -3090,7 +3289,7 @@ namespace gen if ( left <= 0 ) { log_failure( "gen::lex: no tokens found (only whitespace provided)" ); - return { 0, nullptr }; + return { nullptr, 0 }; } if ( Tokens ) @@ -3371,6 +3570,10 @@ namespace gen { token.Type = TokType::Comment; + move_forward(); + token.Text = scanner; + token.Length = 0; + while ( left && current != '\n' ) { move_forward(); @@ -3381,7 +3584,11 @@ namespace gen { token.Type = TokType::Comment; - while ( left && ( current != '*' || *(scanner + 1) != '/' ) ) + move_forward(); + token.Text = scanner; + token.Length = 0; + + while ( left && ( current != '*' && *(scanner + 1) != '/' ) ) { move_forward(); token.Length++; @@ -3459,10 +3666,10 @@ namespace gen if ( array_count(Tokens) == 0 ) { log_failure( "Failed to lex any tokens" ); - return { 0, nullptr }; + return { nullptr, 0 }; } - return { 0, Tokens }; + return { Tokens, 0 }; # undef current # undef move_forward # undef SkipWhitespace @@ -3489,6 +3696,8 @@ namespace gen # define check( Type_ ) left && currtok.Type == Type_ #pragma endregion Helper Macros + Code parse_function_body( Parser::TokArray& toks, char const* context ); + Code parse_class ( Parser::TokArray& toks, char const* context ); Code parse_enum ( Parser::TokArray& toks, char const* context ); Code parse_friend ( Parser::TokArray& toks, char const* context ); @@ -3501,7 +3710,7 @@ namespace gen Code parse_using ( Parser::TokArray& toks, char const* context ); inline - Code parse_array_decl( Parser::TokArray& toks, char const* func_name ) + Code parse_array_decl( Parser::TokArray& toks, char const* context ) { using namespace Parser; @@ -3550,7 +3759,7 @@ namespace gen } inline - Parser::Token parse_identifier( Parser::TokArray& toks, char const* func_name ) + Parser::Token parse_identifier( Parser::TokArray& toks, char const* context ) { using namespace Parser; Token name = currtok; @@ -3563,13 +3772,13 @@ namespace gen if ( left == 0 ) { - log_failure( "%s: Error, unexpected end of type definition, expected identifier", func_name ); + 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", func_name, str_tok_type( currtok.Type ) ); + log_failure( "%s: Error, expected identifier in type definition, not %s", context, str_tok_type( currtok.Type ) ); return { nullptr, 0, TokType::Invalid }; } @@ -3652,6 +3861,43 @@ namespace gen # undef context } + 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" ); + 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.Length, expr_tok.Text ); + } + + return expr; + } + + Code parse_class_struct( Parser::TokType which, Parser::TokArray& toks, char const* context ) + { + using namespace Parser; + + return Code::Invalid; + } + Code parse_class_struct_body( Parser::TokArray& toks, char const* context ) { using namespace Parser; @@ -3670,11 +3916,23 @@ namespace gen switch ( currtok.Type ) { case TokType::Comment: + member = def_comment( currtok.Length, currtok.Text ); + eat( TokType::Comment ); break; case TokType::Access_Public: + member = access_public; + eat( TokType::Access_Public ); + break; + case TokType::Access_Protected: + member = access_protected; + eat( TokType::Access_Protected ); + break; + case TokType::Access_Private: + member = access_private; + eat( TokType::Access_Private ); break; case TokType::Decl_Class: @@ -3705,8 +3963,6 @@ namespace gen member = parse_using( toks, context ); break; - case TokType::Identifier: - case TokType::Spec_Const: case TokType::Spec_Consteval: case TokType::Spec_Constexpr: case TokType::Spec_Constinit: @@ -3714,18 +3970,137 @@ namespace gen case TokType::Spec_Static: case TokType::Spec_ThreadLocal: case TokType::Spec_Volatile: + Code specifiers = Code::Invalid; + + SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; + s32 num_specifiers = 0; + + while ( left && tok_is_specifier( currtok ) ) + { + SpecifierT spec = ESpecifier::to_type( currtok.Text, currtok.Length ); + + switch ( spec ) + { + case ESpecifier::Constexpr: + case ESpecifier::Constinit: + case ESpecifier::Export: + case ESpecifier::External_Linkage: + case ESpecifier::Import: + case ESpecifier::Local_Persist: + case ESpecifier::Mutable: + case ESpecifier::Static_Member: + case ESpecifier::Thread_Local: + case ESpecifier::Volatile: + break; + + default: + log_failure( "gen::parse_variable: invalid specifier " txt(spec) " for variable" ); + return Code::Invalid; + } + + specs_found[num_specifiers] = spec; + num_specifiers++; + eat( currtok.Type ); + } + + if ( num_specifiers ) + { + specifiers = def_specifiers( num_specifiers, specs_found ); + } + + case TokType::Identifier: + case TokType::Spec_Const: case TokType::Type_Unsigned: case TokType::Type_Signed: case TokType::Type_Short: case TokType::Type_Long: - break; + { + Code type = parse_type( toks, context ); + if ( type == Code::Invalid ) + return Code::Invalid; + + Token name = currtok; + + if ( check( TokType::Identifier ) ) + { + name = currtok; + } + + // Parsing a member function + if ( check( TokType::Capture_Start )) + { + Code params = parse_params( toks, context ); + if ( params == Code::Invalid ) + return Code::Invalid; + + if ( check( TokType::BraceCurly_Open ) ) + { + Code body = parse_function_body( toks, context); + if ( body == Code::Invalid ) + return Code::Invalid; + + Code + member = make_code(); + member->Name = get_cached_string( name.Text, name.Length ); + + if ( body ) + { + switch ( body->Type ) + { + case Function_Body: + case Untyped: + break; + + default: + { + log_failure("gen::def_function: body must be either of Function_Body or Untyped type. %s", body->debug_str()); + return Code::Invalid; + } + } + + member->Type = Function; + member->add_entry( body ); + } + else + { + member->Type = Function_Fwd; + } + + member->add_entry( type ); + + if ( params ) + member->add_entry( params ); + + break; + } + } + + // Parsing a member variable + Code array_expr = parse_array_decl( toks, context ); + Code expr = parse_variable_assignment( toks, context ); + + member = make_code(); + member->Type = Variable; + member->Name = get_cached_string( name.Text, name.Length ); + + member->add_entry( type ); + + if (array_expr) + type->add_entry( array_expr ); + + if (specifiers) + member->add_entry( specifiers ); + + if ( expr ) + member->add_entry( expr ); + } + + if ( member == Code::Invalid ) + return Code::Invalid; + + result->add_entry( member ); } - if ( member == Code::Invalid ) - return Code::Invalid; - - result->add_entry( member ); - eat( currtok.Type ); } @@ -3832,28 +4207,98 @@ namespace gen Token name { nullptr, 0, TokType::Invalid }; - Code parent = { nullptr }; - Code speciifes = { nullptr }; - Code body = { nullptr }; + Code parent = { nullptr }; + Code specifiers = { nullptr }; + Code body = { nullptr }; + Code lang_linkage = { nullptr }; Code result = Code::Invalid; + SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; + s32 num_specifiers = 0; + + // Parse module specifiers eat( TokType::Decl_Class ); + // Parse specifiers + while ( left && tok_is_specifier( currtok ) ) + { + SpecifierT spec = ESpecifier::to_type( currtok.Text, currtok.Length ); + + switch ( spec ) + { + case ESpecifier::API_Macro: + case ESpecifier::API_Export: + case ESpecifier::API_Import: + case ESpecifier::External_Linkage: + case ESpecifier::Local_Persist: + case ESpecifier::Mutable: + case ESpecifier::Static_Member: + case ESpecifier::Thread_Local: + case ESpecifier::Volatile: + break; + + default: + log_failure( "gen::parse_variable: invalid specifier " txt(spec) " for variable" ); + return Code::Invalid; + } + + if ( spec == ESpecifier::External_Linkage ) + { + specs_found[num_specifiers] = spec; + num_specifiers++; + eat( TokType::Spec_Extern ); + + if ( currtok.Type == TokType::String ) + { + lang_linkage = untyped_str( currtok.Length, currtok.Text ); + eat( TokType::String ); + } + + continue; + } + + specs_found[num_specifiers] = spec; + num_specifiers++; + eat( currtok.Type ); + } + + if ( num_specifiers ) + { + specifiers = def_specifiers( num_specifiers, specs_found ); + } + + // Parse alignment + + Token name = parse_identifier( toks, context ); + + if ( check( TokType::Assign_Classifer ) ) + { + eat( TokType::Assign_Classifer ); + + AccessSpec access = AccessSpec::Invalid; + + if ( tok_is_access_specifier( currtok ) ) + { + access = tok_to_access_specifier( currtok ); + } + + Token parent_tok = parse_identifier( toks, context ); + } + not_implemented(); } Code parse_class( s32 length, char const* def ) { - # define context txt(parse_class) + check_parse_args( parse_class, length, def ); using namespace Parser; TokArray toks = lex( length, def ); if ( toks.Arr == nullptr ) return Code::Invalid; - return parse_class( toks, context ); - # undef context + return parse_class( toks, txt(parse_class) ); } Code parse_enum( Parser::TokArray& toks, char const* context ) @@ -3882,6 +4327,8 @@ namespace gen is_enum_class = true; } + // TODO: Parse attributes + if ( currtok.Type != TokType::Identifier ) { log_failure( "gen::parse_enum: expected identifier for enum name" ); @@ -3950,17 +4397,38 @@ namespace gen Code parse_enum( s32 length, char const* def ) { - using namespace Parser; - - # define context parse_enum check_parse_args( parse_enum, length, def ); + using namespace Parser; TokArray toks = lex( length, def ); if ( toks.Arr == nullptr ) return Code::Invalid; return parse_enum( toks, txt(parse_enum) ); - # undef context + } + + Code parse_export_body( Parser::TokArray& toks, char const* context ) + { + not_implemented(); + return Code::Invalid; + } + + Code parse_export_body( s32 length, char const* def ) + { + not_implemented(); + return Code::Invalid; + } + + Code parse_extern_link( Parser::TokArray& toks, char const* context ) + { + not_implemented(); + return Code::Invalid; + } + + Code parse_extern_link( s32 length, char const* def ) + { + not_implemented(); + return Code::Invalid; } Code parse_friend( Parser::TokArray& toks, char const* context ) @@ -4015,11 +4483,8 @@ namespace gen Code parse_friend( s32 length, char const* def ) { - using namespace Parser; - using namespace ECode; - -# define context parse_friend check_parse_args( parse_friend, length, def ); + using namespace Parser; TokArray toks = lex( length, def ); if ( toks.Arr == nullptr ) @@ -4041,10 +4506,10 @@ namespace gen Code result = make_code(); result->Type = Global_Body; - while ( left ) - { + // while ( left ) + // { - } + // } result.lock(); return result; @@ -4064,16 +4529,21 @@ namespace gen Code array_expr = Code::Invalid; Code specifiers = Code::Invalid; + // TODO: Parse module specifiers + + // TODO: Parse attributes + while ( left && tok_is_specifier( currtok ) ) { SpecifierT spec = ESpecifier::to_type( currtok.Text, currtok.Length ); switch ( spec ) { + case ESpecifier::API_Macro: + case ESpecifier::API_Export: + case ESpecifier::API_Import: case ESpecifier::Constexpr: - case ESpecifier::Export: case ESpecifier::External_Linkage: - case ESpecifier::Import: case ESpecifier::Local_Persist: case ESpecifier::Mutable: case ESpecifier::Static_Member: @@ -4238,6 +4708,20 @@ namespace gen return Code::Invalid; } + Code parse_union( Parser::TokArray& toks, char const* context ) + { + using namespace Parser; + + not_implemented(); + + return Code::Invalid; + } + + Code parse_union( s32 length, char const* def ) + { + not_implemented( parse_union ); + } + Code parse_variable( Parser::TokArray& toks, char const* context ) { using namespace Parser; @@ -4252,6 +4736,9 @@ namespace gen Code array_expr = Code::Invalid; Code specifiers = Code::Invalid; + // TODO: Parse module specifiers + + // TODO: Parse attributes if ( check( TokType::BraceSquare_Open ) ) { eat( TokType::BraceSquare_Open ); @@ -4280,9 +4767,7 @@ namespace gen { case ESpecifier::Constexpr: case ESpecifier::Constinit: - case ESpecifier::Export: case ESpecifier::External_Linkage: - case ESpecifier::Import: case ESpecifier::Local_Persist: case ESpecifier::Mutable: case ESpecifier::Static_Member: @@ -4334,6 +4819,8 @@ namespace gen name = currtok; eat( TokType::Identifier ); + array_expr = parse_array_decl( toks, txt(parse_variable) ); + Code expr = Code::Invalid; if ( currtok.IsAssign ) @@ -4357,8 +4844,6 @@ namespace gen expr = untyped_str( expr_tok.Length, expr_tok.Text ); } - array_expr = parse_array_decl( toks, txt(parse_variable) ); - eat( TokType::Statement_End ); using namespace ECode; @@ -4387,25 +4872,20 @@ namespace gen Code parse_variable( s32 length, char const* def ) { - # define context txt(parse_variable) - using namespace Parser; - check_parse_args( parse_variable, length, def ); + using namespace Parser; TokArray toks = lex( length, def ); if ( toks.Arr == nullptr ) return Code::Invalid; return parse_variable( toks, txt(parse_variable) ); - # undef context } - Code parse_type( Parser::TokArray& toks, char const* func_name ) + Code parse_type( Parser::TokArray& toks, char const* context ) { using namespace Parser; - # define context parse_type - SpecifierT specs_found[16] { ESpecifier::Num_Specifiers }; s32 num_specifiers = 0; @@ -4429,7 +4909,7 @@ namespace gen if ( left == 0 ) { - log_failure( "%s: Error, unexpected end of type definition", func_name ); + log_failure( "%s: Error, unexpected end of type definition", context ); return Code::Invalid; } @@ -4444,7 +4924,7 @@ namespace gen } else { - name = parse_identifier( toks, func_name ); + name = parse_identifier( toks, context ); if ( ! name ) return Code::Invalid; } @@ -4459,7 +4939,7 @@ namespace gen && spec != ESpecifier::RValue && spec < ESpecifier::Type_Signed ) { - log_failure( "%s: Error, invalid specifier used in type definition: %s", func_name, currtok.Text ); + log_failure( "%s: Error, invalid specifier used in type definition: %s", context, currtok.Text ); return Code::Invalid; } @@ -4485,15 +4965,12 @@ namespace gen } return result; - # undef context } Code parse_type( s32 length, char const* def ) { - using namespace Parser; - - # define context parse_type check_parse_args( parse_type, length, def ); + using namespace Parser; TokArray toks = lex( length, def ); if ( toks.Arr == nullptr ) @@ -4503,7 +4980,6 @@ namespace gen result.lock(); return result; - # undef context } Code parse_typedef( Parser::TokArray& toks, char const* context ) @@ -4549,17 +5025,14 @@ namespace gen Code parse_typedef( s32 length, char const* def ) { - using namespace Parser; - - # define context parse_typedef check_parse_args( parse_typedef, length, def ); + using namespace Parser; TokArray toks = lex( length, def ); if ( toks.Arr == nullptr ) return Code::Invalid; return parse_typedef( toks, txt(parse_typedef) ); - # undef context } Code parse_union( Parser::TokArray& toks, char const* context ) @@ -4597,6 +5070,8 @@ namespace gen eat( TokType::Decl_Namespace ); } + // TODO: Parse Attributes + eat( TokType::Identifier ); if ( currtok.IsAssign ) @@ -4628,72 +5103,14 @@ namespace gen Code parse_using( s32 length, char const* def ) { - # define context parse_using - using namespace Parser; - check_parse_args( parse_using, length, def ); + using namespace Parser; TokArray toks = lex( length, def ); if ( toks.Arr == nullptr ) return Code::Invalid; return parse_using( toks, txt(parse_using) ); - # undef context - } - - s32 parse_classes( s32 length, char const* class_defs, Code* out_class_codes ) - { - not_implemented( parse_classes ); - } - - s32 parse_enums( s32 length, char const* enum_defs, Code* out_enum_codes ) - { - not_implemented( parse_enums ); - } - - s32 parse_friends( s32 length, char const* friend_defs, Code* out_friend_codes ) - { - not_implemented( parse_friends ); - } - - s32 parse_functions ( s32 length, char const* fn_defs, Code* out_fn_codes ) - { - not_implemented( parse_functions ); - } - - s32 parse_namespaces( s32 length, char const* namespace_defs, Code* out_namespaces_codes ) - { - not_implemented( parse_namespaces ); - } - - s32 parse_operators( s32 length, char const* operator_defs, Code* out_operator_codes ) - { - not_implemented( parse_operators ); - } - - s32 parse_structs( s32 length, char const* struct_defs, Code* out_struct_codes ) - { - not_implemented( parse_structs ); - } - - s32 parse_variables( s32 length, char const* vars_def, Code* out_var_codes ) - { - not_implemented( parse_variables ); - } - - s32 parse_typedefs( s32 length, char const* typedef_def, Code* out_typedef_codes ) - { - not_implemented( parse_typedefs ); - } - - s32 parse_unions( s32 length, char const* union_defs, Code* out_union_codes ) - { - not_implemented( parse_unions ); - } - - s32 parse_usings( s32 length, char const* usings_def, Code* out_using_codes ) - { - not_implemented( parse_usings ); } // Undef helper macros diff --git a/project/gen.hpp b/project/gen.hpp index 7daa5b9..21e5b77 100644 --- a/project/gen.hpp +++ b/project/gen.hpp @@ -37,45 +37,50 @@ namespace gen namespace ECode { - # define Define_Types \ - Entry( Untyped ) \ - Entry( Access_Public ) \ - Entry( Access_Protected ) \ - Entry( Access_Private ) \ - Entry( Class ) \ - Entry( Class_Fwd ) \ - Entry( Class_Body ) \ - Entry( Enum ) \ - Entry( Enum_Fwd ) \ - Entry( Enum_Body ) \ - Entry( Enum_Class ) \ - Entry( Enum_Class_Fwd ) \ - Entry( Execution ) \ - Entry( Extern_Linkage ) \ - Entry( Extern_Linkage_Body ) \ - Entry( Friend ) \ - Entry( Function ) \ - Entry( Function_Fwd ) \ - Entry( Function_Body ) \ - Entry( Global_Body ) \ - Entry( Namespace ) \ - Entry( Namespace_Body ) \ - Entry( Operator ) \ - Entry( Operator_Fwd ) \ - Entry( Operator_Member ) \ - Entry( Operator_Member_Fwd ) \ - Entry( Parameters ) \ - Entry( Specifiers ) \ - Entry( Struct ) \ - Entry( Struct_Fwd ) \ - Entry( Struct_Body ) \ - Entry( Variable ) \ - Entry( Typedef ) \ - Entry( Typename ) \ - Entry( Union ) \ - Entry( Union_Fwd ) \ - Entry( Union_Body) \ - Entry( Using ) \ + # define Define_Types \ + Entry( Untyped ) \ + Entry( Comment ) \ + Entry( Access_Private ) \ + Entry( Access_Protected ) \ + Entry( Access_Public ) \ + Entry( Attributes ) \ + Entry( Class ) \ + Entry( Class_Fwd ) \ + Entry( Class_Body ) \ + Entry( Enum ) \ + Entry( Enum_Fwd ) \ + Entry( Enum_Body ) \ + Entry( Enum_Class ) \ + Entry( Enum_Class_Fwd ) \ + Entry( Execution ) \ + Entry( Export_Body ) \ + Entry( Extern_Linkage ) \ + Entry( Extern_Linkage_Body ) \ + Entry( Friend ) \ + Entry( Function ) \ + Entry( Function_Fwd ) \ + Entry( Function_Body ) \ + Entry( Global_Body ) \ + Entry( Module ) \ + Entry( Namespace ) \ + Entry( Namespace_Body ) \ + Entry( Operator ) \ + Entry( Operator_Fwd ) \ + Entry( Operator_Member ) \ + Entry( Operator_Member_Fwd ) \ + Entry( Parameters ) \ + Entry( Preprocessor_Include ) \ + Entry( Specifiers ) \ + Entry( Struct ) \ + Entry( Struct_Fwd ) \ + Entry( Struct_Body ) \ + Entry( Variable ) \ + Entry( Typedef ) \ + Entry( Typename ) \ + Entry( Union ) \ + Entry( Union_Fwd ) \ + Entry( Union_Body) \ + Entry( Using ) \ Entry( Using_Namespace ) enum Type : u32 @@ -101,7 +106,7 @@ namespace gen return lookup[ type ]; } - #undef Define_Types + # undef Define_Types } using CodeT = ECode::Type; @@ -197,38 +202,27 @@ namespace gen return lookup[ op ]; } - #undef Define_Operators + # undef Define_Operators } using OperatorT = EOperator::Type; namespace ESpecifier { - #if defined(ZPL_SYSTEM_WINDOWS) - # define API_Export_Code __declspec(dllexport) - # define API_Import_Code __declspec(dllimport) - # define API_Keyword __declspec - #elif defined(ZPL_SYSTEM_MACOS) - # define API_Export_Code __attribute__ ((visibility ("default"))) - # define API_Import_Code __attribute__ ((visibility ("default"))) - # define API_Keyword __attribute__ - #endif + /* + Note: The following are handled separately: + attributes + alignas + */ #define Define_Specifiers \ - Entry( API_Import, API_Export_Code ) \ - Entry( API_Export, API_Import_Code ) \ - Entry( Alignas, alignas ) \ - Entry( Array_Decl, "You cannot stringize an array declare this way" ) \ Entry( Const, const ) \ Entry( Consteval, consteval ) \ Entry( Constexpr, constexpr ) \ Entry( Constinit, constinit ) \ - Entry( Export, export ) \ Entry( External_Linkage, extern ) \ - Entry( Import, import ) \ Entry( Inline, inline ) \ Entry( Internal_Linkage, static ) \ Entry( Local_Persist, static ) \ - Entry( Module, module ) \ Entry( Mutable, mutable ) \ Entry( Ptr, * ) \ Entry( Ref, & ) \ @@ -295,6 +289,78 @@ namespace gen } using SpecifierT = ESpecifier::Type; + enum class AccessSpec : u32 + { + Public, + Protected, + Private, + + Num_AccessSpec, + Invalid, + }; + + inline + char const* to_str( AccessSpec type ) + { + local_persist + char const* lookup[ (u32)AccessSpec::Num_AccessSpec ] = { + "private", + "protected", + "public", + }; + + if ( type > AccessSpec::Public ) + return lookup[ (u32)AccessSpec::Invalid ]; + + return lookup[ (u32)type ]; + } + + enum class ModuleFlag : u32 + { + None = 0, + Export = bit(0), + Import = bit(1), + Private = bit(2), + + Num_ModuleFlags, + Invalid, + }; + + /* + Predefined attributes + + Used for the parser constructors to identify non-standard attributes + */ + namespace Attribute + { + #if 0 && defined(ZPL_SYSTEM_WINDOWS) || defined( __CYGWIN__ ) + # define GEN_API_ + # define GEN_API_Export_Code __declspec(dllexport) + # define GEN_API_Import_Code __declspec(dllimport) + # define GEN_Attribute_Keyword __declspec + + constexpr char const* API_Export = txt( GEN_API_Export_Code ); + constexpr char const* API_Import = txt( GEN_API_Import_Code ); + + #elif ZPL_HAS_ATTRIBUTE( visibility ) || ZPL_GCC_VERSION_CHECK( 3, 3, 0 ) || ZPL_INTEL_VERSION_CHECK( 13, 0, 0 ) + # define GEN_API_Export_Code __attribute__ ((visibility ("default"))) + # define GEN_API_Import_Code __attribute__ ((visibility ("default"))) + # define GEN_Attribute_Keyword __attribute__ + + constexpr char const* API_Export = txt( GEN_API_Export_Code ); + constexpr char const* API_Import = txt( GEN_API_Import_Code ); + + #else + # define GEN_API_Export_Code + # define GEN_API_Import_Code + # define GEN_Attribute_Keyword + + constexpr char const* API_Export = ""; + constexpr char const* API_Import = ""; + constexpr char const* Attribute_Keyword = ""; + #endif + } + #pragma region Data Structures // Implements basic string interning. Data structure is based off the ZPL Hashtable. ZPL_TABLE_DECLARE( ZPL_EXTERN, StringTable, str_tbl_, String ); @@ -326,7 +392,7 @@ namespace gen void add_entry( AST* other ); - forceinline + inline AST* body() { return Entries[0]; @@ -334,19 +400,19 @@ namespace gen AST* duplicate(); - forceinline + inline bool has_entries() { return Entries[0]; } - forceinline + inline bool is_invalid() { return Type != ECode::Invalid; } - forceinline + inline s32 num_entries() { return DynamicEntries ? array_count(Entries) : StaticIndex; @@ -354,7 +420,7 @@ namespace gen // Class/Struct - forceinline + inline AST* parent() { return Entries[1]; @@ -362,7 +428,7 @@ namespace gen // Enum - forceinline + inline AST* underlying_type() { return Entries[1]; @@ -372,7 +438,7 @@ namespace gen bool add_param( AST* type, s32 length, char const* name ); - forceinline + inline AST* get_param( s32 index ) { if ( index <= 0 ) @@ -381,14 +447,14 @@ namespace gen return Entries[ index + 1 ]; } - forceinline + inline s32 param_count() { // The first entry (which holds the type) represents the first parameter. return num_entries(); } - forceinline + inline AST* param_type() { return Entries[0]; @@ -411,32 +477,32 @@ namespace gen } inline - bool has_specifier( SpecifierT spec ) + s32 has_specifier( SpecifierT spec ) { - for ( s32 Index = 0; Index < StaticIndex; Index++ ) + for ( s32 idx = 0; idx < StaticIndex; idx++ ) { if ( ArrSpecs[StaticIndex] == spec ) - return true; + return idx; } - return false; + return -1; } // Typename - forceinline + inline bool typename_is_ptr() { assert_crash("not implemented"); } - forceinline + inline bool typename_is_ref() { assert_crash("not implemented"); } - forceinline + inline AST* typename_specifiers() { return Entries[0]; @@ -444,7 +510,7 @@ namespace gen // Serialization - forceinline + inline char const* debug_str() { char const* fmt = txt( @@ -469,7 +535,7 @@ namespace gen ); } - forceinline + inline char const* type_str() { return ECode::to_str( Type ); @@ -481,12 +547,14 @@ namespace gen constexpr static uw ArrS_Cap = ( AST_POD_Size - - sizeof(AST*) - - sizeof(StringCached) * 2 - - sizeof(CodeT) - - sizeof(OperatorT) - - sizeof(bool) * 2 - - sizeof(u8) * 7 ) + - sizeof(AST*) // Parent + - sizeof(StringCached) // Name + - sizeof(CodeT) // Type + - sizeof(OperatorT) // Op + - sizeof(ModuleFlag) // ModuleFlags + - sizeof(u32) // StaticIndex + - sizeof(bool) * 2 // Readonly, DynamicEntries + - sizeof(u8) * 6 ) // _Align_Pad / sizeof(AST*); constexpr static @@ -501,12 +569,12 @@ namespace gen }; \ AST* Parent; \ StringCached Name; \ - StringCached Comment; \ CodeT Type; \ OperatorT Op; \ + ModuleFlag ModuleFlags; \ + u32 StaticIndex; \ bool Readonly; \ bool DynamicEntries; \ - u8 StaticIndex; \ u8 _Align_Pad[6]; Using_Code_POD @@ -537,7 +605,7 @@ namespace gen struct Code { #pragma region Statics - // Used internally for the most part to identify invaidly generated code. + // Used to identify invalid generated code. static Code Invalid; #pragma endregion Statics @@ -574,43 +642,43 @@ namespace gen return * (Code*)( ast->body() ); } - forceinline + inline void lock() { ast->Readonly = true; } - forceinline + inline char const* to_string() { return ast->to_string(); } - forceinline + inline operator bool() { return ast; } - forceinline + inline bool operator ==( Code other ) { return ast == other.ast; } - forceinline + inline bool operator !=( Code other ) { return ast != other.ast; } - forceinline + inline operator AST*() { return ast; } - forceinline + inline Code& operator=( Code other ) { if ( ast == nullptr ) @@ -632,7 +700,7 @@ namespace gen return *this; } - forceinline + inline AST* operator->() { if ( ast == nullptr ) @@ -710,63 +778,120 @@ namespace gen void set_allocator_type_table ( AllocatorInfo type_reg_allocator ); # pragma region Upfront - Code def_class ( s32 length, char const* name, Code parent = NoCode, Code specifiers = NoCode, Code body = NoCode ); - Code def_enum ( s32 length, char const* name, Code type = NoCode, EnumT specifier = EnumRegular, Code body = NoCode ); + Code def_comment ( s32 length, char const* content ); + Code def_attributes( s32 length, char const* content ); - Code def_execution ( Code untyped_code ); + Code def_class( s32 length, char const* name + , Code body = NoCode + , Code parent = NoCode, AccessSpec access = AccessSpec::Public + , Code specifiers = NoCode, Code attributes = NoCode + , ModuleFlag mflags = ModuleFlag::None ); - Code def_friend ( Code symbol ); - Code def_function ( s32 length, char const* name, Code params = NoCode, Code ret_type = NoCode, Code specifiers = NoCode, Code body = NoCode ); - Code def_extern_linkage ( s32 length, char const* name, Code body ); - Code def_namespace ( s32 length, char const* name, Code body ); - Code def_operator ( OperatorT op, Code params = NoCode, Code ret_type = NoCode, Code specifiers = NoCode, Code body = NoCode ); + Code def_enum( s32 length, char const* name + , Code body = NoCode, Code type = NoCode + , EnumT specifier = EnumRegular, Code attributes = NoCode + , ModuleFlag mflags = ModuleFlag::None ); - Code def_param ( Code type, s32 length, char const* name, Code value = NoCode ); + Code def_execution ( s32 length, char const* content ); + Code def_extern_link( s32 length, char const* name, Code body, ModuleFlag mflags = ModuleFlag::None ); + Code def_friend ( Code symbol ); - Code def_specifier ( SpecifierT specifier ); + Code def_function( s32 length, char const* name + , Code params = NoCode, Code ret_type = NoCode, Code body = NoCode + , Code specifiers = NoCode, Code attributes = NoCode + , ModuleFlag mflags = ModuleFlag::None ); - Code def_struct ( s32 length, char const* name, Code parent = NoCode, Code specifiers = NoCode, Code body = NoCode ); - Code def_typedef ( s32 length, char const* name, Code type ); - Code def_type ( s32 length, char const* name, Code specifiers = NoCode, Code ArrayExpr = NoCode ); - Code def_union ( s32 length, char const* name, Code body = NoCode ); - Code def_using ( s32 length, char const* name, Code type = NoCode, UsingT specifier = UsingRegular ); + Code def_include ( s32 length, char const* path ); + Code def_module ( s32 length, char const* name, ModuleFlag mflags = ModuleFlag::None ); + Code def_namespace( s32 length, char const* name, Code body, ModuleFlag mflags = ModuleFlag::None ); - Code def_variable ( Code type, s32 length, char const* name, Code value = NoCode, Code specifiers = NoCode ); + Code def_operator( OperatorT op + , Code params = NoCode, Code ret_type = NoCode, Code body = NoCode + , Code specifiers = NoCode, Code attributes = NoCode + , ModuleFlag mflags = ModuleFlag::None ); - Code def_class_body ( s32 num, ... ); - Code def_enum_body ( s32 num, ... ); - Code def_enum_body ( s32 num, Code* codes ); - Code def_extern_linkage_body( s32 num, ... ); - Code def_extern_linkage_body( s32 num, Code* codes ); - Code def_global_body ( s32 num, ... ); - Code def_global_body ( s32 num, Code* codes ); - Code def_function_body ( s32 num, ... ); - Code def_function_body ( s32 num, Code* codes ); - Code def_namespace_body ( s32 num, ... ); - Code def_namespace_body ( s32 num, Code* codes ); - Code def_params ( s32 num, ... ); - Code def_params ( s32 num, Code* params ); - Code def_specifiers ( s32 num , ... ); - Code def_specifiers ( s32 num, SpecifierT* specs ); - Code def_struct_body ( s32 num, ... ); - Code def_struct_body ( s32 num, Code* codes ); - Code def_union_body ( s32 num, ... ); - Code def_union_body ( s32 num, Code* codes ); + Code def_param ( Code type, s32 length, char const* name, Code value = NoCode ); + Code def_specifier( SpecifierT specifier ); + + Code def_struct( s32 length, char const* name + , Code body + , Code parent = NoCode, AccessSpec access + , Code specifiers = NoCode, Code attributes = NoCode + , ModuleFlag mflags = ModuleFlag::None ); + + Code def_typedef( s32 length, char const* name, Code type, Code attributes = NoCode, ModuleFlag mflags = ModuleFlag::None ); + Code def_type ( s32 length, char const* name, Code arrayexpr = NoCode, Code specifiers = NoCode ); + + Code def_union( s32 length, char const* name, Code body = NoCode, Code attributes = NoCode, ModuleFlag mflags = ModuleFlag::None ); + + Code def_using( s32 length, char const* name, UsingT specifier = UsingRegular + , Code type = NoCode + , Code attributess = NoCode + , ModuleFlag mflags = ModuleFlag::None ); + + Code def_variable( Code type, s32 length, char const* name, Code value = NoCode + , Code specifiers = NoCode, Code attributes = NoCode + , ModuleFlag mflags = ModuleFlag::None ); + + Code def_class_body ( s32 num, ... ); + Code def_enum_body ( s32 num, ... ); + Code def_enum_body ( s32 num, Code* codes ); + Code def_extern_link_body( s32 num, ... ); + Code def_extern_link_body( s32 num, Code* codes ); + Code def_export_body ( s32 num, ... ); + Code def_export_body ( s32 num, Code* codes); + Code def_global_body ( s32 num, ... ); + Code def_global_body ( s32 num, Code* codes ); + Code def_function_body ( s32 num, ... ); + Code def_function_body ( s32 num, Code* codes ); + Code def_namespace_body ( s32 num, ... ); + Code def_namespace_body ( s32 num, Code* codes ); + Code def_params ( s32 num, ... ); + Code def_params ( s32 num, Code* params ); + Code def_specifiers ( s32 num , ... ); + Code def_specifiers ( s32 num, SpecifierT* specs ); + Code def_struct_body ( s32 num, ... ); + Code def_struct_body ( s32 num, Code* codes ); + Code def_union_body ( s32 num, ... ); + Code def_union_body ( s32 num, Code* codes ); # pragma endregion Upfront # pragma region Incremental # ifdef GEN_FEATURE_INCREMENTAL - Code make_class ( s32 length, char const* name, Code parent = NoCode, Code specifiers = NoCode ); - Code make_enum ( s32 length, char const* name, Code type = NoCode, EnumT specifier = EnumRegular ); + Code make_class( s32 length, char const* name + , Code parent = NoCode, AccessSpec access = AccessSpec::Public + , Code specifiers = NoCode, Code attributes = NoCode + , ModuleFlag mflags = ModuleFlag::None ); + + Code make_enum( s32 length, char const* name + , Code type = NoCode, EnumT specifier = EnumRegular + , Code attributes = NoCode, ModuleFlag mflags = ModuleFlag::None ); + + Code make_export_body ( s32 length = 1, char const* name = "" ); Code make_extern_linkage( s32 length, char const* name ); - Code make_function ( s32 length, char const* name, Code params = NoCode, Code ret_type = NoCode, Code specifiers = NoCode ); - Code make_global_body ( s32 length = 1, char const* name = "" ); - Code make_namespace ( s32 length, char const* name ); - Code make_operator ( OperatorT op, Code params = NoCode, Code ret_type = NoCode, Code specifiers = NoCode ); - Code make_params (); - Code make_specifiers (); - Code make_struct ( s32 length, char const* name, Code parent = NoCode, Code specifiers = NoCode ); - Code make_union ( s32 length, char const* name ); + + Code make_function( s32 length, char const* name + , Code params = NoCode, Code ret_type = NoCode + , Code specifiers = NoCode, Code attributes = NoCode + , ModuleFlag mflags = ModuleFlag::None ); + + Code make_global_body( s32 length = 1, char const* name = "" ); + Code make_namespace ( s32 length, char const* name ); + + Code make_operator( OperatorT op + , Code params = NoCode, Code ret_type = NoCode + , Code specifiers = NoCode, Code attributes = NoCode + , ModuleFlag mflags = ModuleFlag::None ); + + Code make_params (); + Code make_specifiers(); + + Code make_struct( s32 length, char const* name + , Code parent = NoCode, AccessSpec access + , Code specifiers = NoCode, Code attributes = NoCode + , ModuleFlag mflags = ModuleFlag::None ); + + Code make_union( s32 length, char const* name, Code attributes = NoCode, ModuleFlag mflags = ModuleFlag::None ); # endif # pragma endregion Incremental @@ -774,6 +899,8 @@ namespace gen #ifdef GEN_FEATURE_PARSING Code parse_class ( s32 length, char const* class_def ); Code parse_enum ( s32 length, char const* enum_def ); + Code parse_export_body( s32 length, char const* export_def ); + Code parse_exten_link ( s32 length, char const* exten_link_def); Code parse_friend ( s32 length, char const* friend_def ); Code parse_function ( s32 length, char const* fn_def ); Code parse_global_body( s32 length, char const* body_def ); @@ -785,18 +912,6 @@ namespace gen Code parse_typedef ( s32 length, char const* typedef_def ); Code parse_union ( s32 length, char const* union_def ); Code parse_using ( s32 length, char const* using_def ); - - s32 parse_classes ( s32 length, char const* class_defs, Code* out_class_codes ); - s32 parse_enums ( s32 length, char const* enum_defs, Code* out_enum_codes ); - s32 parse_friends ( s32 length, char const* friend_defs, Code* out_friend_codes ); - s32 parse_functions ( s32 length, char const* fn_defs, Code* out_fn_codes ); - s32 parse_namespaces( s32 length, char const* namespace_defs, Code* out_namespaces_codes ); - s32 parse_operators ( s32 length, char const* operator_defs, Code* out_operator_codes ); - s32 parse_structs ( s32 length, char const* struct_defs, Code* out_struct_codes ); - s32 parse_variables ( s32 length, char const* var_defs, Code* out_var_codes ); - s32 parse_typedefs ( s32 length, char const* typedef_defs, Code* out_typedef_codes ); - s32 parse_unions ( s32 length, char const* union_defs, Code* out_union_codes ); - s32 parse_usings ( s32 length, char const* using_defs, Code* out_using_codes ); #endif #pragma endregion Parsing @@ -833,6 +948,15 @@ namespace gen void write(); }; +#if defined(GEN_FEATURE_EDITOR) || defined(GEN_FEATURE_SCANNER) + struct SymbolInfo + { + StringCached File; + char const* Marker; + Code Signature; + }; +#endif + #ifdef GEN_FEATURE_EDITOR struct Policy { @@ -846,13 +970,6 @@ namespace gen Marker }; - struct SymbolInfo - { - StringCached File; - char const* Marker; - Code Signature; - }; - struct Editor { enum RequestType : u32 @@ -1003,11 +1120,11 @@ namespace gen # define function_2( Name_, Params_ ) gen::def_function( txt_n_len( Name_ ), macro_expand( Params_ ) ) # define function_1( Name_ ) gen::def_function( txt_n_len( Name_ ) ) -# define params_12( T_1, V_1, T_2, V_2, T_3, V_3, T_4, V_4, T_5, V_5, T_6, V_6 ) gen::def_params( 6, type_ns(T_1), txt_n_len( V_1), type_ns(T_2), txt_n_len( V_2), type_ns(T_3), txt_n_len( V_3), type_ns(T_4), txt_n_len( V_4), type_ns(T_5), txt_n_len( V_5), type_ns(T_6), txt_n_len(V_6)) -# define params_10( T_1, V_1, T_2, V_2, T_3, V_3, T_4, V_4, T_5, V_5 ) gen::def_params( 5, type_ns(T_1), txt_n_len( V_1), type_ns(T_2), txt_n_len( V_2), type_ns(T_3), txt_n_len( V_3), type_ns(T_4), txt_n_len( V_4), type_ns(T_5), txt_n_len( V_5)) -# define params_8( T_1, V_1, T_2, V_2, T_3, V_3, T_4, V_4 ) gen::def_params( 4, type_ns(T_1), txt_n_len( V_1), type_ns(T_2), txt_n_len( V_2), type_ns(T_3), txt_n_len( V_3), type_ns(T_4), txt_n_len( V_4) ) -# define params_6( T_1, V_1, T_2, V_2, T_3, V_3 ) gen::def_params( 3, type_ns(T_1), txt_n_len( V_1), type_ns(T_2), txt_n_len( V_2), type_ns(T_3), txt_n_len( V_3)) -# define params_4( T_1, V_1, T_2, V_2 ) gen::def_params( 2, type_ns(T_1), txt_n_len( V_1), type_ns(T_2), txt_n_len( V_2)) +# define params_12( T_1, V_1, T_2, V_2, T_3, V_3, T_4, V_4, T_5, V_5, T_6, V_6 ) gen::def_params( 12, type_ns(T_1), txt_n_len( V_1), type_ns(T_2), txt_n_len( V_2), type_ns(T_3), txt_n_len( V_3), type_ns(T_4), txt_n_len( V_4), type_ns(T_5), txt_n_len( V_5), type_ns(T_6), txt_n_len(V_6)) +# define params_10( T_1, V_1, T_2, V_2, T_3, V_3, T_4, V_4, T_5, V_5 ) gen::def_params( 10, type_ns(T_1), txt_n_len( V_1), type_ns(T_2), txt_n_len( V_2), type_ns(T_3), txt_n_len( V_3), type_ns(T_4), txt_n_len( V_4), type_ns(T_5), txt_n_len( V_5)) +# define params_8( T_1, V_1, T_2, V_2, T_3, V_3, T_4, V_4 ) gen::def_params( 8, type_ns(T_1), txt_n_len( V_1), type_ns(T_2), txt_n_len( V_2), type_ns(T_3), txt_n_len( V_3), type_ns(T_4), txt_n_len( V_4) ) +# define params_6( T_1, V_1, T_2, V_2, T_3, V_3 ) gen::def_params( 6, type_ns(T_1), txt_n_len( V_1), type_ns(T_2), txt_n_len( V_2), type_ns(T_3), txt_n_len( V_3)) +# define params_4( T_1, V_1, T_2, V_2 ) gen::def_params( 4, type_ns(T_1), txt_n_len( V_1), type_ns(T_2), txt_n_len( V_2)) # define params_2( T_1, V_1 ) gen::def_param ( type_ns(T_1), txt_n_len( V_1)) # define params_bad static_assert("params(...): Invalid number of parameters provided.") # define params_11 params_bad @@ -1019,9 +1136,10 @@ namespace gen // Upfront +# define comment( Value_ ) gen::def_comment( sizeof(Value), Value_ ) +# define attribute( Value_ ) gen::def_attribute( txt_n_len(Value_) ) # define class( Name_, ... ) gen::def_class( txt_n_len(Name_), __VA_ARGS__ ) # define enum( Name_, Type_, Body_ ) gen::def_enum ( txt_n_len(Name_), type_ns(Type_), Body_ ) - # define extern_linkage( Name_, Body_ ) gen::def_extern_linkage( txt_n_len(Name_), Body_ ) # define function( ... ) macrofn_polymorphic( function, __VA_ARGS__ ) # define namespace( Name_, Body_ ) gen::def_namespace ( txt_n_len(Name_), Body_ ) @@ -1033,8 +1151,7 @@ namespace gen # define type( Value_, ... ) gen::def_type ( txt_n_len(Value_), __VA_ARGS__ ) # define type_fmt( Fmt_, ... ) gen::def_type ( bprintf( Fmt_, __VA_ARGS__ ) ) # define union( Name_, ... ) gen::def_union ( txt_n_len(Name_), __VA_ARGS__ ) -# define using( Name_, Type_ ) gen::def_using ( txt_n_len(Name_), type_ns(Type_) ) -# define using_namespace( Name_ ) gen::def_using_namespace( txt_n_len(Name_) ) +# define using( Name_, ... ) gen::def_using ( txt_n_len(Name_), __VA_ARGS__ ) # define class_body( ... ) gen::def_class_body ( macro_num_args( __VA_ARGS__ ), __VA_ARGS__ ) # define enum_body( ... ) gen::def_enum_body ( macro_num_args( __VA_ARGS__ ), __VA_ARGS__ ) @@ -1116,6 +1233,7 @@ namespace gen constexpr s32 SizePer_CodeEntriresArena = megabytes(16); constexpr s32 SizePer_StringArena = megabytes(32); + constexpr s32 MaxCommentLineLength = 1024; constexpr s32 MaxNameLength = 128; constexpr s32 MaxUntypedStrLength = kilobytes(640); constexpr s32 StringTable_MaxHashLength = kilobytes(1);