From 5d7dfaf66635d8c3ed10e5aeb23c0b9d29c22214 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Thu, 3 Aug 2023 11:01:43 -0400 Subject: [PATCH] Heavy refactor.. Isolating large macros to their own directory (components/temp). - Plan is to remove them soon with proper generation. Added additional component files, separating the old data_structures header for a set of ast headers. Header_end also had its inlines extracted out. Necessary to complete the macro isolation. ZPL parser dependencies were removed from the core library along with builder, its now generated in bootstrap as pare of making a gen_builder set of files. Singleheader will be changed in next few commits to reflect this as well (By making builder deps and components a conditional option). Tests are most likely all broken for now. --- project/components/ast.cpp | 7 +- project/components/ast.hpp | 577 ++++++++ project/components/ast_case_macros.cpp | 1 + .../{data_structures.hpp => ast_types.hpp} | 592 +-------- project/components/header_end.hpp | 395 +----- project/components/header_start.hpp | 9 + project/components/inlines.hpp | 214 +++ project/components/interface.cpp | 1 + project/components/interface.hpp | 2 + project/components/interface.parsing.cpp | 2 +- project/components/interface.upfront.cpp | 450 +++++-- .../{impl_start.cpp => src_start.cpp} | 1 + project/components/static_data.cpp | 1 + project/components/temp/Readme.md | 8 + project/components/temp/ast_inlines.hpp | 179 +++ project/components/{ => temp}/ecode.hpp | 1 + project/components/{ => temp}/eoperator.hpp | 1 + project/components/{ => temp}/especifier.hpp | 1 + project/components/{ => temp}/etoktype.cpp | 1 + project/components/types.hpp | 9 + project/components/untyped.cpp | 1 + project/dependencies/basic_types.hpp | 1 + project/dependencies/containers.hpp | 1 + project/dependencies/debug.cpp | 1 + project/dependencies/debug.hpp | 3 +- project/dependencies/file_handling.cpp | 1 + project/dependencies/file_handling.hpp | 1 + project/dependencies/hashing.cpp | 1 + project/dependencies/hashing.hpp | 1 + project/dependencies/header_start.hpp | 11 + project/dependencies/macros.hpp | 25 +- project/dependencies/memory.cpp | 1 + project/dependencies/memory.hpp | 1 + project/dependencies/parsing.cpp | 1 + project/dependencies/parsing.hpp | 1 + project/dependencies/printing.cpp | 1 + project/dependencies/printing.hpp | 3 - .../{impl_start.cpp => src_start.cpp} | 1 + project/dependencies/string.cpp | 1 + project/dependencies/string.hpp | 1 + project/dependencies/string_ops.cpp | 1 + project/dependencies/string_ops.hpp | 1 + project/dependencies/timing.cpp | 1 + project/dependencies/timing.hpp | 1 + project/file_processors/builder.cpp | 37 +- project/file_processors/builder.hpp | 5 +- .../scanner.cpp} | 0 project/gen.bootstrap.cpp | 254 ++-- project/gen.cpp | 4 +- project/gen.dep.cpp | 6 +- project/gen.dep.hpp | 12 +- project/gen.hpp | 26 +- project/gen/gen_builder.cpp | 1159 +++++++++++++++++ project/gen/gen_builder.hpp | 448 +++++++ project/helpers/helper.hpp | 31 +- scripts/.clang-format | 23 +- scripts/bootstrap.ci.ps1 | 49 +- scripts/singleheader.ci.ps1 | 41 +- scripts/test.gen_run.ps1 | 2 + singleheader/components/header_start.hpp | 11 +- singleheader/gen.singleheader.cpp | 95 +- test/validate_bootstrap.cpp | 3 + test/validate_singleheader.cpp | 3 + 63 files changed, 3341 insertions(+), 1382 deletions(-) create mode 100644 project/components/ast.hpp rename project/components/{data_structures.hpp => ast_types.hpp} (50%) create mode 100644 project/components/inlines.hpp rename project/components/{impl_start.cpp => src_start.cpp} (99%) create mode 100644 project/components/temp/Readme.md create mode 100644 project/components/temp/ast_inlines.hpp rename project/components/{ => temp}/ecode.hpp (99%) rename project/components/{ => temp}/eoperator.hpp (99%) rename project/components/{ => temp}/especifier.hpp (99%) rename project/components/{ => temp}/etoktype.cpp (99%) rename project/dependencies/{impl_start.cpp => src_start.cpp} (99%) rename project/{components/interface.upfront.bodies.cpp => file_processors/scanner.cpp} (100%) create mode 100644 project/gen/gen_builder.cpp create mode 100644 project/gen/gen_builder.hpp create mode 100644 test/validate_bootstrap.cpp create mode 100644 test/validate_singleheader.cpp diff --git a/project/components/ast.cpp b/project/components/ast.cpp index 8804942..3112994 100644 --- a/project/components/ast.cpp +++ b/project/components/ast.cpp @@ -373,7 +373,7 @@ String AST::to_string() if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export )) result.append( "export " ); - result.append_fmt( "namespace %s\n{\n%s}" + result.append_fmt( "namespace %s\n{\n%s\n}" , Name , Body->to_string() ); @@ -528,7 +528,7 @@ String AST::to_string() break; case Preprocess_Define: - result.append_fmt( "#define %s%s", Name, Content ); + result.append_fmt( "#define %s \\\n%s\n", Name, Content ); break; case Preprocess_If: @@ -544,7 +544,7 @@ String AST::to_string() break; case Preprocess_Include: - result.append_fmt( "#include \"%s\"", Content ); + result.append_fmt( "#include \"%s\"\n", Content ); break; case Preprocess_ElIf: @@ -918,3 +918,4 @@ bool AST::validate_body() } #pragma endregion AST + diff --git a/project/components/ast.hpp b/project/components/ast.hpp new file mode 100644 index 0000000..f4e9fdf --- /dev/null +++ b/project/components/ast.hpp @@ -0,0 +1,577 @@ +struct AST; +struct AST_Body; +struct AST_Attributes; +struct AST_Comment; +struct AST_Class; +struct AST_Define; +struct AST_Enum; +struct AST_Exec; +struct AST_Extern; +struct AST_Include; +struct AST_Friend; +struct AST_Fn; +struct AST_Module; +struct AST_Namespace; +struct AST_Operator; +struct AST_OpCast; +struct AST_Param; +struct AST_Pragma; +struct AST_PreprocessCond; +struct AST_Specifiers; +struct AST_Struct; +struct AST_Template; +struct AST_Type; +struct AST_Typedef; +struct AST_Union; +struct AST_Using; +struct AST_Var; + +struct Code; +struct CodeBody; +// These are to offer ease of use and optionally strong type safety for the AST. +struct CodeAttributes; +struct CodeComment; +struct CodeClass; +struct CodeDefine; +struct CodeEnum; +struct CodeExec; +struct CodeExtern; +struct CodeInclude; +struct CodeFriend; +struct CodeFn; +struct CodeModule; +struct CodeNamespace; +struct CodeOperator; +struct CodeOpCast; +struct CodeParam; +struct CodePreprocessCond; +struct CodePragma; +struct CodeSpecifiers; +struct CodeStruct; +struct CodeTemplate; +struct CodeType; +struct CodeTypedef; +struct CodeUnion; +struct CodeUsing; +struct CodeVar; + +/* + AST* wrapper + - Not constantly have to append the '*' as this is written often.. + - Allows for implicit conversion to any of the ASTs (raw or filtered). +*/ +struct Code +{ +# pragma region Statics + // Used to identify ASTs that should always be duplicated. (Global constant ASTs) + static Code Global; + + // Used to identify invalid generated code. + static Code Invalid; +# pragma endregion Statics + + #define Using_Code( Typename ) \ + char const* debug_str(); \ + Code duplicate(); \ + bool is_equal( Code other ); \ + bool is_valid(); \ + void set_global(); \ + String to_string(); \ + Typename& operator = ( AST* other ); \ + Typename& operator = ( Code other ); \ + bool operator ==( Code other ); \ + bool operator !=( Code other ); \ + operator bool(); + + Using_Code( Code ); + + template< class Type > + Type cast() + { + return * rcast( Type*, this ); + } + + AST* operator ->() + { + return ast; + } + Code& operator ++(); + Code& operator*() + { + return *this; + } + + AST* ast; + +#ifdef GEN_ENFORCE_STRONG_CODE_TYPES +# define operator explicit operator +#endif + operator CodeAttributes() const; + operator CodeComment() const; + operator CodeClass() const; + operator CodeDefine() const; + operator CodeExec() const; + operator CodeEnum() const; + operator CodeExtern() const; + operator CodeInclude() const; + operator CodeFriend() const; + operator CodeFn() const; + operator CodeModule() const; + operator CodeNamespace() const; + operator CodeOperator() const; + operator CodeOpCast() const; + operator CodeParam() const; + operator CodePragma() const; + operator CodePreprocessCond() const; + operator CodeSpecifiers() const; + operator CodeStruct() const; + operator CodeTemplate() const; + operator CodeType() const; + operator CodeTypedef() const; + operator CodeUnion() const; + operator CodeUsing() const; + operator CodeVar() const; + operator CodeBody() const; + #undef operator +}; + +struct Code_POD +{ + AST* ast; +}; + +static_assert( sizeof(Code) == sizeof(Code_POD), "ERROR: Code is not POD" ); + +// Desired width of the AST data structure. +constexpr u32 AST_POD_Size = 128; + +/* + Simple AST POD with functionality to seralize into C++ syntax. +*/ +struct AST +{ +# pragma region Member Functions + void append ( AST* other ); + char const* debug_str (); + AST* duplicate (); + Code& entry ( u32 idx ); + bool has_entries(); + bool is_equal ( AST* other ); + String to_string (); + char const* type_str(); + bool validate_body(); + + template< class Type > + Type cast() + { + return * this; + } + + operator Code(); + operator CodeBody(); + operator CodeAttributes(); + operator CodeComment(); + operator CodeClass(); + operator CodeDefine(); + operator CodeEnum(); + operator CodeExec(); + operator CodeExtern(); + operator CodeInclude(); + operator CodeFriend(); + operator CodeFn(); + operator CodeModule(); + operator CodeNamespace(); + operator CodeOperator(); + operator CodeOpCast(); + operator CodeParam(); + operator CodePragma(); + operator CodePreprocessCond(); + operator CodeSpecifiers(); + operator CodeStruct(); + operator CodeTemplate(); + operator CodeType(); + operator CodeTypedef(); + operator CodeUnion(); + operator CodeUsing(); + operator CodeVar(); +# pragma endregion Member Functions + + constexpr static + uw ArrSpecs_Cap = + ( + AST_POD_Size + - sizeof(AST*) * 3 + - sizeof(StringCached) + - sizeof(CodeT) + - sizeof(ModuleFlag) + - sizeof(s32) + ) + / sizeof(SpecifierT) -1; // -1 for 4 extra bytes + + union { + struct + { + AST* Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable + AST* Specs; // Function, Operator, Type symbol, Variable + union { + AST* ParentType; // Class, Struct + AST* ReturnType; // Function, Operator + AST* UnderlyingType; // Enum, Typedef + AST* ValueType; // Parameter, Variable + }; + union { + AST* Params; // Function, Operator, Template + AST* BitfieldSize; // Varaiable (Class/Struct Data Member) + }; + union { + AST* ArrExpr; // Type Symbol + AST* Body; // Class, Enum, Function, Namespace, Struct, Union + AST* Declaration; // Friend, Template + AST* Value; // Parameter, Variable + }; + }; + StringCached Content; // Attributes, Comment, Execution, Include + SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers + }; + union { + AST* Prev; + AST* Front; + AST* Last; + }; + union { + AST* Next; + AST* Back; + }; + AST* Parent; + StringCached Name; + CodeT Type; + ModuleFlag ModuleFlags; + union { + OperatorT Op; + AccessSpec ParentAccess; + s32 NumEntries; + }; +}; + +struct AST_POD +{ + union { + struct + { + AST* Attributes; // Class, Enum, Function, Struct, Typename, Union, Using, Variable + AST* Specs; // Function, Operator, Type symbol, Variable + union { + AST* ParentType; // Class, Struct + AST* ReturnType; // Function, Operator + AST* UnderlyingType; // Enum, Typedef + AST* ValueType; // Parameter, Variable + }; + union { + AST* Params; // Function, Operator, Template + AST* BitfieldSize; // Varaiable (Class/Struct Data Member) + }; + union { + AST* ArrExpr; // Type Symbol + AST* Body; // Class, Enum, Function, Namespace, Struct, Union + AST* Declaration; // Friend, Template + AST* Value; // Parameter, Variable + }; + }; + StringCached Content; // Attributes, Comment, Execution, Include + SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers + }; + union { + AST* Prev; + AST* Front; + AST* Last; + }; + union { + AST* Next; + AST* Back; + }; + AST* Parent; + StringCached Name; + CodeT Type; + ModuleFlag ModuleFlags; + union { + OperatorT Op; + AccessSpec ParentAccess; + s32 NumEntries; + }; +}; + +// Its intended for the AST to have equivalent size to its POD. +// All extra functionality within the AST namespace should just be syntatic sugar. +static_assert( sizeof(AST) == sizeof(AST_POD), "ERROR: AST IS NOT POD" ); +static_assert( sizeof(AST_POD) == AST_POD_Size, "ERROR: AST POD is not size of AST_POD_Size" ); + +// Used when the its desired when omission is allowed in a definition. +#define NoCode { nullptr } +#define CodeInvalid (* Code::Invalid.ast) // Uses an implicitly overloaded cast from the AST to the desired code type. + +#pragma region Code Types + +struct CodeBody +{ + Using_Code( CodeBody ); + + void append( Code other ) + { + raw()->append( other.ast ); + } + void append( CodeBody body ) + { + for ( Code entry : body ) + { + append( entry ); + } + } + bool has_entries() + { + return rcast( AST*, ast )->has_entries(); + } + AST* raw() + { + return rcast( AST*, ast ); + } + AST_Body* operator->() + { + return ast; + } + operator Code() + { + return * rcast( Code*, this ); + } +#pragma region Iterator + Code begin() + { + if ( ast ) + return { rcast( AST*, ast)->Front }; + + return { nullptr }; + } + Code end() + { + return { rcast(AST*, ast)->Back->Next }; + } +#pragma endregion Iterator + + AST_Body* ast; +}; + +struct CodeClass +{ + Using_Code( CodeClass ); + + void add_interface( CodeType interface ); + + AST* raw() + { + return rcast( AST*, ast ); + } + operator Code() + { + return * rcast( Code*, this ); + } + AST_Class* operator->() + { + if ( ast == nullptr ) + { + log_failure("Attempt to dereference a nullptr"); + return nullptr; + } + return ast; + } + AST_Class* ast; +}; + +struct CodeParam +{ + Using_Code( CodeParam ); + + void append( CodeParam other ); + + CodeParam get( s32 idx ); + bool has_entries(); + AST* raw() + { + return rcast( AST*, ast ); + } + AST_Param* operator->() + { + if ( ast == nullptr ) + { + log_failure("Attempt to dereference a nullptr!"); + return nullptr; + } + return ast; + } + operator Code() + { + return { (AST*)ast }; + } +#pragma region Iterator + CodeParam begin() + { + if ( ast ) + return { ast }; + + return { nullptr }; + } + CodeParam end() + { + return { (AST_Param*) rcast( AST*, ast)->Last }; + } + CodeParam& operator++(); + CodeParam operator*() + { + return * this; + } +#pragma endregion Iterator + + AST_Param* ast; +}; + +struct CodeSpecifiers +{ + Using_Code( CodeSpecifiers ); + + bool append( SpecifierT spec ) + { + if ( ast == nullptr ) + { + log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!"); + return false; + } + + if ( raw()->NumEntries == AST::ArrSpecs_Cap ) + { + log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST::ArrSpecs_Cap ); + return false; + } + + raw()->ArrSpecs[ raw()->NumEntries ] = spec; + raw()->NumEntries++; + return true; + } + s32 has( SpecifierT spec ) + { + for ( s32 idx = 0; idx < raw()->NumEntries; idx++ ) + { + if ( raw()->ArrSpecs[ raw()->NumEntries ] == spec ) + return idx; + } + + return -1; + } + AST* raw() + { + return rcast( AST*, ast ); + } + AST_Specifiers* operator->() + { + if ( ast == nullptr ) + { + log_failure("Attempt to dereference a nullptr!"); + return nullptr; + } + return ast; + } + operator Code() + { + return { (AST*) ast }; + } +#pragma region Iterator + SpecifierT* begin() + { + if ( ast ) + return & raw()->ArrSpecs[0]; + + return nullptr; + } + SpecifierT* end() + { + return raw()->ArrSpecs + raw()->NumEntries; + } +#pragma endregion Iterator + + AST_Specifiers* ast; +}; + +struct CodeStruct +{ + Using_Code( CodeStruct ); + + void add_interface( CodeType interface ); + + AST* raw() + { + return rcast( AST*, ast ); + } + operator Code() + { + return * rcast( Code*, this ); + } + AST_Struct* operator->() + { + if ( ast == nullptr ) + { + log_failure("Attempt to dereference a nullptr"); + return nullptr; + } + return ast; + } + AST_Struct* ast; +}; + +#define Define_CodeType( Typename ) \ +struct Code##Typename \ +{ \ + Using_Code( Code##Typename ); \ + AST* raw() \ + { \ + return rcast( AST*, ast ); \ + } \ + operator Code() \ + { \ + return * rcast( Code*, this ); \ + } \ + AST_##Typename* operator->() \ + { \ + if ( ast == nullptr ) \ + { \ + log_failure("Attempt to dereference a nullptr!"); \ + return nullptr; \ + } \ + return ast; \ + } \ + AST_##Typename* ast; \ +} + +Define_CodeType( Attributes ); +Define_CodeType( Comment ); +Define_CodeType( Define ); +Define_CodeType( Enum ); +Define_CodeType( Exec ); +Define_CodeType( Extern ); +Define_CodeType( Include ); +Define_CodeType( Friend ); +Define_CodeType( Fn ); +Define_CodeType( Module ); +Define_CodeType( Namespace ); +Define_CodeType( Operator ); +Define_CodeType( OpCast ); +Define_CodeType( Pragma ); +Define_CodeType( PreprocessCond ); +Define_CodeType( Template ); +Define_CodeType( Type ); +Define_CodeType( Typedef ); +Define_CodeType( Union ); +Define_CodeType( Using ); +Define_CodeType( Var ); + +#undef Define_CodeType +#undef Using_Code + +#pragma endregion Code Types + diff --git a/project/components/ast_case_macros.cpp b/project/components/ast_case_macros.cpp index fa47e8b..d9c05af 100644 --- a/project/components/ast_case_macros.cpp +++ b/project/components/ast_case_macros.cpp @@ -77,3 +77,4 @@ case Specifiers: \ case Struct_Body: \ case Typename: + diff --git a/project/components/data_structures.hpp b/project/components/ast_types.hpp similarity index 50% rename from project/components/data_structures.hpp rename to project/components/ast_types.hpp index 65cd330..0f56611 100644 --- a/project/components/data_structures.hpp +++ b/project/components/ast_types.hpp @@ -1,591 +1,4 @@ -#pragma region Data Structures - -// Implements basic string interning. Data structure is based off the ZPL Hashtable. -using StringTable = HashTable; - -// Represents strings cached with the string table. -// Should never be modified, if changed string is desired, cache_string( str ) another. -using StringCached = String const; - -struct AST; -struct AST_Body; -struct AST_Attributes; -struct AST_Comment; -struct AST_Class; -struct AST_Define; -struct AST_Enum; -struct AST_Exec; -struct AST_Extern; -struct AST_Include; -struct AST_Friend; -struct AST_Fn; -struct AST_Module; -struct AST_Namespace; -struct AST_Operator; -struct AST_OpCast; -struct AST_Param; -struct AST_Pragma; -struct AST_PreprocessCond; -struct AST_Specifiers; -struct AST_Struct; -struct AST_Template; -struct AST_Type; -struct AST_Typedef; -struct AST_Union; -struct AST_Using; -struct AST_Var; - -struct Code; -struct CodeBody; -// These are to offer ease of use and optionally strong type safety for the AST. -struct CodeAttributes; -struct CodeComment; -struct CodeClass; -struct CodeDefine; -struct CodeEnum; -struct CodeExec; -struct CodeExtern; -struct CodeInclude; -struct CodeFriend; -struct CodeFn; -struct CodeModule; -struct CodeNamespace; -struct CodeOperator; -struct CodeOpCast; -struct CodeParam; -struct CodePreprocessCond; -struct CodePragma; -struct CodeSpecifiers; -struct CodeStruct; -struct CodeTemplate; -struct CodeType; -struct CodeTypedef; -struct CodeUnion; -struct CodeUsing; -struct CodeVar; - -/* - AST* wrapper - - Not constantly have to append the '*' as this is written often.. - - Allows for implicit conversion to any of the ASTs (raw or filtered). -*/ -struct Code -{ -# pragma region Statics - // Used to identify ASTs that should always be duplicated. (Global constant ASTs) - static Code Global; - - // Used to identify invalid generated code. - static Code Invalid; -# pragma endregion Statics - - #define Using_Code( Typename ) \ - char const* debug_str(); \ - Code duplicate(); \ - bool is_equal( Code other ); \ - bool is_valid(); \ - void set_global(); \ - String to_string(); \ - Typename& operator = ( AST* other ); \ - Typename& operator = ( Code other ); \ - bool operator ==( Code other ); \ - bool operator !=( Code other ); \ - operator bool() \ - { \ - return ast != nullptr; \ - } - - template< class Type > - Type cast() - { - return * rcast( Type*, this ); - } - - AST* operator ->() - { - return ast; - } - Code& operator ++(); - Code& operator*() - { - return *this; - } - - Using_Code( Code ); - - AST* ast; - -#ifdef GEN_ENFORCE_STRONG_CODE_TYPES -# define operator explicit operator -#endif - operator CodeAttributes() const; - operator CodeComment() const; - operator CodeClass() const; - operator CodeDefine() const; - operator CodeExec() const; - operator CodeEnum() const; - operator CodeExtern() const; - operator CodeInclude() const; - operator CodeFriend() const; - operator CodeFn() const; - operator CodeModule() const; - operator CodeNamespace() const; - operator CodeOperator() const; - operator CodeOpCast() const; - operator CodeParam() const; - operator CodePragma() const; - operator CodePreprocessCond() const; - operator CodeSpecifiers() const; - operator CodeStruct() const; - operator CodeTemplate() const; - operator CodeType() const; - operator CodeTypedef() const; - operator CodeUnion() const; - operator CodeUsing() const; - operator CodeVar() const; - operator CodeBody() const; - #undef operator -}; - -struct Code_POD -{ - AST* ast; -}; - -static_assert( sizeof(Code) == sizeof(Code_POD), "ERROR: Code is not POD" ); - -// Desired width of the AST data structure. -constexpr u32 AST_POD_Size = 128; - -/* - Simple AST POD with functionality to seralize into C++ syntax. -*/ -struct AST -{ -# pragma region Member Functions - void append ( AST* other ); - char const* debug_str (); - AST* duplicate (); - Code& entry ( u32 idx ); - bool has_entries(); - bool is_equal ( AST* other ); - String to_string (); - char const* type_str(); - bool validate_body(); - - template< class Type > - Type cast() - { - return * this; - } - - operator Code(); - operator CodeBody(); - operator CodeAttributes(); - operator CodeComment(); - operator CodeClass(); - operator CodeDefine(); - operator CodeEnum(); - operator CodeExec(); - operator CodeExtern(); - operator CodeInclude(); - operator CodeFriend(); - operator CodeFn(); - operator CodeModule(); - operator CodeNamespace(); - operator CodeOperator(); - operator CodeOpCast(); - operator CodeParam(); - operator CodePragma(); - operator CodePreprocessCond(); - operator CodeSpecifiers(); - operator CodeStruct(); - operator CodeTemplate(); - operator CodeType(); - operator CodeTypedef(); - operator CodeUnion(); - operator CodeUsing(); - operator CodeVar(); -# pragma endregion Member Functions - - constexpr static - uw ArrSpecs_Cap = - ( - AST_POD_Size - - sizeof(AST*) * 3 - - sizeof(StringCached) - - sizeof(CodeT) - - sizeof(ModuleFlag) - - sizeof(s32) - ) - / sizeof(SpecifierT) -1; // -1 for 4 extra bytes - - union { - struct - { - AST* Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable - AST* Specs; // Function, Operator, Type symbol, Variable - union { - AST* ParentType; // Class, Struct - AST* ReturnType; // Function, Operator - AST* UnderlyingType; // Enum, Typedef - AST* ValueType; // Parameter, Variable - }; - union { - AST* Params; // Function, Operator, Template - AST* BitfieldSize; // Varaiable (Class/Struct Data Member) - }; - union { - AST* ArrExpr; // Type Symbol - AST* Body; // Class, Enum, Function, Namespace, Struct, Union - AST* Declaration; // Friend, Template - AST* Value; // Parameter, Variable - }; - }; - StringCached Content; // Attributes, Comment, Execution, Include - SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers - }; - union { - AST* Prev; - AST* Front; - AST* Last; - }; - union { - AST* Next; - AST* Back; - }; - AST* Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - union { - OperatorT Op; - AccessSpec ParentAccess; - s32 NumEntries; - }; -}; - -struct AST_POD -{ - union { - struct - { - AST* Attributes; // Class, Enum, Function, Struct, Typename, Union, Using, Variable - AST* Specs; // Function, Operator, Type symbol, Variable - union { - AST* ParentType; // Class, Struct - AST* ReturnType; // Function, Operator - AST* UnderlyingType; // Enum, Typedef - AST* ValueType; // Parameter, Variable - }; - union { - AST* Params; // Function, Operator, Template - AST* BitfieldSize; // Varaiable (Class/Struct Data Member) - }; - union { - AST* ArrExpr; // Type Symbol - AST* Body; // Class, Enum, Function, Namespace, Struct, Union - AST* Declaration; // Friend, Template - AST* Value; // Parameter, Variable - }; - }; - StringCached Content; // Attributes, Comment, Execution, Include - SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers - }; - union { - AST* Prev; - AST* Front; - AST* Last; - }; - union { - AST* Next; - AST* Back; - }; - AST* Parent; - StringCached Name; - CodeT Type; - ModuleFlag ModuleFlags; - union { - OperatorT Op; - AccessSpec ParentAccess; - s32 NumEntries; - }; -}; - -// Its intended for the AST to have equivalent size to its POD. -// All extra functionality within the AST namespace should just be syntatic sugar. -static_assert( sizeof(AST) == sizeof(AST_POD), "ERROR: AST IS NOT POD" ); -static_assert( sizeof(AST_POD) == AST_POD_Size, "ERROR: AST POD is not size of AST_POD_Size" ); - -// Used when the its desired when omission is allowed in a definition. -#define NoCode { nullptr } -#define CodeInvalid (* Code::Invalid.ast) // Uses an implicitly overloaded cast from the AST to the desired code type. - -#pragma region Code Types -#define Define_CodeType( Typename ) \ -struct Code##Typename \ -{ \ - Using_Code( Code##Typename ); \ - AST* raw() \ - { \ - return rcast( AST*, ast ); \ - } \ - operator Code() \ - { \ - return * rcast( Code*, this ); \ - } \ - AST_##Typename* operator->() \ - { \ - if ( ast == nullptr ) \ - { \ - log_failure("Attempt to dereference a nullptr!"); \ - return nullptr; \ - } \ - return ast; \ - } \ - AST_##Typename* ast; \ -} - -struct CodeBody -{ - Using_Code( CodeBody ); - - void append( Code other ) - { - raw()->append( other.ast ); - } - void append( CodeBody body ) - { - for ( Code entry : body ) - { - append( entry ); - } - } - bool has_entries() - { - return rcast( AST*, ast )->has_entries(); - } - AST* raw() - { - return rcast( AST*, ast ); - } - AST_Body* operator->() - { - return ast; - } - operator Code() - { - return * rcast( Code*, this ); - } -#pragma region Iterator - Code begin() - { - if ( ast ) - return { rcast( AST*, ast)->Front }; - - return { nullptr }; - } - Code end() - { - return { rcast(AST*, ast)->Back->Next }; - } -#pragma endregion Iterator - - AST_Body* ast; -}; - -Define_CodeType( Attributes ); -Define_CodeType( Comment ); -Define_CodeType( Define ); -Define_CodeType( Enum ); -Define_CodeType( Exec ); -Define_CodeType( Extern ); -Define_CodeType( Include ); -Define_CodeType( Friend ); -Define_CodeType( Fn ); -Define_CodeType( Module ); -Define_CodeType( Namespace ); -Define_CodeType( Operator ); -Define_CodeType( OpCast ); -Define_CodeType( Pragma ); -Define_CodeType( PreprocessCond ); -Define_CodeType( Template ); -Define_CodeType( Type ); -Define_CodeType( Typedef ); -Define_CodeType( Union ); -Define_CodeType( Using ); -Define_CodeType( Var ); - -struct CodeClass -{ - Using_Code( CodeClass ); - - void add_interface( CodeType interface ); - - AST* raw() - { - return rcast( AST*, ast ); - } - operator Code() - { - return * rcast( Code*, this ); - } - AST_Class* operator->() - { - if ( ast == nullptr ) - { - log_failure("Attempt to dereference a nullptr"); - return nullptr; - } - return ast; - } - AST_Class* ast; -}; - -struct CodeParam -{ - Using_Code( CodeParam ); - - void append( CodeParam other ); - - CodeParam get( s32 idx ); - bool has_entries(); - AST* raw() - { - return rcast( AST*, ast ); - } - AST_Param* operator->() - { - if ( ast == nullptr ) - { - log_failure("Attempt to dereference a nullptr!"); - return nullptr; - } - return ast; - } - operator Code() - { - return { (AST*)ast }; - } -#pragma region Iterator - CodeParam begin() - { - if ( ast ) - return { ast }; - - return { nullptr }; - } - CodeParam end() - { - return { (AST_Param*) rcast( AST*, ast)->Last }; - } - CodeParam& operator++(); - CodeParam operator*() - { - return * this; - } -#pragma endregion Iterator - - AST_Param* ast; -}; - -struct CodeSpecifiers -{ - Using_Code( CodeSpecifiers ); - - bool append( SpecifierT spec ) - { - if ( ast == nullptr ) - { - log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!"); - return false; - } - - if ( raw()->NumEntries == AST::ArrSpecs_Cap ) - { - log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST::ArrSpecs_Cap ); - return false; - } - - raw()->ArrSpecs[ raw()->NumEntries ] = spec; - raw()->NumEntries++; - return true; - } - s32 has( SpecifierT spec ) - { - for ( s32 idx = 0; idx < raw()->NumEntries; idx++ ) - { - if ( raw()->ArrSpecs[ raw()->NumEntries ] == spec ) - return idx; - } - - return -1; - } - AST* raw() - { - return rcast( AST*, ast ); - } - AST_Specifiers* operator->() - { - if ( ast == nullptr ) - { - log_failure("Attempt to dereference a nullptr!"); - return nullptr; - } - return ast; - } - operator Code() - { - return { (AST*) ast }; - } -#pragma region Iterator - SpecifierT* begin() - { - if ( ast ) - return & raw()->ArrSpecs[0]; - - return nullptr; - } - SpecifierT* end() - { - return raw()->ArrSpecs + raw()->NumEntries; - } -#pragma endregion Iterator - - AST_Specifiers* ast; -}; - -struct CodeStruct -{ - Using_Code( CodeStruct ); - - void add_interface( CodeType interface ); - - AST* raw() - { - return rcast( AST*, ast ); - } - operator Code() - { - return * rcast( Code*, this ); - } - AST_Struct* operator->() - { - if ( ast == nullptr ) - { - log_failure("Attempt to dereference a nullptr"); - return nullptr; - } - return ast; - } - AST_Struct* ast; -}; - -#undef Define_CodeType -#undef Using_Code -#pragma endregion Code Types - -#pragma region Filtered ASTs +#pragma region AST Types /* Show only relevant members of the AST for its type. AST* fields are replaced with Code types. @@ -1083,6 +496,5 @@ struct AST_Var char _PAD_UNUSED_[ sizeof(u32) ]; }; static_assert( sizeof(AST_Var) == sizeof(AST), "ERROR: AST_Var is not the same size as AST"); -#pragma endregion Filtered ASTs +#pragma endregion AST Types -#pragma endregion Data Structures diff --git a/project/components/header_end.hpp b/project/components/header_end.hpp index 47f923e..3a043f9 100644 --- a/project/components/header_end.hpp +++ b/project/components/header_end.hpp @@ -1,396 +1,3 @@ -#pragma region Inlines - -void AST::append( AST* other ) -{ - if ( other->Parent ) - other = other->duplicate(); - - other->Parent = this; - - if ( Front == nullptr ) - { - Front = other; - Back = other; - - NumEntries++; - return; - } - - AST* - Current = Back; - Current->Next = other; - other->Prev = Current; - Back = other; - NumEntries++; -} - -char const* AST::debug_str() -{ - if ( Parent ) - { - char const* fmt = stringize( - \nType : %s - \nParent : %s %s - \nName : %s - ); - - // These should be used immediately in a log. - // Thus if its desired to keep the debug str - // for multiple calls to bprintf, - // allocate this to proper string. - return str_fmt_buf( fmt - , type_str() - , Parent->Name - , Parent->type_str() - , Name ? Name : "" - ); - } - - char const* fmt = stringize( - \nType : %s - \nName : %s - ); - - // These should be used immediately in a log. - // Thus if its desired to keep the debug str - // for multiple calls to bprintf, - // allocate this to proper string. - return str_fmt_buf( fmt - , type_str() - , Name ? Name : "" - ); -} - -Code& AST::entry( u32 idx ) -{ - AST** current = & Front; - while ( idx >= 0 && current != nullptr ) - { - if ( idx == 0 ) - return * rcast( Code*, current); - - current = & ( * current )->Next; - idx--; - } - - return * rcast( Code*, current); -} - -bool AST::has_entries() -{ - return NumEntries; -} - -char const* AST::type_str() -{ - return ECode::to_str( Type ); -} - -AST::operator Code() -{ - return { this }; -} - -Code& Code::operator ++() -{ - if ( ast ) - ast = ast->Next; - - return *this; -} - -#pragma region AST & Code Gen Common - -#define Define_CodeImpl( Typename ) \ -char const* Typename::debug_str() \ -{ \ - if ( ast == nullptr ) \ - return "Code::debug_str: AST is null!"; \ - \ - return rcast(AST*, ast)->debug_str(); \ -} \ -Code Typename::duplicate() \ -{ \ - if ( ast == nullptr ) \ - { \ - log_failure("Code::duplicate: Cannot duplicate code, AST is null!"); \ - return Code::Invalid; \ - } \ - \ - return { rcast(AST*, ast)->duplicate() }; \ -} \ -bool Typename::is_equal( Code other ) \ -{ \ - if ( ast == nullptr || other.ast == nullptr ) \ - { \ - log_failure("Code::is_equal: Cannot compare code, AST is null!"); \ - return false; \ - } \ - \ - return rcast(AST*, ast)->is_equal( other.ast ); \ -} \ -bool Typename::is_valid() \ -{ \ - return (AST*) ast != nullptr && rcast( AST*, ast)->Type != CodeT::Invalid; \ -} \ -void Typename::set_global() \ -{ \ - if ( ast == nullptr ) \ - { \ - log_failure("Code::set_global: Cannot set code as global, AST is null!"); \ - return; \ - } \ - \ - rcast(AST*, ast)->Parent = Code::Global.ast; \ -} \ -String Typename::to_string() \ -{ \ - if ( ast == nullptr ) \ - { \ - log_failure("Code::to_string: Cannot convert code to string, AST is null!"); \ - return { nullptr }; \ - } \ - \ - return rcast(AST*, ast)->to_string(); \ -} \ -Typename& Typename::operator =( Code other ) \ -{ \ - if ( other.ast && other->Parent ) \ - { \ - ast = rcast( decltype(ast), other.ast->duplicate() ); \ - rcast( AST*, ast)->Parent = nullptr; \ - } \ - \ - ast = rcast( decltype(ast), other.ast ); \ - return *this; \ -} \ -bool Typename::operator ==( Code other ) \ -{ \ - return (AST*) ast == other.ast; \ -} \ -bool Typename::operator !=( Code other ) \ -{ \ - return (AST*) ast != other.ast; \ -} - -Define_CodeImpl( Code ); -Define_CodeImpl( CodeBody ); -Define_CodeImpl( CodeAttributes ); -Define_CodeImpl( CodeComment ); -Define_CodeImpl( CodeClass ); -Define_CodeImpl( CodeDefine ); -Define_CodeImpl( CodeEnum ); -Define_CodeImpl( CodeExec ); -Define_CodeImpl( CodeExtern ); -Define_CodeImpl( CodeInclude ); -Define_CodeImpl( CodeFriend ); -Define_CodeImpl( CodeFn ); -Define_CodeImpl( CodeModule ); -Define_CodeImpl( CodeNamespace ); -Define_CodeImpl( CodeOperator ); -Define_CodeImpl( CodeOpCast ); -Define_CodeImpl( CodeParam ); -Define_CodeImpl( CodePragma ); -Define_CodeImpl( CodePreprocessCond ); -Define_CodeImpl( CodeSpecifiers ); -Define_CodeImpl( CodeStruct ); -Define_CodeImpl( CodeTemplate ); -Define_CodeImpl( CodeType ); -Define_CodeImpl( CodeTypedef ); -Define_CodeImpl( CodeUnion ); -Define_CodeImpl( CodeUsing ); -Define_CodeImpl( CodeVar ); -#undef Define_CodeImpl - -#define Define_AST_Cast( typename ) \ -AST::operator Code ## typename() \ -{ \ - return { rcast( AST_ ## typename*, this ) }; \ -} - -Define_AST_Cast( Body ); -Define_AST_Cast( Attributes ); -Define_AST_Cast( Comment ); -Define_AST_Cast( Class ); -Define_AST_Cast( Define ); -Define_AST_Cast( Enum ); -Define_AST_Cast( Exec ); -Define_AST_Cast( Extern ); -Define_AST_Cast( Include ); -Define_AST_Cast( Friend ); -Define_AST_Cast( Fn ); -Define_AST_Cast( Module ); -Define_AST_Cast( Namespace ); -Define_AST_Cast( Operator ); -Define_AST_Cast( OpCast ); -Define_AST_Cast( Param ); -Define_AST_Cast( Pragma ); -Define_AST_Cast( PreprocessCond ); -Define_AST_Cast( Struct ); -Define_AST_Cast( Specifiers ); -Define_AST_Cast( Template ); -Define_AST_Cast( Type ); -Define_AST_Cast( Typedef ); -Define_AST_Cast( Union ); -Define_AST_Cast( Using ); -Define_AST_Cast( Var ); -#undef Define_AST_Cast - -#define Define_CodeCast( type ) \ -Code::operator Code ## type() const \ -{ \ - return { (AST_ ## type*) ast }; \ -} - -Define_CodeCast( Attributes ); -Define_CodeCast( Comment ); -Define_CodeCast( Class ); -Define_CodeCast( Define ); -Define_CodeCast( Exec ); -Define_CodeCast( Enum ); -Define_CodeCast( Extern ); -Define_CodeCast( Include ); -Define_CodeCast( Friend ); -Define_CodeCast( Fn ); -Define_CodeCast( Module ); -Define_CodeCast( Namespace ); -Define_CodeCast( Operator ); -Define_CodeCast( OpCast ); -Define_CodeCast( Param ); -Define_CodeCast( Pragma ); -Define_CodeCast( PreprocessCond ); -Define_CodeCast( Specifiers ); -Define_CodeCast( Struct ); -Define_CodeCast( Template ); -Define_CodeCast( Type ); -Define_CodeCast( Typedef ); -Define_CodeCast( Union ); -Define_CodeCast( Using ); -Define_CodeCast( Var ); -Define_CodeCast( Body); -#undef Define_CodeCast - -#pragma endregion AST & Code Gen Common - -void CodeClass::add_interface( CodeType type ) -{ - if ( ! ast->Next ) - { - ast->Next = type; - ast->Last = ast->Next; - return; - } - - ast->Next->Next = type; - ast->Last = ast->Next->Next; -} - -void CodeParam::append( CodeParam other ) -{ - AST* self = (AST*) ast; - AST* entry = (AST*) other.ast; - - if ( entry->Parent ) - entry = entry->duplicate(); - - entry->Parent = self; - - if ( self->Last == nullptr ) - { - self->Last = entry; - self->Next = entry; - self->NumEntries++; - return; - } - - self->Last->Next = entry; - self->Last = entry; - self->NumEntries++; -} - -CodeParam CodeParam::get( s32 idx ) -{ - CodeParam param = *this; - do - { - if ( ! ++ param ) - return { nullptr }; - - return { (AST_Param*) param.raw()->Next }; - } - while ( --idx ); - - return { nullptr }; -} - -bool CodeParam::has_entries() -{ - return ast->NumEntries > 0; -} - -CodeParam& CodeParam::operator ++() -{ - ast = ast->Next.ast; - return * this; -} - -void CodeStruct::add_interface( CodeType type ) -{ - if ( ! ast->Next ) - { - ast->Next = type; - ast->Last = ast->Next; - } - - ast->Next->Next = type; - ast->Last = ast->Next->Next; -} - -CodeBody def_body( CodeT type ) -{ - switch ( type ) - { - using namespace ECode; - case Class_Body: - case Enum_Body: - case Export_Body: - case Extern_Linkage: - case Function_Body: - case Global_Body: - case Namespace_Body: - case Struct_Body: - case Union_Body: - break; - - default: - log_failure( "def_body: Invalid type %s", (char const*)ECode::to_str(type) ); - return (CodeBody)Code::Invalid; - } - - Code - result = make_code(); - result->Type = type; - return (CodeBody)result; -} - -//! Do not use directly. Use the token_fmt macro instead. -// Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string. -StrC token_fmt_impl( sw num, ... ) -{ - local_persist thread_local - char buf[GEN_PRINTF_MAXLEN] = { 0 }; - mem_set( buf, 0, GEN_PRINTF_MAXLEN ); - - va_list va; - va_start(va, num ); - sw result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va); - va_end(va); - - return { result, buf }; -} - -#pragma endregion Inlines - #pragma region Constants #ifndef GEN_GLOBAL_BUCKET_SIZE @@ -541,6 +148,7 @@ extern CodeType t_typename; // Global allocator used for data with process lifetime. extern AllocatorInfo GlobalAllocator; extern Array< Arena > Global_AllocatorBuckets; + extern Array< Pool > CodePools; extern Array< Arena > StringArenas; @@ -556,3 +164,4 @@ extern CodeType t_typename; extern AllocatorInfo Allocator_TypeTable; #endif + diff --git a/project/components/header_start.hpp b/project/components/header_start.hpp index 42e210e..a7587f1 100644 --- a/project/components/header_start.hpp +++ b/project/components/header_start.hpp @@ -15,3 +15,12 @@ #ifndef GEN_ROLL_OWN_DEPENDENCIES # include "gen.dep.hpp" #endif + +#ifdef GEN_DONT_USE_NAMESPACE +# define GEN_NS_BEGIN +# define GEN_NS_END +#else +# define GEN_NS_BEGIN namespace gen { +# define GEN_NS_END } +#endif + diff --git a/project/components/inlines.hpp b/project/components/inlines.hpp new file mode 100644 index 0000000..d15b79c --- /dev/null +++ b/project/components/inlines.hpp @@ -0,0 +1,214 @@ +void AST::append( AST* other ) +{ + if ( other->Parent ) + other = other->duplicate(); + + other->Parent = this; + + if ( Front == nullptr ) + { + Front = other; + Back = other; + + NumEntries++; + return; + } + + AST* + Current = Back; + Current->Next = other; + other->Prev = Current; + Back = other; + NumEntries++; +} + +char const* AST::debug_str() +{ + if ( Parent ) + { + char const* fmt = stringize( + \nType : %s + \nParent : %s %s + \nName : %s + ); + + // These should be used immediately in a log. + // Thus if its desired to keep the debug str + // for multiple calls to bprintf, + // allocate this to proper string. + return str_fmt_buf( fmt + , type_str() + , Parent->Name + , Parent->type_str() + , Name ? Name : "" + ); + } + + char const* fmt = stringize( + \nType : %s + \nName : %s + ); + + // These should be used immediately in a log. + // Thus if its desired to keep the debug str + // for multiple calls to bprintf, + // allocate this to proper string. + return str_fmt_buf( fmt + , type_str() + , Name ? Name : "" + ); +} + +Code& AST::entry( u32 idx ) +{ + AST** current = & Front; + while ( idx >= 0 && current != nullptr ) + { + if ( idx == 0 ) + return * rcast( Code*, current); + + current = & ( * current )->Next; + idx--; + } + + return * rcast( Code*, current); +} + +bool AST::has_entries() +{ + return NumEntries; +} + +char const* AST::type_str() +{ + return ECode::to_str( Type ); +} + +AST::operator Code() +{ + return { this }; +} + +Code& Code::operator ++() +{ + if ( ast ) + ast = ast->Next; + + return *this; +} + +void CodeClass::add_interface( CodeType type ) +{ + if ( ! ast->Next ) + { + ast->Next = type; + ast->Last = ast->Next; + return; + } + + ast->Next->Next = type; + ast->Last = ast->Next->Next; +} + +void CodeParam::append( CodeParam other ) +{ + AST* self = (AST*) ast; + AST* entry = (AST*) other.ast; + + if ( entry->Parent ) + entry = entry->duplicate(); + + entry->Parent = self; + + if ( self->Last == nullptr ) + { + self->Last = entry; + self->Next = entry; + self->NumEntries++; + return; + } + + self->Last->Next = entry; + self->Last = entry; + self->NumEntries++; +} + +CodeParam CodeParam::get( s32 idx ) +{ + CodeParam param = *this; + do + { + if ( ! ++ param ) + return { nullptr }; + + return { (AST_Param*) param.raw()->Next }; + } + while ( --idx ); + + return { nullptr }; +} + +bool CodeParam::has_entries() +{ + return ast->NumEntries > 0; +} + +CodeParam& CodeParam::operator ++() +{ + ast = ast->Next.ast; + return * this; +} + +void CodeStruct::add_interface( CodeType type ) +{ + if ( ! ast->Next ) + { + ast->Next = type; + ast->Last = ast->Next; + } + + ast->Next->Next = type; + ast->Last = ast->Next->Next; +} + +CodeBody def_body( CodeT type ) +{ + switch ( type ) + { + using namespace ECode; + case Class_Body: + case Enum_Body: + case Export_Body: + case Extern_Linkage: + case Function_Body: + case Global_Body: + case Namespace_Body: + case Struct_Body: + case Union_Body: + break; + + default: + log_failure( "def_body: Invalid type %s", (char const*)ECode::to_str(type) ); + return (CodeBody)Code::Invalid; + } + + Code + result = make_code(); + result->Type = type; + return (CodeBody)result; +} + +StrC token_fmt_impl( sw num, ... ) +{ + local_persist thread_local + char buf[GEN_PRINTF_MAXLEN] = { 0 }; + mem_set( buf, 0, GEN_PRINTF_MAXLEN ); + + va_list va; + va_start(va, num ); + sw result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va); + va_end(va); + + return { result, buf }; +} + diff --git a/project/components/interface.cpp b/project/components/interface.cpp index ca4fc3a..dd3d3ce 100644 --- a/project/components/interface.cpp +++ b/project/components/interface.cpp @@ -440,3 +440,4 @@ void set_allocator_string_table( AllocatorInfo allocator ) { Allocator_StringArena = allocator; } + diff --git a/project/components/interface.hpp b/project/components/interface.hpp index 00dc4c5..020feee 100644 --- a/project/components/interface.hpp +++ b/project/components/interface.hpp @@ -159,6 +159,7 @@ CodeVar parse_variable ( StrC var_def ); #pragma region Untyped text sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va ); +//! Do not use directly. Use the token_fmt macro instead. StrC token_fmt_impl( sw, ... ); Code untyped_str ( StrC content); @@ -168,3 +169,4 @@ Code untyped_token_fmt( char const* fmt, s32 num_tokens, ... ); #pragma endregion Untyped text #pragma endregion Gen Interface + diff --git a/project/components/interface.parsing.cpp b/project/components/interface.parsing.cpp index 8de7a61..a6f2709 100644 --- a/project/components/interface.parsing.cpp +++ b/project/components/interface.parsing.cpp @@ -1,4 +1,3 @@ - namespace Parser { struct Token @@ -4430,3 +4429,4 @@ CodeVar parse_variable( StrC def ) # undef left # undef check # undef push_scope + diff --git a/project/components/interface.upfront.cpp b/project/components/interface.upfront.cpp index 35c9f92..42b6024 100644 --- a/project/components/interface.upfront.cpp +++ b/project/components/interface.upfront.cpp @@ -503,6 +503,7 @@ CodeDefine def_define( StrC name, StrC content ) CodeDefine result = (CodeDefine) make_code(); + result->Type = Preprocess_Define; result->Name = get_cached_string( name ); result->Content = get_cached_string( content ); @@ -1306,27 +1307,6 @@ CodeVar def_variable( CodeType type, StrC name, Code value return result; } -/* -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( ) - -* 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. - -* 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. - -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; \ @@ -1352,61 +1332,43 @@ if ( codes == nullptr ) \ 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_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 ) #pragma endregion Helper Macros for def_**_body functions CodeBody def_class_body( s32 num, ... ) { def_body_start( def_class_body ); - CodeBody - result = (CodeBody) make_code(); - result->Type = 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 ); - GEN_AST_BODY_CLASS_UNALLOWED_TYPES - def_body_code_validation_end( def_class_body ); + va_start( va, num ); + do + { + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + + if (!entry) + { + log_failure("gen::" + "def_class_body" + ": Provided an null entry"); + return CodeInvalid; + } + + switch (entry->Type) + { + GEN_AST_BODY_CLASS_UNALLOWED_TYPES + log_failure("gen::" "def_class_body" ": Entry type is not allowed: %s", entry.debug_str()); + return CodeInvalid; + + default: + break; + } + + result.append(entry); + } + while (num--, num > 0); va_end(va); return result; @@ -1420,9 +1382,30 @@ CodeBody def_class_body( s32 num, Code* codes ) result = (CodeBody) make_code(); result->Type = Function_Body; - def_body_code_array_validation_start( def_class_body ); - GEN_AST_BODY_CLASS_UNALLOWED_TYPES - def_body_code_validation_end( def_class_body ); + do + { + Code entry = *codes; + codes++; + + if (!entry) + { + log_failure("gen::" "def_class_body" ": Provided an null entry"); + return CodeInvalid; + } + + switch (entry->Type) + { + GEN_AST_BODY_CLASS_UNALLOWED_TYPES + log_failure("gen::" "def_class_body" ": Entry type is not allowed: %s", entry.debug_str()); + return CodeInvalid; + + default: + break; + } + + result.append(entry); + } + while (num--, num > 0); return result; } @@ -1503,9 +1486,30 @@ CodeBody def_export_body( s32 num, ... ) va_list va; va_start(va, num); - def_body_code_validation_start( def_export_body ); - GEN_AST_BODY_EXPORT_UNALLOWED_TYPES - def_body_code_validation_end( def_export_body ); + do + { + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + + if (!entry) + { + log_failure("gen::" "def_export_body" ": Provided an null entry"); + return CodeInvalid; + } + + switch (entry->Type) + { + GEN_AST_BODY_EXPORT_UNALLOWED_TYPES + log_failure("gen::" "def_export_body" ": Entry type is not allowed: %s", entry.debug_str()); + return CodeInvalid; + + default: + break; + } + + result.append(entry); + } + while (num--, num > 0); va_end(va); return result; @@ -1519,9 +1523,30 @@ CodeBody def_export_body( s32 num, Code* codes ) result = (CodeBody) make_code(); result->Type = Export_Body; - def_body_code_array_validation_start( def_export_body ); - GEN_AST_BODY_EXPORT_UNALLOWED_TYPES - def_body_code_validation_end( def_export_body ); + do + { + Code entry = *codes; + codes++; + + if (!entry) + { + log_failure("gen::" "def_export_body" ": Provided an null entry"); + return CodeInvalid; + } + + switch (entry->Type) + { + GEN_AST_BODY_EXPORT_UNALLOWED_TYPES + log_failure("gen::" "def_export_body" ": Entry type is not allowed: %s", entry.debug_str()); + return CodeInvalid; + + default: + break; + } + + result.append(entry); + } + while (num--, num > 0); return result; } @@ -1536,9 +1561,30 @@ CodeBody def_extern_link_body( s32 num, ... ) va_list va; va_start(va, num); - def_body_code_validation_start( def_extern_linkage_body ); - GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES - def_body_code_validation_end( def_extern_linkage_body ); + do + { + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + + if (!entry) + { + log_failure("gen::" "def_extern_linkage_body" ": Provided an null entry"); + return CodeInvalid; + } + + switch (entry->Type) + { + GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES + log_failure("gen::" "def_extern_linkage_body" ": Entry type is not allowed: %s", entry.debug_str()); + return CodeInvalid; + + default: + break; + } + + result.append(entry); + } + while (num--, num > 0); va_end(va); return result; @@ -1552,9 +1598,31 @@ CodeBody def_extern_link_body( s32 num, Code* codes ) result = (CodeBody) make_code(); result->Type = Extern_Linkage_Body; - def_body_code_array_validation_start( def_extern_linkage_body ); - GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES - def_body_code_validation_end( def_extern_linkage_body ); + do + { + Code entry = *codes; + codes++; + + if (!entry) + { + log_failure("gen::" "def_extern_linkage_body" ": Provided an null entry"); + return CodeInvalid; + } + + switch (entry->Type) + { + GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES + log_failure("gen::" "def_extern_linkage_body" ": Entry type is not allowed: %s", entry.debug_str()); + return CodeInvalid; + + default: + break; + } + + result.append(entry); + + } + while (num--, num > 0); return result; } @@ -1569,9 +1637,31 @@ CodeBody def_function_body( s32 num, ... ) va_list va; va_start(va, num); - def_body_code_validation_start( def_function_body ); - GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES - def_body_code_validation_end( def_function_body ); + do + { + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + + if (!entry) + { + log_failure("gen::" stringize(def_function_body) ": Provided an null entry"); + return CodeInvalid; + } + + switch (entry->Type) + { + + GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES + log_failure("gen::" stringize(def_function_body) ": Entry type is not allowed: %s", entry.debug_str()); + return CodeInvalid; + + default: + break; + } + + result.append(entry); + } + while (num--, num > 0); va_end(va); return result; @@ -1585,9 +1675,29 @@ CodeBody def_function_body( s32 num, Code* codes ) result = (CodeBody) make_code(); result->Type = Function_Body; - def_body_code_array_validation_start( def_function_body ); - GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES - def_body_code_validation_end( def_function_body ); + do + { + Code entry = *codes; + codes++; + + if (!entry) + { + log_failure("gen::" "def_function_body" ": Provided an null entry"); + return CodeInvalid; + } + + switch (entry->Type) + { + GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES + log_failure("gen::" "def_function_body" ": Entry type is not allowed: %s", entry.debug_str()); + return CodeInvalid; + + default: + break; + } + result.append(entry); + } + while (num--, num > 0); return result; } @@ -1602,9 +1712,30 @@ CodeBody def_global_body( s32 num, ... ) va_list va; va_start(va, num); - def_body_code_validation_start( def_global_body ); - GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES - def_body_code_validation_end( def_global_body ); + do + { + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + + if (!entry) + { + log_failure("gen::" "def_global_body" ": Provided an null entry"); + return CodeInvalid; + } + + switch (entry->Type) + { + GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES + log_failure("gen::" "def_global_body" ": Entry type is not allowed: %s", entry.debug_str()); + return (*Code::Invalid.ast); + + default: + break; + } + + result.append(entry); + } + while (num--, num > 0); va_end(va); return result; @@ -1618,9 +1749,30 @@ CodeBody def_global_body( s32 num, Code* codes ) result = (CodeBody) make_code(); result->Type = Global_Body; - def_body_code_array_validation_start( def_global_body ); - GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES - def_body_code_validation_end( def_global_body ); + do + { + Code entry = *codes; + codes++; + + if (!entry) + { + log_failure("gen::" "def_global_body" ": Provided an null entry"); + return CodeInvalid; + } + + switch (entry->Type) + { + GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES + log_failure("gen::" "def_global_body" ": Entry type is not allowed: %s", entry.debug_str()); + return CodeInvalid; + + default: + break; + } + + result.append(entry); + } + while (num--, num > 0); return result; } @@ -1635,9 +1787,30 @@ CodeBody def_namespace_body( s32 num, ... ) va_list va; va_start(va, num); - def_body_code_validation_start( def_namespace_body ); - GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES - def_body_code_validation_end( def_namespace_body ); + do + { + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + + if (!entry) + { + log_failure("gen::" "def_namespace_body" ": Provided an null entry"); + return CodeInvalid; + } + + switch (entry->Type) + { + GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES + log_failure("gen::" "def_namespace_body" ": Entry type is not allowed: %s", entry.debug_str()); + return CodeInvalid; + + default: + break; + } + + result.append(entry); + } + while (num--, num > 0); va_end(va); return result; @@ -1651,9 +1824,29 @@ CodeBody def_namespace_body( s32 num, Code* codes ) result = (CodeBody) make_code(); result->Type = Global_Body; - def_body_code_array_validation_start( def_namespace_body ); - GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES - def_body_code_validation_end( def_namespace_body ); + do + { + Code entry = *codes; + codes++; + + if (!entry) + { + log_failure("gen::" "def_namespace_body" ": Provided an null entry"); + return CodeInvalid; + } + + switch (entry->Type) + { + GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES + log_failure("gen::" "def_namespace_body" ": Entry type is not allowed: %s", entry.debug_str() ); + return CodeInvalid; + + default: break; + } + + result.append(entry); + } + while (num--, num > 0); return result; } @@ -1803,9 +1996,30 @@ CodeBody def_struct_body( s32 num, ... ) va_list va; va_start(va, num); - def_body_code_validation_start( def_struct_body ); - GEN_AST_BODY_STRUCT_UNALLOWED_TYPES - def_body_code_validation_end( def_struct_body ); + do + { + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); + + if (!entry) + { + log_failure("gen::" "def_struct_body" ": Provided an null entry"); + return CodeInvalid; + } + + switch (entry->Type) + { + GEN_AST_BODY_STRUCT_UNALLOWED_TYPES + log_failure("gen::" "def_struct_body" ": Entry type is not allowed: %s", entry.debug_str()); + return CodeInvalid; + + default: + break; + } + + result.append(entry); + } + while (num--, num > 0); va_end(va); return result; @@ -1819,9 +2033,30 @@ CodeBody def_struct_body( s32 num, Code* codes ) result = (CodeBody) make_code(); result->Type = Struct_Body; - def_body_code_array_validation_start( def_struct_body ); - GEN_AST_BODY_STRUCT_UNALLOWED_TYPES - def_body_code_validation_end( def_struct_body ); + do + { + Code entry = *codes; + codes++; + + if (!entry) + { + log_failure("gen::" "def_struct_body" ": Provided an null entry"); + return CodeInvalid; + } + + switch (entry->Type) + { + GEN_AST_BODY_STRUCT_UNALLOWED_TYPES + log_failure("gen::" "def_struct_body" ": Entry type is not allowed: %s", entry.debug_str() ); + return CodeInvalid; + + default: + break; + } + + result.append(entry); + } + while (num--, num > 0); return result; } @@ -1895,3 +2130,4 @@ CodeBody def_union_body( s32 num, CodeUnion* codes ) # undef name_check # undef null_check # undef null_or_invalid_check + diff --git a/project/components/impl_start.cpp b/project/components/src_start.cpp similarity index 99% rename from project/components/impl_start.cpp rename to project/components/src_start.cpp index 51b55e2..7c69c14 100644 --- a/project/components/impl_start.cpp +++ b/project/components/src_start.cpp @@ -7,3 +7,4 @@ #ifndef GEN_ROLL_OWN_DEPENDENCIES # include "gen.dep.cpp" #endif + diff --git a/project/components/static_data.cpp b/project/components/static_data.cpp index f914d94..914f95d 100644 --- a/project/components/static_data.cpp +++ b/project/components/static_data.cpp @@ -92,3 +92,4 @@ global CodeType t_f64; #endif #pragma endregion Constants + diff --git a/project/components/temp/Readme.md b/project/components/temp/Readme.md new file mode 100644 index 0000000..eae1c40 --- /dev/null +++ b/project/components/temp/Readme.md @@ -0,0 +1,8 @@ +# Temporary Code + +These are heavy macro code used throughout the library thats intended to be replaced with codegen done with the library itself. + +The reason for this is to minimize macro generation to only trivial cases. +This makes the library more verbose but makes it easier to debug which is of higher priority. + +Any sort of verbosity cost will be mitigated with better docs and heavy usage of pragma regions. diff --git a/project/components/temp/ast_inlines.hpp b/project/components/temp/ast_inlines.hpp new file mode 100644 index 0000000..cf5cef2 --- /dev/null +++ b/project/components/temp/ast_inlines.hpp @@ -0,0 +1,179 @@ +// This is the non-bootstraped version of the Common AST Implementation. This will be obsolete once bootstrap is stress tested. + +#pragma region AST Common + +#define Define_CodeImpl( Typename ) \ +char const* Typename::debug_str() \ +{ \ + if ( ast == nullptr ) \ + return "Code::debug_str: AST is null!"; \ + \ + return rcast(AST*, ast)->debug_str(); \ +} \ +Code Typename::duplicate() \ +{ \ + if ( ast == nullptr ) \ + { \ + log_failure("Code::duplicate: Cannot duplicate code, AST is null!"); \ + return Code::Invalid; \ + } \ + \ + return { rcast(AST*, ast)->duplicate() }; \ +} \ +bool Typename::is_equal( Code other ) \ +{ \ + if ( ast == nullptr || other.ast == nullptr ) \ + { \ + log_failure("Code::is_equal: Cannot compare code, AST is null!"); \ + return false; \ + } \ + \ + return rcast(AST*, ast)->is_equal( other.ast ); \ +} \ +bool Typename::is_valid() \ +{ \ + return (AST*) ast != nullptr && rcast( AST*, ast)->Type != CodeT::Invalid; \ +} \ +void Typename::set_global() \ +{ \ + if ( ast == nullptr ) \ + { \ + log_failure("Code::set_global: Cannot set code as global, AST is null!"); \ + return; \ + } \ + \ + rcast(AST*, ast)->Parent = Code::Global.ast; \ +} \ +String Typename::to_string() \ +{ \ + if ( ast == nullptr ) \ + { \ + log_failure("Code::to_string: Cannot convert code to string, AST is null!"); \ + return { nullptr }; \ + } \ + \ + return rcast(AST*, ast)->to_string(); \ +} \ +Typename& Typename::operator =( Code other ) \ +{ \ + if ( other.ast && other->Parent ) \ + { \ + ast = rcast( decltype(ast), other.ast->duplicate() ); \ + rcast( AST*, ast)->Parent = nullptr; \ + } \ + \ + ast = rcast( decltype(ast), other.ast ); \ + return *this; \ +} \ +bool Typename::operator ==( Code other ) \ +{ \ + return (AST*) ast == other.ast; \ +} \ +bool Typename::operator !=( Code other ) \ +{ \ + return (AST*) ast != other.ast; \ +} \ +Typename::operator bool() \ +{ \ + return ast != nullptr; \ +} + +Define_CodeImpl( Code ); +Define_CodeImpl( CodeBody ); +Define_CodeImpl( CodeAttributes ); +Define_CodeImpl( CodeComment ); +Define_CodeImpl( CodeClass ); +Define_CodeImpl( CodeDefine ); +Define_CodeImpl( CodeEnum ); +Define_CodeImpl( CodeExec ); +Define_CodeImpl( CodeExtern ); +Define_CodeImpl( CodeInclude ); +Define_CodeImpl( CodeFriend ); +Define_CodeImpl( CodeFn ); +Define_CodeImpl( CodeModule ); +Define_CodeImpl( CodeNamespace ); +Define_CodeImpl( CodeOperator ); +Define_CodeImpl( CodeOpCast ); +Define_CodeImpl( CodeParam ); +Define_CodeImpl( CodePragma ); +Define_CodeImpl( CodePreprocessCond ); +Define_CodeImpl( CodeSpecifiers ); +Define_CodeImpl( CodeStruct ); +Define_CodeImpl( CodeTemplate ); +Define_CodeImpl( CodeType ); +Define_CodeImpl( CodeTypedef ); +Define_CodeImpl( CodeUnion ); +Define_CodeImpl( CodeUsing ); +Define_CodeImpl( CodeVar ); +#undef Define_CodeImpl + +#define Define_AST_Cast( typename ) \ +AST::operator Code ## typename() \ +{ \ + return { rcast( AST_ ## typename*, this ) }; \ +} + +Define_AST_Cast( Body ); +Define_AST_Cast( Attributes ); +Define_AST_Cast( Comment ); +Define_AST_Cast( Class ); +Define_AST_Cast( Define ); +Define_AST_Cast( Enum ); +Define_AST_Cast( Exec ); +Define_AST_Cast( Extern ); +Define_AST_Cast( Include ); +Define_AST_Cast( Friend ); +Define_AST_Cast( Fn ); +Define_AST_Cast( Module ); +Define_AST_Cast( Namespace ); +Define_AST_Cast( Operator ); +Define_AST_Cast( OpCast ); +Define_AST_Cast( Param ); +Define_AST_Cast( Pragma ); +Define_AST_Cast( PreprocessCond ); +Define_AST_Cast( Struct ); +Define_AST_Cast( Specifiers ); +Define_AST_Cast( Template ); +Define_AST_Cast( Type ); +Define_AST_Cast( Typedef ); +Define_AST_Cast( Union ); +Define_AST_Cast( Using ); +Define_AST_Cast( Var ); +#undef Define_AST_Cast + +#define Define_CodeCast( type ) \ +Code::operator Code ## type() const \ +{ \ + return { (AST_ ## type*) ast }; \ +} + +Define_CodeCast( Attributes ); +Define_CodeCast( Comment ); +Define_CodeCast( Class ); +Define_CodeCast( Define ); +Define_CodeCast( Exec ); +Define_CodeCast( Enum ); +Define_CodeCast( Extern ); +Define_CodeCast( Include ); +Define_CodeCast( Friend ); +Define_CodeCast( Fn ); +Define_CodeCast( Module ); +Define_CodeCast( Namespace ); +Define_CodeCast( Operator ); +Define_CodeCast( OpCast ); +Define_CodeCast( Param ); +Define_CodeCast( Pragma ); +Define_CodeCast( PreprocessCond ); +Define_CodeCast( Specifiers ); +Define_CodeCast( Struct ); +Define_CodeCast( Template ); +Define_CodeCast( Type ); +Define_CodeCast( Typedef ); +Define_CodeCast( Union ); +Define_CodeCast( Using ); +Define_CodeCast( Var ); +Define_CodeCast( Body); +#undef Define_CodeCast + +#pragma endregion AST Common + diff --git a/project/components/ecode.hpp b/project/components/temp/ecode.hpp similarity index 99% rename from project/components/ecode.hpp rename to project/components/temp/ecode.hpp index 8422e77..20828c7 100644 --- a/project/components/ecode.hpp +++ b/project/components/temp/ecode.hpp @@ -84,3 +84,4 @@ namespace ECode # undef Define_Types } using CodeT = ECode::Type; + diff --git a/project/components/eoperator.hpp b/project/components/temp/eoperator.hpp similarity index 99% rename from project/components/eoperator.hpp rename to project/components/temp/eoperator.hpp index 70c99dd..16ed9bd 100644 --- a/project/components/eoperator.hpp +++ b/project/components/temp/eoperator.hpp @@ -73,3 +73,4 @@ namespace EOperator # undef Define_Operators } using OperatorT = EOperator::Type; + diff --git a/project/components/especifier.hpp b/project/components/temp/especifier.hpp similarity index 99% rename from project/components/especifier.hpp rename to project/components/temp/especifier.hpp index e2939ac..f72b506 100644 --- a/project/components/especifier.hpp +++ b/project/components/temp/especifier.hpp @@ -106,3 +106,4 @@ namespace ESpecifier # undef Define_Specifiers } using SpecifierT = ESpecifier::Type; + diff --git a/project/components/etoktype.cpp b/project/components/temp/etoktype.cpp similarity index 99% rename from project/components/etoktype.cpp rename to project/components/temp/etoktype.cpp index 78a5932..f4b1d73 100644 --- a/project/components/etoktype.cpp +++ b/project/components/temp/etoktype.cpp @@ -162,3 +162,4 @@ namespace Parser using TokType = ETokType::Type; } // Parser + diff --git a/project/components/types.hpp b/project/components/types.hpp index 99c4865..f6fc2a1 100644 --- a/project/components/types.hpp +++ b/project/components/types.hpp @@ -113,4 +113,13 @@ constexpr char const* Attribute_Keyword = stringize( GEN_Attribute_Keyword ); #endif constexpr char const* Attribute_Keyword = ""; + #endif + +// Implements basic string interning. Data structure is based off the ZPL Hashtable. +using StringTable = HashTable; + +// Represents strings cached with the string table. +// Should never be modified, if changed string is desired, cache_string( str ) another. +using StringCached = String const; + diff --git a/project/components/untyped.cpp b/project/components/untyped.cpp index 46c6e14..e9ab823 100644 --- a/project/components/untyped.cpp +++ b/project/components/untyped.cpp @@ -181,3 +181,4 @@ Code untyped_token_fmt( s32 num_tokens, ... ) return result; } + diff --git a/project/dependencies/basic_types.hpp b/project/dependencies/basic_types.hpp index 0aa0bec..942bfcf 100644 --- a/project/dependencies/basic_types.hpp +++ b/project/dependencies/basic_types.hpp @@ -118,3 +118,4 @@ typedef s16 b16; typedef s32 b32; #pragma region Basic Types + diff --git a/project/dependencies/containers.hpp b/project/dependencies/containers.hpp index 03f3044..ac233b9 100644 --- a/project/dependencies/containers.hpp +++ b/project/dependencies/containers.hpp @@ -533,3 +533,4 @@ protected: }; #pragma endregion Containers + diff --git a/project/dependencies/debug.cpp b/project/dependencies/debug.cpp index 25b6e1f..d73829c 100644 --- a/project/dependencies/debug.cpp +++ b/project/dependencies/debug.cpp @@ -39,3 +39,4 @@ s32 assert_crash( char const* condition ) #endif #pragma endregion Debug + diff --git a/project/dependencies/debug.hpp b/project/dependencies/debug.hpp index 6c8fd35..c439040 100644 --- a/project/dependencies/debug.hpp +++ b/project/dependencies/debug.hpp @@ -1,4 +1,4 @@ -#pragma endregion Debug +#pragma region Debug #if defined( _MSC_VER ) # if _MSC_VER < 1300 @@ -34,3 +34,4 @@ s32 assert_crash( char const* condition ); void process_exit( u32 code ); #pragma endregion Debug + diff --git a/project/dependencies/file_handling.cpp b/project/dependencies/file_handling.cpp index 3c9a931..542593a 100644 --- a/project/dependencies/file_handling.cpp +++ b/project/dependencies/file_handling.cpp @@ -634,3 +634,4 @@ internal GEN_FILE_CLOSE_PROC( _memory_file_close ) FileOperations const memory_file_operations = { _memory_file_read, _memory_file_write, _memory_file_seek, _memory_file_close }; #pragma endregion File Handling + diff --git a/project/dependencies/file_handling.hpp b/project/dependencies/file_handling.hpp index 671d2f3..faadb53 100644 --- a/project/dependencies/file_handling.hpp +++ b/project/dependencies/file_handling.hpp @@ -370,3 +370,4 @@ u8* file_stream_buf( FileInfo* file, sw* size ); extern FileOperations const memory_file_operations; #pragma endregion File Handling + diff --git a/project/dependencies/hashing.cpp b/project/dependencies/hashing.cpp index b0cd7b5..7989e70 100644 --- a/project/dependencies/hashing.cpp +++ b/project/dependencies/hashing.cpp @@ -83,3 +83,4 @@ u64 crc64( void const* data, sw len ) } #pragma region Hashing + diff --git a/project/dependencies/hashing.hpp b/project/dependencies/hashing.hpp index 2cc9f7e..f59b028 100644 --- a/project/dependencies/hashing.hpp +++ b/project/dependencies/hashing.hpp @@ -4,3 +4,4 @@ u32 crc32( void const* data, sw len ); u64 crc64( void const* data, sw len ); #pragma endregion Hashing + diff --git a/project/dependencies/header_start.hpp b/project/dependencies/header_start.hpp index 138d8fc..d654577 100644 --- a/project/dependencies/header_start.hpp +++ b/project/dependencies/header_start.hpp @@ -122,10 +122,21 @@ #pragma endregion Platform Detection #pragma region Mandatory Includes + # include # include # if defined( GEN_SYSTEM_WINDOWS ) # include # endif + #pragma endregion Mandatory Includes + +#ifdef GEN_DONT_USE_NAMESPACE +# define GEN_NS_BEGIN +# define GEN_NS_END +#else +# define GEN_NS_BEGIN namespace gen { +# define GEN_NS_END } +#endif + diff --git a/project/dependencies/macros.hpp b/project/dependencies/macros.hpp index 752dc3c..b50fa77 100644 --- a/project/dependencies/macros.hpp +++ b/project/dependencies/macros.hpp @@ -14,6 +14,7 @@ #define bitfield_is_equal( Type, Field, Mask ) ( (Type(Mask) & Type(Field)) == Type(Mask) ) // Casting + #define ccast( Type, Value ) ( * const_cast< Type* >( & (Value) ) ) #define pcast( Type, Value ) ( * reinterpret_cast< Type* >( & ( Value ) ) ) #define rcast( Type, Value ) reinterpret_cast< Type >( Value ) @@ -21,36 +22,43 @@ // Num Arguments (Varadics) #if defined(__GNUC__) || defined(__clang__) -// Supports 0-10 arguments +// Supports 0-50 arguments #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, \ + _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ + _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ + _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ N, ... \ ) N - // _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ - // _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ - // _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__, \ + 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \ + 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \ + 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \ 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, \ 0 \ ) - // 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \ - // 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \ - // 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, + #else -// Supports 1-10 arguments +// Supports 1-50 arguments #define num_args_impl( \ _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ + _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ + _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ + _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ N, ... \ ) N #define num_args(...) \ num_args_impl( __VA_ARGS__, \ + 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \ + 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \ + 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \ 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 \ ) @@ -105,3 +113,4 @@ void swap( Type& a, Type& b ) } #pragma endregion Macros + diff --git a/project/dependencies/memory.cpp b/project/dependencies/memory.cpp index 24a1b1c..39c83d1 100644 --- a/project/dependencies/memory.cpp +++ b/project/dependencies/memory.cpp @@ -387,3 +387,4 @@ void Pool::clear() } #pragma endregion Memory + diff --git a/project/dependencies/memory.hpp b/project/dependencies/memory.hpp index e9b5980..8b9b15b 100644 --- a/project/dependencies/memory.hpp +++ b/project/dependencies/memory.hpp @@ -484,3 +484,4 @@ struct Pool }; #pragma endregion Memory + diff --git a/project/dependencies/parsing.cpp b/project/dependencies/parsing.cpp index 2e27d83..d86609f 100644 --- a/project/dependencies/parsing.cpp +++ b/project/dependencies/parsing.cpp @@ -1104,3 +1104,4 @@ String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delimi } #pragma endregion CSV + diff --git a/project/dependencies/parsing.hpp b/project/dependencies/parsing.hpp index 19d3a8f..3f7810b 100644 --- a/project/dependencies/parsing.hpp +++ b/project/dependencies/parsing.hpp @@ -423,3 +423,4 @@ GEN_IMPL_INLINE String csv_write_string( AllocatorInfo a, CSV_Object* obj ) } #pragma endregion CSV + diff --git a/project/dependencies/printing.cpp b/project/dependencies/printing.cpp index 05151a0..18223fc 100644 --- a/project/dependencies/printing.cpp +++ b/project/dependencies/printing.cpp @@ -562,3 +562,4 @@ sw str_fmt_out_err( char const* fmt, ... ) } #pragma endregion Printing + diff --git a/project/dependencies/printing.hpp b/project/dependencies/printing.hpp index 7fa3262..5509388 100644 --- a/project/dependencies/printing.hpp +++ b/project/dependencies/printing.hpp @@ -13,9 +13,6 @@ sw str_fmt_va ( char* str, sw n, char const* fmt, va_list va ); sw str_fmt_out_va ( char const* fmt, va_list va ); sw str_fmt_out_err ( char const* fmt, ... ); sw str_fmt_out_err_va( char const* fmt, va_list va ); - -// TODO : Move these to file handling. - sw str_fmt_file ( FileInfo* f, char const* fmt, ... ); sw str_fmt_file_va ( FileInfo* f, char const* fmt, va_list va ); diff --git a/project/dependencies/impl_start.cpp b/project/dependencies/src_start.cpp similarity index 99% rename from project/dependencies/impl_start.cpp rename to project/dependencies/src_start.cpp index dda2e1d..7582c0d 100644 --- a/project/dependencies/impl_start.cpp +++ b/project/dependencies/src_start.cpp @@ -78,3 +78,4 @@ #endif #pragma endregion Macros and Includes + diff --git a/project/dependencies/string.cpp b/project/dependencies/string.cpp index c77477b..623fda0 100644 --- a/project/dependencies/string.cpp +++ b/project/dependencies/string.cpp @@ -37,3 +37,4 @@ bool String::append_fmt( char const* fmt, ... ) } #pragma endregion String + diff --git a/project/dependencies/string.hpp b/project/dependencies/string.hpp index 2ff6595..4ff7baf 100644 --- a/project/dependencies/string.hpp +++ b/project/dependencies/string.hpp @@ -373,3 +373,4 @@ struct String_POD static_assert( sizeof( String_POD ) == sizeof( String ), "String is not a POD" ); #pragma endregion String + diff --git a/project/dependencies/string_ops.cpp b/project/dependencies/string_ops.cpp index dc452e5..c1317d7 100644 --- a/project/dependencies/string_ops.cpp +++ b/project/dependencies/string_ops.cpp @@ -207,3 +207,4 @@ f64 str_to_f64( const char* str, char** end_ptr ) } #pragma endregion String Ops + diff --git a/project/dependencies/string_ops.hpp b/project/dependencies/string_ops.hpp index 9920c10..0393fe0 100644 --- a/project/dependencies/string_ops.hpp +++ b/project/dependencies/string_ops.hpp @@ -260,3 +260,4 @@ GEN_IMPL_INLINE void str_to_upper( char* str ) } #pragma endregion String Ops + diff --git a/project/dependencies/timing.cpp b/project/dependencies/timing.cpp index b5fecda..05a7db1 100644 --- a/project/dependencies/timing.cpp +++ b/project/dependencies/timing.cpp @@ -160,3 +160,4 @@ #endif #pragma endregion Timing + diff --git a/project/dependencies/timing.hpp b/project/dependencies/timing.hpp index e11d1ef..6ba8427 100644 --- a/project/dependencies/timing.hpp +++ b/project/dependencies/timing.hpp @@ -12,3 +12,4 @@ u64 time_rel_ms( void ); #endif #pragma endregion Timing + diff --git a/project/file_processors/builder.cpp b/project/file_processors/builder.cpp index e747d43..968bd69 100644 --- a/project/file_processors/builder.cpp +++ b/project/file_processors/builder.cpp @@ -1,3 +1,25 @@ +Builder Builder::open( char const* path ) +{ + Builder result; + + FileError error = file_open_mode( & result.File, EFileMode_WRITE, path ); + + if ( error != EFileError_NONE ) + { + log_failure( "gen::File::open - Could not open file: %s", path); + return result; + } + + result.Buffer = String::make_reserve( GlobalAllocator, Builder_StrBufferReserve ); + + return result; +} + +void Builder::pad_lines( s32 num ) +{ + Buffer.append( "\n" ); +} + void Builder::print( Code code ) { Buffer.append( code->to_string() ); @@ -16,21 +38,6 @@ void Builder::print_fmt( char const* fmt, ... ) Buffer.append( buf, res ); } -bool Builder::open( char const* path ) -{ - FileError error = file_open_mode( & File, EFileMode_WRITE, path ); - - 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() ); diff --git a/project/file_processors/builder.hpp b/project/file_processors/builder.hpp index fd02e10..b457ebe 100644 --- a/project/file_processors/builder.hpp +++ b/project/file_processors/builder.hpp @@ -3,9 +3,12 @@ struct Builder FileInfo File; String Buffer; + static Builder open( char const* path ); + + void pad_lines( s32 num ); + void print( Code ); void print_fmt( char const* fmt, ... ); - bool open( char const* path ); void write(); }; diff --git a/project/components/interface.upfront.bodies.cpp b/project/file_processors/scanner.cpp similarity index 100% rename from project/components/interface.upfront.bodies.cpp rename to project/file_processors/scanner.cpp diff --git a/project/gen.bootstrap.cpp b/project/gen.bootstrap.cpp index 202dc71..f052347 100644 --- a/project/gen.bootstrap.cpp +++ b/project/gen.bootstrap.cpp @@ -2,32 +2,22 @@ #define GEN_ENFORCE_STRONG_CODE_TYPES #define GEN_EXPOSE_BACKEND #include "gen.cpp" -#include "file_processors/scanner.hpp" + #include "helpers/helper.hpp" +GEN_NS_BEGIN +#include "dependencies/parsing.cpp" +GEN_NS_END + +#include "file_processors/builder.hpp" +#include "file_processors/builder.cpp" +#include "file_processors/scanner.hpp" + using namespace gen; -bool namespace_by_default = true; - -constexpr StrC nspace_default = txt_StrC(R"( -#if defined(GEN_DONT_USE_NAMESPACE) && ! defined(GEN_NS_BEGIN) -# define GEN_NS_BEGIN -# define GEN_NS_END -#elif ! defined(GEN_NS_BEGIN) -# define GEN_NS_BEGIN namespace gen { -# define GEN_NS_END } -#endif -)"); - -constexpr StrC nspace_non_default = txt_StrC(R"( -#if ! defined(GEN_USE_NAMESPACE) && ! defined(GEN_NS_BEGIN) -# define GEN_NS_BEGIN -# define GEN_NS_END -#elif ! defined(GEN_NS_BEGIN) -# define GEN_NS_BEGIN namespace gen { -# define GEN_NS_END } -#endif -)"); +constexpr char const* generation_notice = +"// This file was generated automatially by gen.bootstrap.cpp " +"(See: https://github.com/Ed94/gencpp)\n\n"; int gen_main() { @@ -39,7 +29,6 @@ int gen_main() // gen_dep.hpp { Code header_start = scan_file( "dependencies/header_start.hpp" ); - Code nspace_macro = untyped_str( namespace_by_default ? nspace_default : nspace_non_default ); Code macros = scan_file( "dependencies/macros.hpp" ); Code basic_types = scan_file( "dependencies/basic_types.hpp" ); Code debug = scan_file( "dependencies/debug.hpp" ); @@ -49,118 +38,114 @@ int gen_main() Code containers = scan_file( "dependencies/containers.hpp" ); Code hashing = scan_file( "dependencies/hashing.hpp" ); Code string = scan_file( "dependencies/string.hpp" ); - Code parsing = scan_file( "dependencies/parsing.hpp" ); + Code file_handling = scan_file( "dependencies/file_handling.hpp" ); Code timing = scan_file( "dependencies/timing.hpp" ); - // TOOD : Make this optional - Code file_handling = scan_file( "dependencies/file_handling.hpp" ); - Builder - deps_header; - deps_header.open("gen/gen_dep.hpp"); - deps_header.print_fmt("// This file is intended to be included within gen.hpp (There is no pragma diagnostic ignores)\n\n"); - deps_header.print_fmt("#pragma once\n\n"); - deps_header.print( header_start ); - deps_header.print( nspace_macro ); - deps_header.print_fmt( "GEN_NS_BEGIN\n\n"); + deps_header = Builder::open("gen/gen_dep.hpp"); + deps_header.print_fmt( generation_notice ); + deps_header.print_fmt("// This file is intended to be included within gen.hpp (There is no pragma diagnostic ignores)\n\n"); + deps_header.print_fmt("#pragma once\n\n"); + deps_header.print( header_start ); + deps_header.print_fmt( "GEN_NS_BEGIN\n\n"); - deps_header.print( macros ); - deps_header.print( basic_types ); - deps_header.print( debug ); - deps_header.print( memory ); - deps_header.print( string_ops ); - deps_header.print( printing ); - deps_header.print( containers ); - deps_header.print( hashing ); - deps_header.print( string ); - deps_header.print( file_handling ); - deps_header.print( parsing ); - deps_header.print( timing ); + deps_header.print( macros ); + deps_header.print( basic_types ); + deps_header.print( debug ); + deps_header.print( memory ); + deps_header.print( string_ops ); + deps_header.print( printing ); + deps_header.print( containers ); + deps_header.print( hashing ); + deps_header.print( string ); + deps_header.print( file_handling ); + deps_header.print( timing ); - deps_header.print_fmt( "GEN_NS_END\n\n"); + deps_header.print_fmt( "GEN_NS_END\n\n"); deps_header.write(); } // gen_dep.cpp { - CodeInclude header = def_include( txt_StrC("gen_dep.hpp") ); - Code impl_start = scan_file( "dependencies/impl_start.cpp" ); - Code debug = scan_file( "dependencies/debug.cpp" ); - Code string_ops = scan_file( "dependencies/string_ops.cpp" ); - Code printing = scan_file( "dependencies/printing.cpp" ); - Code memory = scan_file( "dependencies/memory.cpp" ); - Code parsing = scan_file( "dependencies/parsing.cpp" ); - Code hashing = scan_file( "dependencies/hashing.cpp" ); - Code string = scan_file( "dependencies/string.cpp" ); - Code timing = scan_file( "dependencies/timing.cpp" ); + Code src_start = scan_file( "dependencies/src_start.cpp" ); + Code debug = scan_file( "dependencies/debug.cpp" ); + Code string_ops = scan_file( "dependencies/string_ops.cpp" ); + Code printing = scan_file( "dependencies/printing.cpp" ); + Code memory = scan_file( "dependencies/memory.cpp" ); + Code hashing = scan_file( "dependencies/hashing.cpp" ); + Code string = scan_file( "dependencies/string.cpp" ); + Code file_handling = scan_file( "dependencies/file_handling.cpp" ); + Code timing = scan_file( "dependencies/timing.cpp" ); Builder - deps_impl; - deps_impl.open("gen/gen_dep.cpp"); - deps_impl.print_fmt("// This file is intended to be included within gen.cpp (There is no pragma diagnostic ignores)\n\n"); - deps_impl.print( impl_start ); - deps_impl.print( header ); - deps_impl.print_fmt( "\nGEN_NS_BEGIN\n"); + deps_impl = Builder::open("gen/gen_dep.cpp"); + deps_impl.print_fmt( generation_notice ); + deps_impl.print_fmt("// This file is intended to be included within gen.cpp (There is no pragma diagnostic ignores)\n\n"); + deps_impl.print( src_start ); + deps_impl.print_fmt( "GEN_NS_BEGIN\n\n"); - deps_impl.print( debug ); - deps_impl.print( string_ops ); - deps_impl.print( printing ); - deps_impl.print( hashing ); - deps_impl.print( memory ); - deps_impl.print( parsing ); - deps_impl.print( string ); - deps_impl.print( timing ); + deps_impl.print( debug ); + deps_impl.print( string_ops ); + deps_impl.print( printing ); + deps_impl.print( hashing ); + deps_impl.print( memory ); + deps_impl.print( string ); + deps_impl.print( file_handling ); + deps_impl.print( timing ); - deps_impl.print_fmt( "GEN_NS_END\n\n"); + deps_impl.print_fmt( "GEN_NS_END\n\n"); deps_impl.write(); } // gen.hpp { Code header_start = scan_file( "components/header_start.hpp" ); - Code nspace_macro = untyped_str( namespace_by_default ? nspace_default : nspace_non_default ); Code types = scan_file( "components/types.hpp" ); - Code data_structs = scan_file( "components/data_structures.hpp" ); + Code ast = scan_file( "components/ast.hpp" ); + Code ast_types = scan_file( "components/ast_types.hpp" ); Code interface = scan_file( "components/interface.hpp" ); + Code inlines = scan_file( "components/inlines.hpp" ); + Code ast_inlines = scan_file( "components/temp/ast_inlines.hpp" ); Code header_end = scan_file( "components/header_end.hpp" ); - CodeBody ecode = gen_ecode( "enums/ECode.csv" ); - CodeBody eoperator = gen_eoperator( "enums/EOperator.csv" ); + CodeBody ecode = gen_ecode ( "enums/ECode.csv" ); + CodeBody eoperator = gen_eoperator ( "enums/EOperator.csv" ); CodeBody especifier = gen_especifier( "enums/ESpecifier.csv" ); - // TODO : Make this optional to include - Code builder = scan_file( "file_processors/builder.hpp" ); - Builder - header; - header.open( "gen/gen.hpp" ); - header.print_fmt("#pragma once\n\n"); - header.print( push_ignores ); - header.print( header_start ); - header.print( nspace_macro ); - header.print_fmt( "GEN_NS_BEGIN\n\n"); + header = Builder::open( "gen/gen.hpp" ); + header.print_fmt( generation_notice ); + header.print_fmt("#pragma once\n\n"); + header.print( push_ignores ); + header.print( header_start ); + header.print_fmt( "GEN_NS_BEGIN\n\n"); - header.print_fmt("#pragma region Types\n\n"); - header.print( types ); - header.print( ecode ); - header.print( eoperator ); - header.print( especifier ); - header.print_fmt("#pragma endregion Types\n\n"); + header.print_fmt("#pragma region Types\n\n"); + header.print( types ); + header.print( ecode ); + header.print( eoperator ); + header.print( especifier ); + header.print_fmt("#pragma endregion Types\n\n"); - header.print( data_structs ); - header.print( interface ); - header.print( header_end ); + header.print_fmt("#pragma region AST\n\n"); + header.print( ast ); + header.print( ast_types ); + header.print_fmt("#pragma endregion AST\n\n"); - header.print( builder ); + header.print( interface ); - header.print_fmt( "GEN_NS_END\n\n"); - header.print( pop_ignores ); + header.print( inlines ); + header.print( ast_inlines ); + + header.print( header_end ); + header.print_fmt( "GEN_NS_END\n\n"); + header.print( pop_ignores ); header.write(); } // gen.cpp { - Code impl_start = scan_file( "components/impl_start.cpp" ); + Code src_start = scan_file( "components/src_start.cpp" ); CodeInclude header = def_include( txt_StrC("gen.hpp") ); Code data = scan_file( "components/static_data.cpp" ); Code ast_case_macros = scan_file( "components/ast_case_macros.cpp" ); @@ -170,33 +155,60 @@ int gen_main() Code parsing = scan_file( "components/interface.parsing.cpp" ); Code untyped = scan_file( "components/untyped.cpp" ); - CodeBody etoktype = gen_etoktype( "enums/ETokType.csv", "enums/AttributeTokens.csv" ); + CodeBody etoktype = gen_etoktype( "enums/ETokType.csv", "enums/AttributeTokens.csv" ); CodeNamespace parser_nspace = def_namespace( name(Parser), def_namespace_body( args(etoktype)) ); - // TODO : Make this optional to include + Builder + src = Builder::open( "gen/gen.cpp" ); + src.print_fmt( generation_notice ); + src.print( push_ignores ); + src.print( src_start ); + src.print( header ); + src.print_fmt( "\nGEN_NS_BEGIN\n\n"); + + src.print( data ); + src.print( ast_case_macros ); + src.print( ast ); + src.print( interface ); + src.print( upfront ); + src.print( parser_nspace ); + src.print( parsing ); + src.print( untyped ); + + src.print_fmt( "GEN_NS_END\n\n"); + src.print( pop_ignores ); + src.write(); + } + + // gen_builder.hpp + { + Code parsing = scan_file( "dependencies/parsing.hpp" ); + Code builder = scan_file( "file_processors/builder.hpp" ); + + Builder + header = Builder::open( "gen/gen_builder.hpp" ); + header.print_fmt( generation_notice ); + header.print( def_include( txt_StrC("gen.hpp") )); + header.print_fmt( "\nGEN_NS_BEGIN\n\n" ); + header.print( parsing ); + header.print( builder ); + header.print_fmt( "\nGEN_NS_END\n\n" ); + header.write(); + } + + // gen_builder.cpp + { + Code parsing = scan_file( "dependencies/parsing.cpp" ); Code builder = scan_file( "file_processors/builder.cpp" ); Builder - impl; - impl.open( "gen/gen.cpp" ); - impl.print( push_ignores ); - impl.print( impl_start ); - impl.print( header ); - impl.print_fmt( "\nGEN_NS_BEGIN\n\n"); - - impl.print( data ); - impl.print( ast_case_macros ); - impl.print( ast ); - impl.print( interface ); - impl.print( upfront ); - impl.print( parser_nspace ); - impl.print( parsing ); - impl.print( untyped ); - - impl.print( builder ); - impl.print_fmt( "GEN_NS_END\n\n"); - impl.print( pop_ignores ); - impl.write(); + src = Builder::open( "gen/gen_builder.cpp" ); + src.print( def_include( txt_StrC("gen_builder.hpp") ) ); + src.print_fmt( "\nGEN_NS_BEGIN\n\n" ); + src.print( parsing ); + src.print( builder ); + src.print_fmt( "\nGEN_NS_END\n\n" ); + src.write(); } gen::deinit(); diff --git a/project/gen.cpp b/project/gen.cpp index a71f597..42eb09b 100644 --- a/project/gen.cpp +++ b/project/gen.cpp @@ -23,12 +23,10 @@ GEN_NS_BEGIN #include "components/interface.cpp" #include "components/interface.upfront.cpp" -#include "components/etoktype.cpp" +#include "components/temp/etoktype.cpp" #include "components/interface.parsing.cpp" #include "components/untyped.cpp" -#include "file_processors/builder.cpp" - GEN_NS_END #include "helpers/pop_ignores.inline.hpp" diff --git a/project/gen.dep.cpp b/project/gen.dep.cpp index e7b4f92..3945bbb 100644 --- a/project/gen.dep.cpp +++ b/project/gen.dep.cpp @@ -1,17 +1,19 @@ // This file is intended to be included within gen.cpp (There is no pragma diagnostic ignores) #include "gen.dep.hpp" -#include "dependencies/impl_start.cpp" +#include "dependencies/src_start.cpp" GEN_NS_BEGIN #include "dependencies/debug.cpp" + #include "dependencies/string_ops.cpp" #include "dependencies/printing.cpp" #include "dependencies/memory.cpp" -#include "dependencies/parsing.cpp" + #include "dependencies/hashing.cpp" #include "dependencies/string.cpp" + #include "dependencies/timing.cpp" #include "dependencies/file_handling.cpp" diff --git a/project/gen.dep.hpp b/project/gen.dep.hpp index 0e0ae16..e7b9bbd 100644 --- a/project/gen.dep.hpp +++ b/project/gen.dep.hpp @@ -3,26 +3,20 @@ #include "dependencies/header_start.hpp" -#ifdef GEN_DONT_USE_NAMESPACE -# define GEN_NS_BEGIN -# define GEN_NS_END -#else -# define GEN_NS_BEGIN namespace gen { -# define GEN_NS_END } -#endif - GEN_NS_BEGIN #include "dependencies/macros.hpp" #include "dependencies/basic_types.hpp" #include "dependencies/debug.hpp" + #include "dependencies/memory.hpp" #include "dependencies/string_ops.hpp" #include "dependencies/printing.hpp" + #include "dependencies/containers.hpp" #include "dependencies/hashing.hpp" #include "dependencies/string.hpp" -#include "dependencies/parsing.hpp" + #include "dependencies/timing.hpp" #include "dependencies/file_handling.hpp" diff --git a/project/gen.hpp b/project/gen.hpp index e3abc5b..b7158f3 100644 --- a/project/gen.hpp +++ b/project/gen.hpp @@ -11,25 +11,21 @@ #include "helpers/push_ignores.inline.hpp" #include "components/header_start.hpp" -#ifdef GEN_DONT_USE_NAMESPACE -# define GEN_NS_BEGIN -# define GEN_NS_END -#else -# define GEN_NS_BEGIN namespace gen { -# define GEN_NS_END } -#endif - GEN_NS_BEGIN #include "components/types.hpp" -#include "components/ecode.hpp" -#include "components/eoperator.hpp" -#include "components/especifier.hpp" -#include "components/data_structures.hpp" -#include "components/interface.hpp" -#include "components/header_end.hpp" +#include "components/temp/ecode.hpp" +#include "components/temp/eoperator.hpp" +#include "components/temp/especifier.hpp" -#include "file_processors/builder.hpp" +#include "components/ast.hpp" +#include "components/ast_types.hpp" + +#include "components/interface.hpp" + +#include "components/inlines.hpp" +#include "components/temp/ast_inlines.hpp" +#include "components/header_end.hpp" GEN_NS_END diff --git a/project/gen/gen_builder.cpp b/project/gen/gen_builder.cpp new file mode 100644 index 0000000..b727689 --- /dev/null +++ b/project/gen/gen_builder.cpp @@ -0,0 +1,1159 @@ +#include "gen_builder.hpp" + +GEN_NS_BEGIN + +#pragma region ADT + +#define _adt_fprintf( s_, fmt_, ... ) \ + do \ + { \ + if ( str_fmt_file( s_, fmt_, ##__VA_ARGS__ ) < 0 ) \ + return EADT_ERROR_OUT_OF_MEMORY; \ + } while ( 0 ) + +u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32 is_array ) +{ + ADT_Type type = EADT_TYPE_OBJECT; + if ( is_array ) + type = EADT_TYPE_ARRAY; + + ADT_Node* parent = node->parent; + zero_item( node ); + + node->type = type; + node->name = name; + node->parent = parent; + node->nodes = Array< ADT_Node >::init( backing ); + + if ( ! node->nodes ) + return EADT_ERROR_OUT_OF_MEMORY; + + return 0; +} + +u8 adt_destroy_branch( ADT_Node* node ) +{ + GEN_ASSERT_NOT_NULL( node ); + if ( ( node->type == EADT_TYPE_OBJECT || node->type == EADT_TYPE_ARRAY ) && node->nodes ) + { + for ( sw i = 0; i < node->nodes.num(); ++i ) + { + adt_destroy_branch( node->nodes + i ); + } + + node->nodes.free(); + } + return 0; +} + +u8 adt_make_leaf( ADT_Node* node, char const* name, ADT_Type type ) +{ + GEN_ASSERT( type != EADT_TYPE_OBJECT && type != EADT_TYPE_ARRAY ); + + ADT_Node* parent = node->parent; + zero_item( node ); + + node->type = type; + node->name = name; + node->parent = parent; + return 0; +} + +ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ) +{ + if ( node->type != EADT_TYPE_OBJECT ) + { + return NULL; + } + + for ( sw i = 0; i < node->nodes.num(); i++ ) + { + if ( ! str_compare( node->nodes[ i ].name, name ) ) + { + return ( node->nodes + i ); + } + } + + if ( deep_search ) + { + for ( sw i = 0; i < node->nodes.num(); i++ ) + { + ADT_Node* res = adt_find( node->nodes + i, name, deep_search ); + + if ( res != NULL ) + return res; + } + } + + return NULL; +} + +internal ADT_Node* _adt_get_value( ADT_Node* node, char const* value ) +{ + switch ( node->type ) + { + case EADT_TYPE_MULTISTRING : + case EADT_TYPE_STRING : + { + if ( node->string && ! str_compare( node->string, value ) ) + { + return node; + } + } + break; + case EADT_TYPE_INTEGER : + case EADT_TYPE_REAL : + { + char back[ 4096 ] = { 0 }; + FileInfo tmp; + + /* allocate a file descriptor for a memory-mapped number to string conversion, input source buffer is not cloned, however. */ + file_stream_open( &tmp, heap(), ( u8* )back, size_of( back ), EFileStream_WRITABLE ); + adt_print_number( &tmp, node ); + + sw fsize = 0; + u8* buf = file_stream_buf( &tmp, &fsize ); + + if ( ! str_compare( ( char const* )buf, value ) ) + { + file_close( &tmp ); + return node; + } + + file_close( &tmp ); + } + break; + default : + break; /* node doesn't support value based lookup */ + } + + return NULL; +} + +internal ADT_Node* _adt_get_field( ADT_Node* node, char* name, char* value ) +{ + for ( sw i = 0; i < node->nodes.num(); i++ ) + { + if ( ! str_compare( node->nodes[ i ].name, name ) ) + { + ADT_Node* child = &node->nodes[ i ]; + if ( _adt_get_value( child, value ) ) + { + return node; /* this object does contain a field of a specified value! */ + } + } + } + + return NULL; +} + +ADT_Node* adt_query( ADT_Node* node, char const* uri ) +{ + GEN_ASSERT_NOT_NULL( uri ); + + if ( *uri == '/' ) + { + uri++; + } + + if ( *uri == 0 ) + { + return node; + } + + if ( ! node || ( node->type != EADT_TYPE_OBJECT && node->type != EADT_TYPE_ARRAY ) ) + { + return NULL; + } + +#if defined EADT_URI_DEBUG || 0 + str_fmt_out( "uri: %s\n", uri ); +#endif + + char * p = ( char* )uri, *b = p, *e = p; + ADT_Node* found_node = NULL; + + b = p; + p = e = ( char* )str_skip( p, '/' ); + char* buf = str_fmt_buf( "%.*s", ( int )( e - b ), b ); + + /* handle field value lookup */ + if ( *b == '[' ) + { + char *l_p = buf + 1, *l_b = l_p, *l_e = l_p, *l_b2 = l_p, *l_e2 = l_p; + l_e = ( char* )str_skip( l_p, '=' ); + l_e2 = ( char* )str_skip( l_p, ']' ); + + if ( ( ! *l_e && node->type != EADT_TYPE_ARRAY ) || ! *l_e2 ) + { + GEN_ASSERT_MSG( 0, "Invalid field value lookup" ); + return NULL; + } + + *l_e2 = 0; + + /* [field=value] */ + if ( *l_e ) + { + *l_e = 0; + l_b2 = l_e + 1; + + /* run a value comparison against our own fields */ + if ( node->type == EADT_TYPE_OBJECT ) + { + found_node = _adt_get_field( node, l_b, l_b2 ); + } + + /* run a value comparison against any child that is an object node */ + else if ( node->type == EADT_TYPE_ARRAY ) + { + for ( sw i = 0; i < node->nodes.num(); i++ ) + { + ADT_Node* child = &node->nodes[ i ]; + if ( child->type != EADT_TYPE_OBJECT ) + { + continue; + } + + found_node = _adt_get_field( child, l_b, l_b2 ); + + if ( found_node ) + break; + } + } + } + /* [value] */ + else + { + for ( sw i = 0; i < node->nodes.num(); i++ ) + { + ADT_Node* child = &node->nodes[ i ]; + if ( _adt_get_value( child, l_b2 ) ) + { + found_node = child; + break; /* we found a matching value in array, ignore the rest of it */ + } + } + } + + /* go deeper if uri continues */ + if ( *e ) + { + return adt_query( found_node, e + 1 ); + } + } + /* handle field name lookup */ + else if ( node->type == EADT_TYPE_OBJECT ) + { + found_node = adt_find( node, buf, false ); + + /* go deeper if uri continues */ + if ( *e ) + { + return adt_query( found_node, e + 1 ); + } + } + /* handle array index lookup */ + else + { + sw idx = ( sw )str_to_i64( buf, NULL, 10 ); + if ( idx >= 0 && idx < node->nodes.num() ) + { + found_node = &node->nodes[ idx ]; + + /* go deeper if uri continues */ + if ( *e ) + { + return adt_query( found_node, e + 1 ); + } + } + } + + return found_node; +} + +ADT_Node* adt_alloc_at( ADT_Node* parent, sw index ) +{ + if ( ! parent || ( parent->type != EADT_TYPE_OBJECT && parent->type != EADT_TYPE_ARRAY ) ) + { + return NULL; + } + + if ( ! parent->nodes ) + return NULL; + + if ( index < 0 || index > parent->nodes.num() ) + return NULL; + + ADT_Node o = { 0 }; + o.parent = parent; + if ( ! parent->nodes.append_at( o, index ) ) + return NULL; + + return parent->nodes + index; +} + +ADT_Node* adt_alloc( ADT_Node* parent ) +{ + if ( ! parent || ( parent->type != EADT_TYPE_OBJECT && parent->type != EADT_TYPE_ARRAY ) ) + { + return NULL; + } + + if ( ! parent->nodes ) + return NULL; + + return adt_alloc_at( parent, parent->nodes.num() ); +} + +b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing ) +{ + return adt_make_branch( obj, backing, name, 0 ); +} + +b8 adt_set_arr( ADT_Node* obj, char const* name, AllocatorInfo backing ) +{ + return adt_make_branch( obj, backing, name, 1 ); +} + +b8 adt_set_str( ADT_Node* obj, char const* name, char const* value ) +{ + adt_make_leaf( obj, name, EADT_TYPE_STRING ); + obj->string = value; + return true; +} + +b8 adt_set_flt( ADT_Node* obj, char const* name, f64 value ) +{ + adt_make_leaf( obj, name, EADT_TYPE_REAL ); + obj->real = value; + return true; +} + +b8 adt_set_int( ADT_Node* obj, char const* name, s64 value ) +{ + adt_make_leaf( obj, name, EADT_TYPE_INTEGER ); + obj->integer = value; + return true; +} + +ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, sw index ) +{ + GEN_ASSERT_NOT_NULL( node ); + GEN_ASSERT_NOT_NULL( new_parent ); + ADT_Node* old_parent = node->parent; + ADT_Node* new_node = adt_alloc_at( new_parent, index ); + *new_node = *node; + new_node->parent = new_parent; + if ( old_parent ) + { + adt_remove_node( node ); + } + return new_node; +} + +ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent ) +{ + GEN_ASSERT_NOT_NULL( node ); + GEN_ASSERT_NOT_NULL( new_parent ); + GEN_ASSERT( new_parent->type == EADT_TYPE_ARRAY || new_parent->type == EADT_TYPE_OBJECT ); + return adt_move_node_at( node, new_parent, new_parent->nodes.num() ); +} + +void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ) +{ + GEN_ASSERT_NOT_NULL( node ); + GEN_ASSERT_NOT_NULL( other_node ); + ADT_Node* parent = node->parent; + ADT_Node* other_parent = other_node->parent; + sw index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); + sw index2 = ( pointer_diff( other_parent->nodes, other_node ) / size_of( ADT_Node ) ); + ADT_Node temp = parent->nodes[ index ]; + temp.parent = other_parent; + other_parent->nodes[ index2 ].parent = parent; + parent->nodes[ index ] = other_parent->nodes[ index2 ]; + other_parent->nodes[ index2 ] = temp; +} + +void adt_remove_node( ADT_Node* node ) +{ + GEN_ASSERT_NOT_NULL( node ); + GEN_ASSERT_NOT_NULL( node->parent ); + ADT_Node* parent = node->parent; + sw index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); + parent->nodes.remove_at( index ); +} + +ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ) +{ + ADT_Node* o = adt_alloc( parent ); + if ( ! o ) + return NULL; + if ( adt_set_obj( o, name, parent->nodes.get_header()->Allocator ) ) + { + adt_remove_node( o ); + return NULL; + } + return o; +} + +ADT_Node* adt_append_arr( ADT_Node* parent, char const* name ) +{ + ADT_Node* o = adt_alloc( parent ); + if ( ! o ) + return NULL; + if ( adt_set_arr( o, name, parent->nodes.get_header()->Allocator ) ) + { + adt_remove_node( o ); + return NULL; + } + return o; +} + +ADT_Node* adt_append_str( ADT_Node* parent, char const* name, char const* value ) +{ + ADT_Node* o = adt_alloc( parent ); + if ( ! o ) + return NULL; + adt_set_str( o, name, value ); + return o; +} + +ADT_Node* adt_append_flt( ADT_Node* parent, char const* name, f64 value ) +{ + ADT_Node* o = adt_alloc( parent ); + if ( ! o ) + return NULL; + adt_set_flt( o, name, value ); + return o; +} + +ADT_Node* adt_append_int( ADT_Node* parent, char const* name, s64 value ) +{ + ADT_Node* o = adt_alloc( parent ); + if ( ! o ) + return NULL; + adt_set_int( o, name, value ); + return o; +} + +/* parser helpers */ +char* adt_parse_number_strict( ADT_Node* node, char* base_str ) +{ + GEN_ASSERT_NOT_NULL( node ); + GEN_ASSERT_NOT_NULL( base_str ); + char *p = base_str, *e = p; + + while ( *e ) + ++e; + + while ( *p && ( str_find( "eE.+-", *p ) || char_is_hex_digit( *p ) ) ) + { + ++p; + } + + if ( p >= e ) + { + return adt_parse_number( node, base_str ); + } + + return base_str; +} + +char* adt_parse_number( ADT_Node* node, char* base_str ) +{ + GEN_ASSERT_NOT_NULL( node ); + GEN_ASSERT_NOT_NULL( base_str ); + char *p = base_str, *e = p; + + s32 base = 0; + s32 base2 = 0; + u8 base2_offset = 0; + s8 exp = 0, orig_exp = 0; + u8 neg_zero = 0; + u8 lead_digit = 0; + ADT_Type node_type = EADT_TYPE_UNINITIALISED; + u8 node_props = 0; + + /* skip false positives and special cases */ + if ( ! ! str_find( "eE", *p ) || ( ! ! str_find( ".+-", *p ) && ! char_is_hex_digit( *( p + 1 ) ) && *( p + 1 ) != '.' ) ) + { + return ++base_str; + } + + node_type = EADT_TYPE_INTEGER; + neg_zero = false; + + sw ib = 0; + char buf[ 48 ] = { 0 }; + + if ( *e == '+' ) + ++e; + else if ( *e == '-' ) + { + buf[ ib++ ] = *e++; + } + + if ( *e == '.' ) + { + node_type = EADT_TYPE_REAL; + node_props = EADT_PROPS_IS_PARSED_REAL; + lead_digit = false; + buf[ ib++ ] = '0'; + do + { + buf[ ib++ ] = *e; + } while ( char_is_digit( *++e ) ); + } + else + { + if ( ! str_compare( e, "0x", 2 ) || ! str_compare( e, "0X", 2 ) ) + { + node_props = EADT_PROPS_IS_HEX; + } + + /* bail if ZPL_ADT_PROPS_IS_HEX is unset but we get 'x' on input */ + if ( char_to_lower( *e ) == 'x' && ( node_props != EADT_PROPS_IS_HEX ) ) + { + return ++base_str; + } + + while ( char_is_hex_digit( *e ) || char_to_lower( *e ) == 'x' ) + { + buf[ ib++ ] = *e++; + } + + if ( *e == '.' ) + { + node_type = EADT_TYPE_REAL; + lead_digit = true; + u32 step = 0; + + do + { + buf[ ib++ ] = *e; + ++step; + } while ( char_is_digit( *++e ) ); + + if ( step < 2 ) + { + buf[ ib++ ] = '0'; + } + } + } + + /* check if we have a dot here, this is a false positive (IP address, ...) */ + if ( *e == '.' ) + { + return ++base_str; + } + + f32 eb = 10; + char expbuf[ 6 ] = { 0 }; + sw expi = 0; + + if ( *e && ! ! str_find( "eE", *e ) ) + { + ++e; + if ( *e == '+' || *e == '-' || char_is_digit( *e ) ) + { + if ( *e == '-' ) + { + eb = 0.1f; + } + if ( ! char_is_digit( *e ) ) + { + ++e; + } + while ( char_is_digit( *e ) ) + { + expbuf[ expi++ ] = *e++; + } + } + + orig_exp = exp = ( u8 )str_to_i64( expbuf, NULL, 10 ); + } + + if ( node_type == EADT_TYPE_INTEGER ) + { + node->integer = str_to_i64( buf, 0, 0 ); +#ifndef GEN_PARSER_DISABLE_ANALYSIS + /* special case: negative zero */ + if ( node->integer == 0 && buf[ 0 ] == '-' ) + { + neg_zero = true; + } +#endif + while ( orig_exp-- > 0 ) + { + node->integer *= ( s64 )eb; + } + } + else + { + node->real = str_to_f64( buf, 0 ); + +#ifndef GEN_PARSER_DISABLE_ANALYSIS + char *q = buf, *base_string = q, *base_string2 = q; + base_string = zpl_cast( char* ) str_skip( base_string, '.' ); + *base_string = '\0'; + base_string2 = base_string + 1; + char* base_string_off = base_string2; + while ( *base_string_off++ == '0' ) + base2_offset++; + + base = ( s32 )str_to_i64( q, 0, 0 ); + base2 = ( s32 )str_to_i64( base_string2, 0, 0 ); + if ( exp ) + { + exp = exp * ( ! ( eb == 10.0f ) ? -1 : 1 ); + node_props = EADT_PROPS_IS_EXP; + } + + /* special case: negative zero */ + if ( base == 0 && buf[ 0 ] == '-' ) + { + neg_zero = true; + } +#endif + while ( orig_exp-- > 0 ) + { + node->real *= eb; + } + } + + node->type = node_type; + node->props = node_props; + +#ifndef GEN_PARSER_DISABLE_ANALYSIS + node->base = base; + node->base2 = base2; + node->base2_offset = base2_offset; + node->exp = exp; + node->neg_zero = neg_zero; + node->lead_digit = lead_digit; +#else + unused( base ); + unused( base2 ); + unused( base2_offset ); + unused( exp ); + unused( neg_zero ); + unused( lead_digit ); +#endif + return e; +} + +ADT_Error adt_print_number( FileInfo* file, ADT_Node* node ) +{ + GEN_ASSERT_NOT_NULL( file ); + GEN_ASSERT_NOT_NULL( node ); + if ( node->type != EADT_TYPE_INTEGER && node->type != EADT_TYPE_REAL ) + { + return EADT_ERROR_INVALID_TYPE; + } + +#ifndef GEN_PARSER_DISABLE_ANALYSIS + if ( node->neg_zero ) + { + _adt_fprintf( file, "-" ); + } +#endif + + switch ( node->type ) + { + case EADT_TYPE_INTEGER : + { + if ( node->props == EADT_PROPS_IS_HEX ) + { + _adt_fprintf( file, "0x%llx", ( long long )node->integer ); + } + else + { + _adt_fprintf( file, "%lld", ( long long )node->integer ); + } + } + break; + + case EADT_TYPE_REAL : + { + if ( node->props == EADT_PROPS_NAN ) + { + _adt_fprintf( file, "NaN" ); + } + else if ( node->props == EADT_PROPS_NAN_NEG ) + { + _adt_fprintf( file, "-NaN" ); + } + else if ( node->props == EADT_PROPS_INFINITY ) + { + _adt_fprintf( file, "Infinity" ); + } + else if ( node->props == EADT_PROPS_INFINITY_NEG ) + { + _adt_fprintf( file, "-Infinity" ); + } + else if ( node->props == EADT_PROPS_TRUE ) + { + _adt_fprintf( file, "true" ); + } + else if ( node->props == EADT_PROPS_FALSE ) + { + _adt_fprintf( file, "false" ); + } + else if ( node->props == EADT_PROPS_NULL ) + { + _adt_fprintf( file, "null" ); +#ifndef GEN_PARSER_DISABLE_ANALYSIS + } + else if ( node->props == EADT_PROPS_IS_EXP ) + { + _adt_fprintf( file, "%lld.%0*d%llde%lld", ( long long )node->base, node->base2_offset, 0, ( long long )node->base2, ( long long )node->exp ); + } + else if ( node->props == EADT_PROPS_IS_PARSED_REAL ) + { + if ( ! node->lead_digit ) + _adt_fprintf( file, ".%0*d%lld", node->base2_offset, 0, ( long long )node->base2 ); + else + _adt_fprintf( file, "%lld.%0*d%lld", ( long long int )node->base2_offset, 0, ( int )node->base, ( long long )node->base2 ); +#endif + } + else + { + _adt_fprintf( file, "%f", node->real ); + } + } + break; + } + + return EADT_ERROR_NONE; +} + +ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_chars, char const* escape_symbol ) +{ + GEN_ASSERT_NOT_NULL( file ); + GEN_ASSERT_NOT_NULL( node ); + GEN_ASSERT_NOT_NULL( escaped_chars ); + if ( node->type != EADT_TYPE_STRING && node->type != EADT_TYPE_MULTISTRING ) + { + return EADT_ERROR_INVALID_TYPE; + } + + /* escape string */ + char const *p = node->string, *b = p; + + if ( ! p ) + return EADT_ERROR_NONE; + + do + { + p = str_skip_any( p, escaped_chars ); + _adt_fprintf( file, "%.*s", pointer_diff( b, p ), b ); + if ( *p && ! ! str_find( escaped_chars, *p ) ) + { + _adt_fprintf( file, "%s%c", escape_symbol, *p ); + p++; + } + b = p; + } while ( *p ); + + return EADT_ERROR_NONE; +} + +ADT_Error adt_str_to_number( ADT_Node* node ) +{ + GEN_ASSERT( node ); + + if ( node->type == EADT_TYPE_REAL || node->type == EADT_TYPE_INTEGER ) + return EADT_ERROR_ALREADY_CONVERTED; /* this is already converted/parsed */ + if ( node->type != EADT_TYPE_STRING && node->type != EADT_TYPE_MULTISTRING ) + { + return EADT_ERROR_INVALID_TYPE; + } + + adt_parse_number( node, ( char* )node->string ); + + return EADT_ERROR_NONE; +} + +ADT_Error adt_str_to_number_strict( ADT_Node* node ) +{ + GEN_ASSERT( node ); + + if ( node->type == EADT_TYPE_REAL || node->type == EADT_TYPE_INTEGER ) + return EADT_ERROR_ALREADY_CONVERTED; /* this is already converted/parsed */ + if ( node->type != EADT_TYPE_STRING && node->type != EADT_TYPE_MULTISTRING ) + { + return EADT_ERROR_INVALID_TYPE; + } + + adt_parse_number_strict( node, ( char* )node->string ); + + return EADT_ERROR_NONE; +} + +#undef _adt_fprintf + +#pragma endregion ADT + +#pragma region CSV + +#ifdef GEN_CSV_DEBUG +# define GEN_CSV_ASSERT( msg ) GEN_PANIC( msg ) +#else +# define GEN_CSV_ASSERT( msg ) +#endif + + +u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim ) +{ + CSV_Error error = ECSV_Error__NONE; + GEN_ASSERT_NOT_NULL( root ); + GEN_ASSERT_NOT_NULL( text ); + zero_item( root ); + + adt_make_branch( root, allocator, NULL, has_header ? false : true ); + + char* currentChar = text; + char* beginChar; + char* endChar; + + sw columnIndex = 0; + sw totalColumnIndex = 0; + + do + { + char delimiter = 0; + currentChar = zpl_cast( char* ) str_trim( currentChar, false ); + + if ( *currentChar == 0 ) + break; + + ADT_Node rowItem = { 0 }; + rowItem.type = EADT_TYPE_STRING; + +#ifndef GEN_PARSER_DISABLE_ANALYSIS + rowItem.name_style = EADT_NAME_STYLE_NO_QUOTES; +#endif + + /* handle string literals */ + if ( *currentChar == '"' ) + { + currentChar += 1; + beginChar = currentChar; + endChar = currentChar; + rowItem.string = beginChar; +#ifndef GEN_PARSER_DISABLE_ANALYSIS + rowItem.name_style = EADT_NAME_STYLE_DOUBLE_QUOTE; +#endif + do + { + endChar = zpl_cast( char* ) str_skip( endChar, '"' ); + + if ( *endChar && *( endChar + 1 ) == '"' ) + { + endChar += 2; + } + else + break; + } while ( *endChar ); + + if ( *endChar == 0 ) + { + GEN_CSV_ASSERT( "unmatched quoted string" ); + error = ECSV_Error__UNEXPECTED_END_OF_INPUT; + return error; + } + + *endChar = 0; + currentChar = zpl_cast( char* ) str_trim( endChar + 1, true ); + delimiter = *currentChar; + + /* unescape escaped quotes (so that unescaped text escapes :) */ + { + char* escapedChar = beginChar; + do + { + if ( *escapedChar == '"' && *( escapedChar + 1 ) == '"' ) + { + mem_move( escapedChar, escapedChar + 1, str_len( escapedChar ) ); + } + escapedChar++; + } while ( *escapedChar ); + } + } + else if ( *currentChar == delim ) + { + delimiter = *currentChar; + rowItem.string = ""; + } + else if ( *currentChar ) + { + /* regular data */ + beginChar = currentChar; + endChar = currentChar; + rowItem.string = beginChar; + + do + { + endChar++; + } while ( *endChar && *endChar != delim && *endChar != '\n' ); + + if ( *endChar ) + { + currentChar = zpl_cast( char* ) str_trim( endChar, true ); + + while ( char_is_space( *( endChar - 1 ) ) ) + { + endChar--; + } + + delimiter = *currentChar; + *endChar = 0; + } + else + { + delimiter = 0; + currentChar = endChar; + } + + /* check if number and process if so */ + b32 skip_number = false; + char* num_p = beginChar; + + // We only consider hexadecimal values if they start with 0x + if ( str_len( num_p ) > 2 && num_p[ 0 ] == '0' && ( num_p[ 1 ] == 'x' || num_p[ 1 ] == 'X' ) ) + { + num_p += 2; // skip '0x' prefix + do + { + if ( ! char_is_hex_digit( *num_p ) ) + { + skip_number = true; + break; + } + } while ( *num_p++ ); + } + else + { + skip_number = true; + } + + if ( ! skip_number ) + { + adt_str_to_number( &rowItem ); + } + } + + if ( columnIndex >= root->nodes.num() ) + { + adt_append_arr( root, NULL ); + } + + root->nodes[ columnIndex ].nodes.append( rowItem ); + + if ( delimiter == delim ) + { + columnIndex++; + currentChar++; + } + else if ( delimiter == '\n' || delimiter == 0 ) + { + /* check if number of rows is not mismatched */ + if ( totalColumnIndex < columnIndex ) + totalColumnIndex = columnIndex; + + else if ( totalColumnIndex != columnIndex ) + { + GEN_CSV_ASSERT( "mismatched rows" ); + error = ECSV_Error__MISMATCHED_ROWS; + return error; + } + + columnIndex = 0; + + if ( delimiter != 0 ) + currentChar++; + } + } while ( *currentChar ); + + if ( root->nodes.num() == 0 ) + { + GEN_CSV_ASSERT( "unexpected end of input. stream is empty." ); + error = ECSV_Error__UNEXPECTED_END_OF_INPUT; + return error; + } + + /* consider first row as a header. */ + if ( has_header ) + { + for ( sw i = 0; i < root->nodes.num(); i++ ) + { + CSV_Object* col = root->nodes + i; + CSV_Object* hdr = col->nodes; + col->name = hdr->string; + col->nodes.remove_at( 0 ); + } + } + + return error; +} + +void csv_free( CSV_Object* obj ) +{ + adt_destroy_branch( obj ); +} + +void _csv_write_record( FileInfo* file, CSV_Object* node ) +{ + switch ( node->type ) + { + case EADT_TYPE_STRING : + { +#ifndef GEN_PARSER_DISABLE_ANALYSIS + switch ( node->name_style ) + { + case EADT_NAME_STYLE_DOUBLE_QUOTE : + { + str_fmt_file( file, "\"" ); + adt_print_string( file, node, "\"", "\"" ); + str_fmt_file( file, "\"" ); + } + break; + + case EADT_NAME_STYLE_NO_QUOTES : + { +#endif + str_fmt_file( file, "%s", node->string ); +#ifndef GEN_PARSER_DISABLE_ANALYSIS + } + break; + } +#endif + } + break; + + case EADT_TYPE_REAL : + case EADT_TYPE_INTEGER : + { + adt_print_number( file, node ); + } + break; + } +} + +void _csv_write_header( FileInfo* file, CSV_Object* header ) +{ + CSV_Object temp = *header; + temp.string = temp.name; + temp.type = EADT_TYPE_STRING; + _csv_write_record( file, &temp ); +} + +void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delimiter ) +{ + GEN_ASSERT_NOT_NULL( file ); + GEN_ASSERT_NOT_NULL( obj ); + GEN_ASSERT( obj->nodes ); + sw cols = obj->nodes.num(); + if ( cols == 0 ) + return; + + sw rows = obj->nodes[ 0 ].nodes.num(); + if ( rows == 0 ) + return; + + b32 has_headers = obj->nodes[ 0 ].name != NULL; + + if ( has_headers ) + { + for ( sw i = 0; i < cols; i++ ) + { + _csv_write_header( file, &obj->nodes[ i ] ); + if ( i + 1 != cols ) + { + str_fmt_file( file, "%c", delimiter ); + } + } + str_fmt_file( file, "\n" ); + } + + for ( sw r = 0; r < rows; r++ ) + { + for ( sw i = 0; i < cols; i++ ) + { + _csv_write_record( file, &obj->nodes[ i ].nodes[ r ] ); + if ( i + 1 != cols ) + { + str_fmt_file( file, "%c", delimiter ); + } + } + str_fmt_file( file, "\n" ); + } +} + +String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delimiter ) +{ + FileInfo tmp; + file_stream_new( &tmp, a ); + csv_write_delimiter( &tmp, obj, delimiter ); + sw fsize; + u8* buf = file_stream_buf( &tmp, &fsize ); + String output = String::make_length( a, ( char* )buf, fsize ); + file_close( &tmp ); + return output; +} + +#pragma endregion CSV + +Builder Builder::open( char const* path ) +{ + Builder result; + + FileError error = file_open_mode( &result.File, EFileMode_WRITE, path ); + + if ( error != EFileError_NONE ) + { + log_failure( "gen::File::open - Could not open file: %s", path ); + return result; + } + + result.Buffer = String::make_reserve( GlobalAllocator, Builder_StrBufferReserve ); + + return result; +} + +void Builder::pad_lines( s32 num ) +{ + Buffer.append( "\n" ); +} + +void Builder::print( Code code ) +{ + Buffer.append( 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 ); +} + +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(); +} + +GEN_NS_END diff --git a/project/gen/gen_builder.hpp b/project/gen/gen_builder.hpp new file mode 100644 index 0000000..8512d39 --- /dev/null +++ b/project/gen/gen_builder.hpp @@ -0,0 +1,448 @@ +// This file was generated automatially by gen.bootstrap.cpp (See: https://github.com/Ed94/gencpp) + +#include "gen.hpp" + +GEN_NS_BEGIN + +#pragma region ADT + +enum ADT_Type : u32 +{ + EADT_TYPE_UNINITIALISED, /* node was not initialised, this is a programming error! */ + EADT_TYPE_ARRAY, + EADT_TYPE_OBJECT, + EADT_TYPE_STRING, + EADT_TYPE_MULTISTRING, + EADT_TYPE_INTEGER, + EADT_TYPE_REAL, +}; + +enum ADT_Props : u32 +{ + EADT_PROPS_NONE, + EADT_PROPS_NAN, + EADT_PROPS_NAN_NEG, + EADT_PROPS_INFINITY, + EADT_PROPS_INFINITY_NEG, + EADT_PROPS_FALSE, + EADT_PROPS_TRUE, + EADT_PROPS_NULL, + EADT_PROPS_IS_EXP, + EADT_PROPS_IS_HEX, + + // Used internally so that people can fill in real numbers they plan to write. + EADT_PROPS_IS_PARSED_REAL, +}; + +enum ADT_NamingStyle : u32 +{ + EADT_NAME_STYLE_DOUBLE_QUOTE, + EADT_NAME_STYLE_SINGLE_QUOTE, + EADT_NAME_STYLE_NO_QUOTES, +}; + +enum ADT_AssignStyle : u32 +{ + EADT_ASSIGN_STYLE_COLON, + EADT_ASSIGN_STYLE_EQUALS, + EADT_ASSIGN_STYLE_LINE, +}; + +enum ADT_DelimStyle : u32 +{ + EADT_DELIM_STYLE_COMMA, + EADT_DELIM_STYLE_LINE, + EADT_DELIM_STYLE_NEWLINE, +}; + +enum ADT_Error : u32 +{ + EADT_ERROR_NONE, + EADT_ERROR_INTERNAL, + EADT_ERROR_ALREADY_CONVERTED, + EADT_ERROR_INVALID_TYPE, + EADT_ERROR_OUT_OF_MEMORY, +}; + +struct ADT_Node +{ + char const* name; + struct ADT_Node* parent; + + /* properties */ + ADT_Type type : 4; + u8 props : 4; +#ifndef GEN_PARSER_DISABLE_ANALYSIS + u8 cfg_mode : 1; + u8 name_style : 2; + u8 assign_style : 2; + u8 delim_style : 2; + u8 delim_line_width : 4; + u8 assign_line_width : 4; +#endif + + /* adt data */ + union + { + char const* string; + Array< ADT_Node > nodes; ///< zpl_array + + struct + { + union + { + f64 real; + s64 integer; + }; + +#ifndef GEN_PARSER_DISABLE_ANALYSIS + /* number analysis */ + s32 base; + s32 base2; + u8 base2_offset : 4; + s8 exp : 4; + u8 neg_zero : 1; + u8 lead_digit : 1; +#endif + }; + }; +}; + +/* ADT NODE LIMITS + * delimiter and assignment segment width is limited to 128 whitespace symbols each. + * real number limits decimal position to 128 places. + * real number exponent is limited to 64 digits. + */ + +/** + * @brief Initialise an ADT object or array + * + * @param node + * @param backing Memory allocator used for descendants + * @param name Node's name + * @param is_array + * @return error code + */ +u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32 is_array ); + +/** + * @brief Destroy an ADT branch and its descendants + * + * @param node + * @return error code + */ +u8 adt_destroy_branch( ADT_Node* node ); + +/** + * @brief Initialise an ADT leaf + * + * @param node + * @param name Node's name + * @param type Node's type (use zpl_adt_make_branch for container nodes) + * @return error code + */ +u8 adt_make_leaf( ADT_Node* node, char const* name, ADT_Type type ); + + +/** + * @brief Fetch a node using provided URI string. + * + * This method uses a basic syntax to fetch a node from the ADT. The following features are available + * to retrieve the data: + * + * - "a/b/c" navigates through objects "a" and "b" to get to "c" + * - "arr/[foo=123]/bar" iterates over "arr" to find any object with param "foo" that matches the value "123", then gets its field called "bar" + * - "arr/3" retrieves the 4th element in "arr" + * - "arr/[apple]" retrieves the first element of value "apple" in "arr" + * + * @param node ADT node + * @param uri Locator string as described above + * @return zpl_adt_node* + * + * @see code/apps/examples/json_get.c + */ +ADT_Node* adt_query( ADT_Node* node, char const* uri ); + +/** + * @brief Find a field node within an object by the given name. + * + * @param node + * @param name + * @param deep_search Perform search recursively + * @return zpl_adt_node * node + */ +ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ); + +/** + * @brief Allocate an unitialised node within a container at a specified index. + * + * @param parent + * @param index + * @return zpl_adt_node * node + */ +ADT_Node* adt_alloc_at( ADT_Node* parent, sw index ); + +/** + * @brief Allocate an unitialised node within a container. + * + * @param parent + * @return zpl_adt_node * node + */ +ADT_Node* adt_alloc( ADT_Node* parent ); + +/** + * @brief Move an existing node to a new container at a specified index. + * + * @param node + * @param new_parent + * @param index + * @return zpl_adt_node * node + */ +ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, sw index ); + +/** + * @brief Move an existing node to a new container. + * + * @param node + * @param new_parent + * @return zpl_adt_node * node + */ +ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent ); + +/** + * @brief Swap two nodes. + * + * @param node + * @param other_node + * @return + */ +void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ); + +/** + * @brief Remove node from container. + * + * @param node + * @return + */ +void adt_remove_node( ADT_Node* node ); + +/** + * @brief Initialise a node as an object + * + * @param obj + * @param name + * @param backing + * @return + */ +b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing ); + +/** + * @brief Initialise a node as an array + * + * @param obj + * @param name + * @param backing + * @return + */ +b8 adt_set_arr( ADT_Node* obj, char const* name, AllocatorInfo backing ); + +/** + * @brief Initialise a node as a string + * + * @param obj + * @param name + * @param value + * @return + */ +b8 adt_set_str( ADT_Node* obj, char const* name, char const* value ); + +/** + * @brief Initialise a node as a float + * + * @param obj + * @param name + * @param value + * @return + */ +b8 adt_set_flt( ADT_Node* obj, char const* name, f64 value ); + +/** + * @brief Initialise a node as a signed integer + * + * @param obj + * @param name + * @param value + * @return + */ +b8 adt_set_int( ADT_Node* obj, char const* name, s64 value ); + +/** + * @brief Append a new node to a container as an object + * + * @param parent + * @param name + * @return* + */ +ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ); + +/** + * @brief Append a new node to a container as an array + * + * @param parent + * @param name + * @return* + */ +ADT_Node* adt_append_arr( ADT_Node* parent, char const* name ); + +/** + * @brief Append a new node to a container as a string + * + * @param parent + * @param name + * @param value + * @return* + */ +ADT_Node* adt_append_str( ADT_Node* parent, char const* name, char const* value ); + +/** + * @brief Append a new node to a container as a float + * + * @param parent + * @param name + * @param value + * @return* + */ +ADT_Node* adt_append_flt( ADT_Node* parent, char const* name, f64 value ); + +/** + * @brief Append a new node to a container as a signed integer + * + * @param parent + * @param name + * @param value + * @return* + */ +ADT_Node* adt_append_int( ADT_Node* parent, char const* name, s64 value ); + +/* parser helpers */ + +/** + * @brief Parses a text and stores the result into an unitialised node. + * + * @param node + * @param base + * @return* + */ +char* adt_parse_number( ADT_Node* node, char* base ); + +/** + * @brief Parses a text and stores the result into an unitialised node. + * This function expects the entire input to be a number. + * + * @param node + * @param base + * @return* + */ +char* adt_parse_number_strict( ADT_Node* node, char* base_str ); + +/** + * @brief Parses and converts an existing string node into a number. + * + * @param node + * @return + */ +ADT_Error adt_str_to_number( ADT_Node* node ); + +/** + * @brief Parses and converts an existing string node into a number. + * This function expects the entire input to be a number. + * + * @param node + * @return + */ +ADT_Error adt_str_to_number_strict( ADT_Node* node ); + +/** + * @brief Prints a number into a file stream. + * + * The provided file handle can also be a memory mapped stream. + * + * @see zpl_file_stream_new + * @param file + * @param node + * @return + */ +ADT_Error adt_print_number( FileInfo* file, ADT_Node* node ); + +/** + * @brief Prints a string into a file stream. + * + * The provided file handle can also be a memory mapped stream. + * + * @see zpl_file_stream_new + * @param file + * @param node + * @param escaped_chars + * @param escape_symbol + * @return + */ +ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_chars, char const* escape_symbol ); + +#pragma endregion ADT + +#pragma region CSV + +enum CSV_Error : u32 +{ + ECSV_Error__NONE, + ECSV_Error__INTERNAL, + ECSV_Error__UNEXPECTED_END_OF_INPUT, + ECSV_Error__MISMATCHED_ROWS, +}; + +typedef ADT_Node CSV_Object; + +GEN_DEF_INLINE u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ); +u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim ); +void csv_free( CSV_Object* obj ); + +GEN_DEF_INLINE void csv_write( FileInfo* file, CSV_Object* obj ); +GEN_DEF_INLINE String csv_write_string( AllocatorInfo a, CSV_Object* obj ); +void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delim ); +String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delim ); + +/* inline */ + +GEN_IMPL_INLINE u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ) +{ + return csv_parse_delimiter( root, text, allocator, has_header, ',' ); +} + +GEN_IMPL_INLINE void csv_write( FileInfo* file, CSV_Object* obj ) +{ + csv_write_delimiter( file, obj, ',' ); +} + +GEN_IMPL_INLINE String csv_write_string( AllocatorInfo a, CSV_Object* obj ) +{ + return csv_write_string_delimiter( a, obj, ',' ); +} + +#pragma endregion CSV + +struct Builder +{ + FileInfo File; + String Buffer; + + static Builder open( char const* path ); + + void pad_lines( s32 num ); + + void print( Code ); + void print_fmt( char const* fmt, ... ); + + void write(); +}; + +GEN_NS_END diff --git a/project/helpers/helper.hpp b/project/helpers/helper.hpp index 2270899..e834481 100644 --- a/project/helpers/helper.hpp +++ b/project/helpers/helper.hpp @@ -2,6 +2,10 @@ #include "gen.hpp" +GEN_NS_BEGIN +#include "dependencies/parsing.hpp" +GEN_NS_END + using namespace gen; CodeBody gen_ecode( char const* path ) @@ -208,7 +212,7 @@ CodeBody gen_especifier( char const* path ) CodeBody gen_etoktype( char const* etok_path, char const* attr_path ) { - char scratch_mem[kilobytes(64)]; + char scratch_mem[kilobytes(16)]; Arena scratch = Arena::init_from_memory( scratch_mem, sizeof(scratch_mem) ); FileContents enum_content = file_read_contents( scratch, zero_terminate, etok_path ); @@ -226,10 +230,11 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path ) Array attribute_strs = csv_attr_nodes.nodes[0].nodes; Array attribute_str_strs = csv_attr_nodes.nodes[1].nodes; - String enum_entries = String::make_reserve( GlobalAllocator, kilobytes(2) ); - String to_str_entries = String::make_reserve( GlobalAllocator, kilobytes(4) ); - String attribute_entries = String::make_reserve( GlobalAllocator, kilobytes(2) ); - String to_str_attributes = String::make_reserve( GlobalAllocator, kilobytes(4) ); + String enum_entries = String::make_reserve( GlobalAllocator, kilobytes(2) ); + String to_str_entries = String::make_reserve( GlobalAllocator, kilobytes(4) ); + String attribute_entries = String::make_reserve( GlobalAllocator, kilobytes(2) ); + String to_str_attributes = String::make_reserve( GlobalAllocator, kilobytes(4) ); + String attribute_define_entries = String::make_reserve( GlobalAllocator, kilobytes(4) ); for (uw idx = 0; idx < enum_strs.num(); idx++) { @@ -247,8 +252,17 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path ) attribute_entries.append_fmt( "%s,\n", attribute_str ); to_str_attributes.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str); + attribute_define_entries.append_fmt( "Entry( %s, %s )", attribute_str, entry_to_str ); + + if ( idx < attribute_strs.num() - 1 ) + attribute_define_entries.append( " \\\n"); } +#pragma push_macro( "GEN_DEFINE_ATTRIBUTE_TOKENS" ) +#undef GEN_DEFINE_ATTRIBUTE_TOKENS + CodeDefine attribute_entires_def = def_define( name(GEN_DEFINE_ATTRIBUTE_TOKENS), attribute_define_entries ); +#pragma pop_macro( "GEN_DEFINE_ATTRIBUTE_TOKENS" ) + CodeEnum enum_code = parse_enum(token_fmt("entries", (StrC)enum_entries, "attribute_toks", (StrC)attribute_entries, stringize( enum Type : u32 { @@ -308,8 +322,13 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path ) #pragma pop_macro( "do_once_start" ) #pragma pop_macro( "do_once_end" ) - CodeNamespace nspace = def_namespace( name(ETokType), def_namespace_body( args( enum_code, to_str, to_type ) ) ); + CodeNamespace nspace = def_namespace( name(ETokType), def_namespace_body( args( attribute_entires_def, enum_code, to_str, to_type ) ) ); CodeUsing td_toktype = def_using( name(TokType), def_type( name(ETokType::Type) ) ); return def_global_body( args( nspace, td_toktype ) ); } + +CodeBody gen_data_structures( char const* data_path, char const* ast_path ) +{ + return CodeInvalid; +} diff --git a/scripts/.clang-format b/scripts/.clang-format index 3b57be7..5247aae 100644 --- a/scripts/.clang-format +++ b/scripts/.clang-format @@ -6,16 +6,22 @@ AlignAfterOpenBracket: BlockIndent AlignArrayOfStructures: Left AlignConsecutiveAssignments: Enabled: true - AcrossEmptyLines: false - AcrossComments: true + AcrossEmptyLines: true + AcrossComments: false AlignCompound: true PadOperators: true -AlignConsecutiveBitFields: AcrossComments -AlignConsecutiveDeclarations: AcrossComments +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false +AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false AlignConsecutiveMacros: Enabled: true AcrossEmptyLines: true - AcrossComments: true + AcrossComments: false AlignEscapedNewlines: Left AlignOperands: DontAlign @@ -62,7 +68,7 @@ BraceWrapping: BeforeWhile: false BreakAfterAttributes: Always -# BreakArrays: false +BreakArrays: true # BreakBeforeInlineASMColon: OnlyMultiline BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Allman @@ -73,7 +79,7 @@ BreakBeforeTernaryOperators: true BreakConstructorInitializers: BeforeComma BreakStringLiterals: true -ColumnLimit: 120 +ColumnLimit: 160 CompactNamespaces: true @@ -92,7 +98,6 @@ FixNamespaceComments: true IncludeBlocks: Preserve - IndentCaseBlocks: false IndentCaseLabels: true IndentExternBlock: AfterExternBlock @@ -128,7 +133,7 @@ SeparateDefinitionBlocks: Always ShortNamespaceLines: 40 SortIncludes: false -SortUsingDeclarations: true +SortUsingDeclarations: false SpaceAfterCStyleCast: false SpaceAfterLogicalNot: true diff --git a/scripts/bootstrap.ci.ps1 b/scripts/bootstrap.ci.ps1 index d75ff42..b895073 100644 --- a/scripts/bootstrap.ci.ps1 +++ b/scripts/bootstrap.ci.ps1 @@ -22,7 +22,7 @@ write-host "`n`nBuilding gencpp bootstrap`n" if ( -not( Test-Path $path_project_build) ) { -# Generate build files for meta-program +# Generate build files for bootstrap Push-Location $path_project $args_meson = @() $args_meson += "setup" @@ -32,7 +32,7 @@ Push-Location $path_project Pop-Location } -# Compile meta-program +# Compile bootstrap Push-Location $path_root $args_ninja = @() $args_ninja += "-C" @@ -42,29 +42,36 @@ Push-Location $path_root Pop-Location Push-location $path_project -if ( -not(Test-Path($path_project_gen) )) { - New-Item -ItemType Directory -Path $path_project_gen -} + if ( -not(Test-Path($path_project_gen) )) { + New-Item -ItemType Directory -Path $path_project_gen + } -# Run meta-program -$gencpp_bootstrap = Join-Path $path_project_build gencpp_bootstrap.exe + # Run bootstrap + $gencpp_bootstrap = Join-Path $path_project_build gencpp_bootstrap.exe -Write-Host `nRunning gencpp bootstrap... -& $gencpp_bootstrap + Write-Host `nRunning gencpp bootstrap... + & $gencpp_bootstrap -# Format generated files -Write-Host `nBeginning format... -$formatParams = @( - '-i' # In-place - '-style=file:../scripts/.clang-format' - '-verbose' -) + # Format generated gencpp + Write-Host `nBeginning format... + $formatParams = @( + '-i' # In-place + '-style=file:../scripts/.clang-format' + '-verbose' + ) -$include = @('gen.hpp', 'gen.cpp', 'gen_dep.hpp', 'gen_dep.cpp') -$exclude = $null + $include = @( + 'gen.hpp', 'gen.cpp', + 'gen_dep.hpp', 'gen_dep.cpp', + 'gen_builder.hpp', 'gen_builder.cpp' + ) + $exclude = $null -$targetFiles = @(Get-ChildItem -Recurse -Path $path_project_gen -Include $include -Exclude $exclude | Select-Object -ExpandProperty FullName) + $targetFiles = @(Get-ChildItem -Recurse -Path $path_project_gen -Include $include -Exclude $exclude | Select-Object -ExpandProperty FullName) -clang-format $formatParams $targetFiles -Write-Host "`nFormatting complete" + clang-format $formatParams $targetFiles + Write-Host "`nFormatting complete" Pop-Location + +# Build and run validation + diff --git a/scripts/singleheader.ci.ps1 b/scripts/singleheader.ci.ps1 index 0f84a66..0c1ec49 100644 --- a/scripts/singleheader.ci.ps1 +++ b/scripts/singleheader.ci.ps1 @@ -42,29 +42,32 @@ Push-Location $path_root Pop-Location Push-location $path_singleheader -if ( -not(Test-Path($path_singleheader_gen) )) { - New-Item -ItemType Directory -Path $path_singleheader_gen -} + if ( -not(Test-Path($path_singleheader_gen) )) { + New-Item -ItemType Directory -Path $path_singleheader_gen + } -# Run meta-program -$gencpp_singleheader = Join-Path $path_singleheader_build gencpp_singleheader.exe + # Run meta-program + $gencpp_singleheader = Join-Path $path_singleheader_build gencpp_singleheader.exe -Write-Host `nRunning gencpp singleheader... -& $gencpp_singleheader + Write-Host `nRunning gencpp singleheader... + & $gencpp_singleheader -# Format generated files -Write-Host `nBeginning format... -$formatParams = @( - '-i' # In-place - '-style=file:../scripts/.clang-format' - '-verbose' -) + # Format generated files + Write-Host `nBeginning format... + $formatParams = @( + '-i' # In-place + '-style=file:../scripts/.clang-format' + '-verbose' + ) -$include = @('gen.hpp') -$exclude = $null + $include = @('gen.hpp') + $exclude = $null -$targetFiles = @(Get-ChildItem -Recurse -Path $path_project -Include $include -Exclude $exclude | Select-Object -ExpandProperty FullName) + $targetFiles = @(Get-ChildItem -Recurse -Path $path_project -Include $include -Exclude $exclude | Select-Object -ExpandProperty FullName) -clang-format $formatParams $targetFiles -Write-Host "`nFormatting complete" + clang-format $formatParams $targetFiles + Write-Host "`nFormatting complete" Pop-Location + +# Build and run validation + diff --git a/scripts/test.gen_run.ps1 b/scripts/test.gen_run.ps1 index be5e9fe..68dd9d0 100644 --- a/scripts/test.gen_run.ps1 +++ b/scripts/test.gen_run.ps1 @@ -1,3 +1,5 @@ +cls + [string] $type = $null [string] $test = $false diff --git a/singleheader/components/header_start.hpp b/singleheader/components/header_start.hpp index 7a21966..fdee90c 100644 --- a/singleheader/components/header_start.hpp +++ b/singleheader/components/header_start.hpp @@ -11,4 +11,13 @@ */ #if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME) # error Gen.hpp : GEN_TIME not defined -#endif \ No newline at end of file +#endif + +#ifdef GEN_DONT_USE_NAMESPACE +# define GEN_NS_BEGIN +# define GEN_NS_END +#else +# define GEN_NS_BEGIN namespace gen { +# define GEN_NS_END } +#endif + diff --git a/singleheader/gen.singleheader.cpp b/singleheader/gen.singleheader.cpp index aff3cef..81240ed 100644 --- a/singleheader/gen.singleheader.cpp +++ b/singleheader/gen.singleheader.cpp @@ -7,27 +7,9 @@ using namespace gen; -bool namespace_by_default = true; - -constexpr StrC nspace_default = txt_StrC(R"( -#if defined(GEN_DONT_USE_NAMESPACE) && ! defined(GEN_NS_BEGIN) -# define GEN_NS_BEGIN -# define GEN_NS_END -#elif ! defined(GEN_NS_BEGIN) -# define GEN_NS_BEGIN namespace gen { -# define GEN_NS_END } -#endif -)"); - -constexpr StrC nspace_non_default = txt_StrC(R"( -#if ! defined(GEN_USE_NAMESPACE) && ! defined(GEN_NS_BEGIN) -# define GEN_NS_BEGIN -# define GEN_NS_END -#elif ! defined(GEN_NS_BEGIN) -# define GEN_NS_BEGIN namespace gen { -# define GEN_NS_END } -#endif -)"); +constexpr char const* generation_notice = +"// This file was generated automatially by gen.bootstrap.cpp " +"(See: https://github.com/Ed94/gencpp)\n\n"; constexpr StrC implementation_guard_start = txt_StrC(R"( #pragma region GENCPP IMPLEMENTATION GUARD @@ -50,9 +32,13 @@ constexpr StrC roll_own_dependencies_guard_start = txt_StrC(R"( constexpr StrC roll_own_dependencies_guard_end = txt_StrC(R"( // GEN_ROLL_OWN_DEPENDENCIES #endif - )"); +global bool generate_gen_dep = true; +global bool generate_builder = true; +global bool generate_editor = true; +global bool generate_scanner = true; + int gen_main() { gen::init(); @@ -63,11 +49,10 @@ int gen_main() Code pop_ignores = scan_file( project_dir "helpers/pop_ignores.inline.hpp" ); Code header_start = scan_file( "components/header_start.hpp" ); - Code nspace_macro = untyped_str( namespace_by_default ? nspace_default : nspace_non_default ); Builder - header; - header.open( "gen/gen.hpp" ); + header = Builder::open( "gen/gen.hpp" ); + header.print( generation_notice ); header.print( push_ignores ); header.print_fmt("#pragma once\n\n"); @@ -75,8 +60,8 @@ int gen_main() // Headers { header.print( header_start ); - header.print( nspace_macro ); + if ( generate_gen_dep ) { header.print_fmt( roll_own_dependencies_guard_start ); @@ -91,7 +76,6 @@ int gen_main() Code hashing = scan_file( project_dir "dependencies/hashing.hpp" ); Code string = scan_file( project_dir "dependencies/string.hpp" ); Code file_handling = scan_file( project_dir "dependencies/file_handling.hpp" ); - Code parsing = scan_file( project_dir "dependencies/parsing.hpp" ); Code timing = scan_file( project_dir "dependencies/timing.hpp" ); header.print( header_start ); @@ -106,7 +90,6 @@ int gen_main() header.print( hashing ); header.print( string ); header.print( file_handling ); - header.print( parsing ); header.print( timing ); header.print_fmt( "GEN_NS_END\n" ); @@ -114,16 +97,17 @@ int gen_main() } Code types = scan_file( project_dir "components/types.hpp" ); - Code data_structs = scan_file( project_dir "components/data_structures.hpp" ); + Code ast = scan_file( project_dir "components/ast.hpp" ); + Code ast_types = scan_file( project_dir "components/ast_types.hpp" ); Code interface = scan_file( project_dir "components/interface.hpp" ); + Code inlines = scan_file( project_dir "components/inlines.hpp" ); + Code ast_inlines = scan_file( project_dir "components/temp/ast_inlines.hpp" ); Code header_end = scan_file( project_dir "components/header_end.hpp" ); - CodeBody ecode = gen_ecode( project_dir "enums/ECode.csv" ); - CodeBody eoperator = gen_eoperator( project_dir "enums/EOperator.csv" ); + CodeBody ecode = gen_ecode ( project_dir "enums/ECode.csv" ); + CodeBody eoperator = gen_eoperator ( project_dir "enums/EOperator.csv" ); CodeBody especifier = gen_especifier( project_dir "enums/ESpecifier.csv" ); - Code builder = scan_file( project_dir "file_processors/builder.hpp" ); - header.print_fmt( "GEN_NS_BEGIN\n\n" ); header.print_fmt("#pragma region Types\n\n"); @@ -133,32 +117,40 @@ int gen_main() header.print( especifier ); header.print_fmt("#pragma endregion Types\n\n"); - header.print( data_structs ); + header.print_fmt("#pragma region AST\n\n"); + header.print( ast ); + header.print( ast_types ); + header.print_fmt("#pragma endregion AST\n\n"); + header.print( interface ); + + header.print_fmt( inlines ); + header.print_fmt( ast_inlines ); + header.print( header_end ); - header.print( builder ); header.print_fmt( "GEN_NS_END\n" ); } // Implementation { header.print_fmt( "%s\n", (char const*) implementation_guard_start ); + + if ( generate_gen_dep ) { - header.print_fmt( roll_own_dependencies_guard_start ); - - Code impl_start = scan_file( project_dir "dependencies/impl_start.cpp" ); - Code debug = scan_file( project_dir "dependencies/debug.cpp" ); - Code string_ops = scan_file( project_dir "dependencies/string_ops.cpp" ); - Code printing = scan_file( project_dir "dependencies/printing.cpp" ); - Code memory = scan_file( project_dir "dependencies/memory.cpp" ); - Code parsing = scan_file( project_dir "dependencies/parsing.cpp" ); - Code hashing = scan_file( project_dir "dependencies/hashing.cpp" ); - Code string = scan_file( project_dir "dependencies/string.cpp" ); - Code timing = scan_file( project_dir "dependencies/timing.cpp" ); - + Code impl_start = scan_file( project_dir "dependencies/impl_start.cpp" ); + Code debug = scan_file( project_dir "dependencies/debug.cpp" ); + Code string_ops = scan_file( project_dir "dependencies/string_ops.cpp" ); + Code printing = scan_file( project_dir "dependencies/printing.cpp" ); + Code memory = scan_file( project_dir "dependencies/memory.cpp" ); + Code parsing = scan_file( project_dir "dependencies/parsing.cpp" ); + Code hashing = scan_file( project_dir "dependencies/hashing.cpp" ); + Code string = scan_file( project_dir "dependencies/string.cpp" ); Code file_handling = scan_file( project_dir "dependencies/file_handling.cpp" ); + Code timing = scan_file( project_dir "dependencies/timing.cpp" ); + header.print_fmt( roll_own_dependencies_guard_start ); header.print_fmt( "GEN_NS_BEGIN\n\n"); + header.print( impl_start ); header.print( debug ); header.print( string_ops ); @@ -167,12 +159,10 @@ int gen_main() header.print( parsing ); header.print( hashing ); header.print( string ); + header.print( file_handling ); header.print( timing ); - header.print( file_handling ); - header.print_fmt( "GEN_NS_END\n"); - header.print_fmt( roll_own_dependencies_guard_end ); } @@ -184,11 +174,9 @@ int gen_main() Code parsing = scan_file( project_dir "components/interface.parsing.cpp" ); Code untyped = scan_file( project_dir "components/untyped.cpp" ); - CodeBody etoktype = gen_etoktype( project_dir "enums/ETokType.csv", project_dir "enums/AttributeTokens.csv" ); + CodeBody etoktype = gen_etoktype( project_dir "enums/ETokType.csv", project_dir "enums/AttributeTokens.csv" ); CodeNamespace parser_nspace = def_namespace( name(Parser), def_namespace_body( args(etoktype)) ); - Code builder = scan_file( project_dir "file_processors/builder.cpp" ); - header.print_fmt( "GEN_NS_BEGIN\n\n"); header.print( data ); header.print( ast_case_macros ); @@ -198,7 +186,6 @@ int gen_main() header.print( parser_nspace ); header.print( parsing ); header.print( untyped ); - header.print( builder ); header.print_fmt( "GEN_NS_END\n"); header.print_fmt( "%s\n", (char const*) implementation_guard_end ); diff --git a/test/validate_bootstrap.cpp b/test/validate_bootstrap.cpp new file mode 100644 index 0000000..32280b3 --- /dev/null +++ b/test/validate_bootstrap.cpp @@ -0,0 +1,3 @@ +// Constructs an AST from the bootstrap generated gen files, then serializes it to a set of files. +// Using the new set of serialized files, reconstructs the AST and then serializes it again. +// The two sets of serialized files should be identical. (Verified by comparing the file hashes) diff --git a/test/validate_singleheader.cpp b/test/validate_singleheader.cpp new file mode 100644 index 0000000..fcd9752 --- /dev/null +++ b/test/validate_singleheader.cpp @@ -0,0 +1,3 @@ +// Constructs an AST from the singlheader generated gen files, then serializes it to a set of files. +// Using the new set of serialized files, reconstructs the AST and then serializes it again (to different set of files). +// The two sets of serialized files should be identical. (Verified by comparing the file hashes)