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)