diff --git a/project/components/ast.hpp b/project/components/ast.hpp index 88729f1..69cfa27 100644 --- a/project/components/ast.hpp +++ b/project/components/ast.hpp @@ -333,12 +333,13 @@ struct AST AST* ValueType; // Parameter, Variable }; union { + AST* Macro; // Parameter AST* BitfieldSize; // Variable (Class/Struct Data Member) AST* Params; // Constructor, Function, Operator, Template, Typename }; union { AST* ArrExpr; // Typename - AST* Body; // Class, Constructr, Destructor, Enum, Function, Namespace, Struct, Union + AST* Body; // Class, Constructr, Destructor, Enum, Friend, Function, Namespace, Struct, Union AST* Declaration; // Friend, Template AST* Value; // Parameter, Variable }; @@ -393,12 +394,13 @@ struct AST_POD AST* ValueType; // Parameter, Variable }; union { + AST* Macro; // Parameter AST* BitfieldSize; // Variable (Class/Struct Data Member) AST* Params; // Constructor, Function, Operator, Template, Typename }; union { AST* ArrExpr; // Typename - AST* Body; // Class, Constructr, Destructor, Enum, Function, Namespace, Struct, Union + AST* Body; // Class, Constructr, Destructor, Enum, Friend, Function, Namespace, Struct, Union AST* Declaration; // Friend, Template AST* Value; // Parameter, Variable }; diff --git a/project/components/ast_types.hpp b/project/components/ast_types.hpp index 9bd22a4..c5c5b6e 100644 --- a/project/components/ast_types.hpp +++ b/project/components/ast_types.hpp @@ -118,7 +118,7 @@ struct AST_Constructor Code Next; parser::Token* Tok; Code Parent; - char _PAD_NAME_[ sizeof(StringCached) ]; + StringCached Name; CodeT Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; @@ -158,7 +158,7 @@ struct AST_Destructor Code Next; parser::Token* Tok; Code Parent; - char _PAD_NAME_[ sizeof(StringCached) ]; + StringCached Name; CodeT Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; @@ -642,7 +642,7 @@ struct AST_Param { char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ]; CodeType ValueType; - char _PAD_PROPERTIES_[ sizeof(AST*) ]; + Code Macro; Code Value; char _PAD_PROPERTIES_3_[ sizeof(AST*) ]; }; diff --git a/project/components/code_serialization.cpp b/project/components/code_serialization.cpp index 318d475..45356f5 100644 --- a/project/components/code_serialization.cpp +++ b/project/components/code_serialization.cpp @@ -96,12 +96,18 @@ String CodeConstructor::to_string() void CodeConstructor::to_string_def( String& result ) { - result.append( ast->Parent->Name ); + AST* ClassStructParent = ast->Parent->Parent; + if (ClassStructParent) { + result.append( ClassStructParent->Name ); + } + else { + result.append( ast->Name ); + } if ( ast->Params ) result.append_fmt( "( %S )", ast->Params.to_string() ); else - result.append( "(void)" ); + result.append( "()" ); if ( ast->InitializerList ) result.append_fmt( " : %S", ast->InitializerList.to_string() ); @@ -114,17 +120,26 @@ void CodeConstructor::to_string_def( String& result ) void CodeConstructor::to_string_fwd( String& result ) { - result.append( ast->Parent->Name ); + AST* ClassStructParent = ast->Parent->Parent; + if (ClassStructParent) { + result.append( ClassStructParent->Name ); + } + else { + result.append( ast->Name ); + } if ( ast->Params ) result.append_fmt( "( %S )", ast->Params.to_string() ); else - { - if ( ast->InlineCmt ) - result.append_fmt( "(void); // %S\n", ast->InlineCmt->Content ); - else - result.append( "(void);\n" ); - } + result.append_fmt("()"); + + if (ast->Body) + result.append_fmt( " = %S", ast->Body.to_string() ); + + if ( ast->InlineCmt ) + result.append_fmt( "; // %S\n", ast->InlineCmt->Content ); + else + result.append( ";" ); } String CodeClass::to_string() @@ -159,7 +174,7 @@ void CodeClass::to_string_def( String& result ) { char const* access_level = to_str( ast->ParentAccess ); - result.append_fmt( "%S : %s %S", ast->Name, access_level, ast->ParentType ); + result.append_fmt( "%S : %s %S", ast->Name, access_level, ast->ParentType.to_string() ); CodeType interface = ast->ParentType->Next->cast< CodeType >(); if ( interface ) @@ -235,7 +250,11 @@ String CodeDestructor::to_string() void CodeDestructor::to_string_def( String& result ) { - if ( ast->Specs ) + if ( ast->Name ) + { + result.append_fmt( "%S()", ast->Name ); + } + else if ( ast->Specs ) { if ( ast->Specs.has( ESpecifier::Virtual ) ) result.append_fmt( "virtual ~%S()", ast->Parent->Name ); @@ -259,6 +278,8 @@ void CodeDestructor::to_string_fwd( String& result ) if ( ast->Specs.has( ESpecifier::Pure ) ) result.append( " = 0;" ); + else if (ast->Body) + result.append_fmt( " = %S;", ast->Body.to_string() ); } else result.append_fmt( "~%S();", ast->Parent->Name ); @@ -424,7 +445,7 @@ void CodeFriend::to_string( String& result ) { result.append_fmt( "friend %S", ast->Declaration->to_string() ); - if ( result[ result.length() -1 ] != ';' ) + if ( ast->Declaration->Type != ECode::Function && result[ result.length() - 1 ] != ';' ) { result.append( ";" ); } @@ -513,7 +534,7 @@ void CodeFn::to_string_fwd( String& result ) { for ( SpecifierT spec : ast->Specs ) { - if ( ! ESpecifier::is_trailing( spec ) ) + if ( ESpecifier::is_trailing( spec ) && ! (spec != ESpecifier::Pure) ) { StrC spec_str = ESpecifier::to_str( spec ); result.append_fmt( " %.*s", spec_str.Len, spec_str.Ptr ); @@ -550,6 +571,11 @@ void CodeFn::to_string_fwd( String& result ) } } + if ( ast->Specs.has( ESpecifier::Pure ) >= 0 ) + result.append( " = 0;" ); + else if (ast->Body) + result.append_fmt( " = %S;", ast->Body.to_string() ); + if ( ast->InlineCmt ) result.append_fmt( "; %S", ast->InlineCmt->Content ); else @@ -797,24 +823,30 @@ String CodeParam::to_string() void CodeParam::to_string( String& result ) { - if ( ast->ValueType.ast == nullptr ) + if ( ast->Macro ) { - result.append_fmt( "%S", ast->Name ); - return; + // Related to parsing: ( , ... ) + result.append( ast->Macro.ast->Content ); + // Could also be: ( , ... ) } if ( ast->Name ) - result.append_fmt( "%S %S", ast->ValueType.to_string(), ast->Name ); + { + if ( ast->ValueType.ast == nullptr ) + result.append_fmt( " %S", ast->Name ); + else + result.append_fmt( " %S %S", ast->ValueType.to_string(), ast->Name ); - else - result.append_fmt( "%S", ast->ValueType.to_string() ); + } + else if ( ast->ValueType ) + result.append_fmt( " %S", ast->ValueType.to_string() ); if ( ast->Value ) - result.append_fmt( "= %S", ast->Value.to_string() ); + result.append_fmt( " = %S", ast->Value.to_string() ); - if ( ast->NumEntries - 1 > 0) + if ( ast->NumEntries - 1 > 0 ) { - for ( CodeParam param : ast->Next ) + for ( CodeParam param : ast->Next ) { result.append_fmt( ", %S", param.to_string() ); } @@ -942,7 +974,7 @@ void CodeStruct::to_string_def( String& result ) { char const* access_level = to_str( ast->ParentAccess ); - result.append_fmt( "%S : %s %S", ast->Name, access_level, ast->ParentType ); + result.append_fmt( "%S : %s %S", ast->Name, access_level, ast->ParentType.to_string() ); CodeType interface = ast->ParentType->Next->cast< CodeType >(); if ( interface ) diff --git a/project/components/code_types.hpp b/project/components/code_types.hpp index 64cfe6d..4b67d57 100644 --- a/project/components/code_types.hpp +++ b/project/components/code_types.hpp @@ -159,7 +159,7 @@ struct CodeSpecifiers { for ( s32 idx = 0; idx < raw()->NumEntries; idx++ ) { - if ( raw()->ArrSpecs[ raw()->NumEntries ] == spec ) + if ( raw()->ArrSpecs[ idx ] == spec ) return idx; } diff --git a/project/components/gen/ast_inlines.hpp b/project/components/gen/ast_inlines.hpp index bc8c066..0d70d13 100644 --- a/project/components/gen/ast_inlines.hpp +++ b/project/components/gen/ast_inlines.hpp @@ -36,7 +36,7 @@ bool Code::is_equal( Code other ) bool Code::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void Code::set_global() @@ -62,12 +62,12 @@ Code& Code::operator=( Code other ) bool Code::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool Code::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } Code::operator bool() @@ -104,7 +104,7 @@ bool CodeBody::is_equal( Code other ) bool CodeBody::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeBody::set_global() @@ -130,12 +130,12 @@ CodeBody& CodeBody::operator=( Code other ) bool CodeBody::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeBody::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeBody::operator bool() @@ -172,7 +172,7 @@ bool CodeAttributes::is_equal( Code other ) bool CodeAttributes::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeAttributes::set_global() @@ -198,12 +198,12 @@ CodeAttributes& CodeAttributes::operator=( Code other ) bool CodeAttributes::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeAttributes::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeAttributes::operator bool() @@ -260,7 +260,7 @@ bool CodeComment::is_equal( Code other ) bool CodeComment::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeComment::set_global() @@ -286,12 +286,12 @@ CodeComment& CodeComment::operator=( Code other ) bool CodeComment::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeComment::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeComment::operator bool() @@ -348,7 +348,7 @@ bool CodeConstructor::is_equal( Code other ) bool CodeConstructor::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeConstructor::set_global() @@ -374,12 +374,12 @@ CodeConstructor& CodeConstructor::operator=( Code other ) bool CodeConstructor::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeConstructor::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeConstructor::operator bool() @@ -436,7 +436,7 @@ bool CodeClass::is_equal( Code other ) bool CodeClass::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeClass::set_global() @@ -462,12 +462,12 @@ CodeClass& CodeClass::operator=( Code other ) bool CodeClass::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeClass::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeClass::operator bool() @@ -504,7 +504,7 @@ bool CodeDefine::is_equal( Code other ) bool CodeDefine::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeDefine::set_global() @@ -530,12 +530,12 @@ CodeDefine& CodeDefine::operator=( Code other ) bool CodeDefine::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeDefine::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeDefine::operator bool() @@ -592,7 +592,7 @@ bool CodeDestructor::is_equal( Code other ) bool CodeDestructor::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeDestructor::set_global() @@ -618,12 +618,12 @@ CodeDestructor& CodeDestructor::operator=( Code other ) bool CodeDestructor::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeDestructor::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeDestructor::operator bool() @@ -680,7 +680,7 @@ bool CodeEnum::is_equal( Code other ) bool CodeEnum::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeEnum::set_global() @@ -706,12 +706,12 @@ CodeEnum& CodeEnum::operator=( Code other ) bool CodeEnum::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeEnum::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeEnum::operator bool() @@ -768,7 +768,7 @@ bool CodeExec::is_equal( Code other ) bool CodeExec::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeExec::set_global() @@ -794,12 +794,12 @@ CodeExec& CodeExec::operator=( Code other ) bool CodeExec::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeExec::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeExec::operator bool() @@ -856,7 +856,7 @@ bool CodeExtern::is_equal( Code other ) bool CodeExtern::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeExtern::set_global() @@ -882,12 +882,12 @@ CodeExtern& CodeExtern::operator=( Code other ) bool CodeExtern::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeExtern::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeExtern::operator bool() @@ -944,7 +944,7 @@ bool CodeFriend::is_equal( Code other ) bool CodeFriend::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeFriend::set_global() @@ -970,12 +970,12 @@ CodeFriend& CodeFriend::operator=( Code other ) bool CodeFriend::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeFriend::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeFriend::operator bool() @@ -1032,7 +1032,7 @@ bool CodeFn::is_equal( Code other ) bool CodeFn::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeFn::set_global() @@ -1058,12 +1058,12 @@ CodeFn& CodeFn::operator=( Code other ) bool CodeFn::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeFn::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeFn::operator bool() @@ -1120,7 +1120,7 @@ bool CodeInclude::is_equal( Code other ) bool CodeInclude::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeInclude::set_global() @@ -1146,12 +1146,12 @@ CodeInclude& CodeInclude::operator=( Code other ) bool CodeInclude::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeInclude::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeInclude::operator bool() @@ -1208,7 +1208,7 @@ bool CodeModule::is_equal( Code other ) bool CodeModule::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeModule::set_global() @@ -1234,12 +1234,12 @@ CodeModule& CodeModule::operator=( Code other ) bool CodeModule::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeModule::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeModule::operator bool() @@ -1296,7 +1296,7 @@ bool CodeNS::is_equal( Code other ) bool CodeNS::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeNS::set_global() @@ -1322,12 +1322,12 @@ CodeNS& CodeNS::operator=( Code other ) bool CodeNS::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeNS::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeNS::operator bool() @@ -1384,7 +1384,7 @@ bool CodeOperator::is_equal( Code other ) bool CodeOperator::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeOperator::set_global() @@ -1410,12 +1410,12 @@ CodeOperator& CodeOperator::operator=( Code other ) bool CodeOperator::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeOperator::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeOperator::operator bool() @@ -1472,7 +1472,7 @@ bool CodeOpCast::is_equal( Code other ) bool CodeOpCast::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeOpCast::set_global() @@ -1498,12 +1498,12 @@ CodeOpCast& CodeOpCast::operator=( Code other ) bool CodeOpCast::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeOpCast::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeOpCast::operator bool() @@ -1560,7 +1560,7 @@ bool CodeParam::is_equal( Code other ) bool CodeParam::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeParam::set_global() @@ -1586,12 +1586,12 @@ CodeParam& CodeParam::operator=( Code other ) bool CodeParam::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeParam::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeParam::operator bool() @@ -1628,7 +1628,7 @@ bool CodePragma::is_equal( Code other ) bool CodePragma::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodePragma::set_global() @@ -1654,12 +1654,12 @@ CodePragma& CodePragma::operator=( Code other ) bool CodePragma::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodePragma::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodePragma::operator bool() @@ -1716,7 +1716,7 @@ bool CodePreprocessCond::is_equal( Code other ) bool CodePreprocessCond::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodePreprocessCond::set_global() @@ -1742,12 +1742,12 @@ CodePreprocessCond& CodePreprocessCond::operator=( Code other ) bool CodePreprocessCond::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodePreprocessCond::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodePreprocessCond::operator bool() @@ -1804,7 +1804,7 @@ bool CodeSpecifiers::is_equal( Code other ) bool CodeSpecifiers::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeSpecifiers::set_global() @@ -1830,12 +1830,12 @@ CodeSpecifiers& CodeSpecifiers::operator=( Code other ) bool CodeSpecifiers::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeSpecifiers::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeSpecifiers::operator bool() @@ -1872,7 +1872,7 @@ bool CodeStruct::is_equal( Code other ) bool CodeStruct::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeStruct::set_global() @@ -1898,12 +1898,12 @@ CodeStruct& CodeStruct::operator=( Code other ) bool CodeStruct::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeStruct::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeStruct::operator bool() @@ -1940,7 +1940,7 @@ bool CodeTemplate::is_equal( Code other ) bool CodeTemplate::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeTemplate::set_global() @@ -1966,12 +1966,12 @@ CodeTemplate& CodeTemplate::operator=( Code other ) bool CodeTemplate::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeTemplate::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeTemplate::operator bool() @@ -2028,7 +2028,7 @@ bool CodeType::is_equal( Code other ) bool CodeType::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeType::set_global() @@ -2054,12 +2054,12 @@ CodeType& CodeType::operator=( Code other ) bool CodeType::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeType::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeType::operator bool() @@ -2116,7 +2116,7 @@ bool CodeTypedef::is_equal( Code other ) bool CodeTypedef::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeTypedef::set_global() @@ -2142,12 +2142,12 @@ CodeTypedef& CodeTypedef::operator=( Code other ) bool CodeTypedef::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeTypedef::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeTypedef::operator bool() @@ -2204,7 +2204,7 @@ bool CodeUnion::is_equal( Code other ) bool CodeUnion::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeUnion::set_global() @@ -2230,12 +2230,12 @@ CodeUnion& CodeUnion::operator=( Code other ) bool CodeUnion::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeUnion::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeUnion::operator bool() @@ -2292,7 +2292,7 @@ bool CodeUsing::is_equal( Code other ) bool CodeUsing::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeUsing::set_global() @@ -2318,12 +2318,12 @@ CodeUsing& CodeUsing::operator=( Code other ) bool CodeUsing::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeUsing::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeUsing::operator bool() @@ -2380,7 +2380,7 @@ bool CodeVar::is_equal( Code other ) bool CodeVar::is_valid() { - return ( AST* )ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; + return (AST*)ast != nullptr && rcast( AST*, ast )->Type != CodeT::Invalid; } void CodeVar::set_global() @@ -2406,12 +2406,12 @@ CodeVar& CodeVar::operator=( Code other ) bool CodeVar::operator==( Code other ) { - return ( AST* )ast == other.ast; + return (AST*)ast == other.ast; } bool CodeVar::operator!=( Code other ) { - return ( AST* )ast != other.ast; + return (AST*)ast != other.ast; } CodeVar::operator bool() @@ -2450,7 +2450,7 @@ AST::operator CodeBody() Code::operator CodeBody() const { - return { ( AST_Body* )ast }; + return { (AST_Body*)ast }; } AST::operator CodeAttributes() @@ -2460,7 +2460,7 @@ AST::operator CodeAttributes() Code::operator CodeAttributes() const { - return { ( AST_Attributes* )ast }; + return { (AST_Attributes*)ast }; } AST::operator CodeComment() @@ -2470,7 +2470,7 @@ AST::operator CodeComment() Code::operator CodeComment() const { - return { ( AST_Comment* )ast }; + return { (AST_Comment*)ast }; } AST::operator CodeConstructor() @@ -2480,7 +2480,7 @@ AST::operator CodeConstructor() Code::operator CodeConstructor() const { - return { ( AST_Constructor* )ast }; + return { (AST_Constructor*)ast }; } AST::operator CodeClass() @@ -2490,7 +2490,7 @@ AST::operator CodeClass() Code::operator CodeClass() const { - return { ( AST_Class* )ast }; + return { (AST_Class*)ast }; } AST::operator CodeDefine() @@ -2500,7 +2500,7 @@ AST::operator CodeDefine() Code::operator CodeDefine() const { - return { ( AST_Define* )ast }; + return { (AST_Define*)ast }; } AST::operator CodeDestructor() @@ -2510,7 +2510,7 @@ AST::operator CodeDestructor() Code::operator CodeDestructor() const { - return { ( AST_Destructor* )ast }; + return { (AST_Destructor*)ast }; } AST::operator CodeEnum() @@ -2520,7 +2520,7 @@ AST::operator CodeEnum() Code::operator CodeEnum() const { - return { ( AST_Enum* )ast }; + return { (AST_Enum*)ast }; } AST::operator CodeExec() @@ -2530,7 +2530,7 @@ AST::operator CodeExec() Code::operator CodeExec() const { - return { ( AST_Exec* )ast }; + return { (AST_Exec*)ast }; } AST::operator CodeExtern() @@ -2540,7 +2540,7 @@ AST::operator CodeExtern() Code::operator CodeExtern() const { - return { ( AST_Extern* )ast }; + return { (AST_Extern*)ast }; } AST::operator CodeFriend() @@ -2550,7 +2550,7 @@ AST::operator CodeFriend() Code::operator CodeFriend() const { - return { ( AST_Friend* )ast }; + return { (AST_Friend*)ast }; } AST::operator CodeFn() @@ -2560,7 +2560,7 @@ AST::operator CodeFn() Code::operator CodeFn() const { - return { ( AST_Fn* )ast }; + return { (AST_Fn*)ast }; } AST::operator CodeInclude() @@ -2570,7 +2570,7 @@ AST::operator CodeInclude() Code::operator CodeInclude() const { - return { ( AST_Include* )ast }; + return { (AST_Include*)ast }; } AST::operator CodeModule() @@ -2580,7 +2580,7 @@ AST::operator CodeModule() Code::operator CodeModule() const { - return { ( AST_Module* )ast }; + return { (AST_Module*)ast }; } AST::operator CodeNS() @@ -2590,7 +2590,7 @@ AST::operator CodeNS() Code::operator CodeNS() const { - return { ( AST_NS* )ast }; + return { (AST_NS*)ast }; } AST::operator CodeOperator() @@ -2600,7 +2600,7 @@ AST::operator CodeOperator() Code::operator CodeOperator() const { - return { ( AST_Operator* )ast }; + return { (AST_Operator*)ast }; } AST::operator CodeOpCast() @@ -2610,7 +2610,7 @@ AST::operator CodeOpCast() Code::operator CodeOpCast() const { - return { ( AST_OpCast* )ast }; + return { (AST_OpCast*)ast }; } AST::operator CodeParam() @@ -2620,7 +2620,7 @@ AST::operator CodeParam() Code::operator CodeParam() const { - return { ( AST_Param* )ast }; + return { (AST_Param*)ast }; } AST::operator CodePragma() @@ -2630,7 +2630,7 @@ AST::operator CodePragma() Code::operator CodePragma() const { - return { ( AST_Pragma* )ast }; + return { (AST_Pragma*)ast }; } AST::operator CodePreprocessCond() @@ -2640,7 +2640,7 @@ AST::operator CodePreprocessCond() Code::operator CodePreprocessCond() const { - return { ( AST_PreprocessCond* )ast }; + return { (AST_PreprocessCond*)ast }; } AST::operator CodeSpecifiers() @@ -2650,7 +2650,7 @@ AST::operator CodeSpecifiers() Code::operator CodeSpecifiers() const { - return { ( AST_Specifiers* )ast }; + return { (AST_Specifiers*)ast }; } AST::operator CodeStruct() @@ -2660,7 +2660,7 @@ AST::operator CodeStruct() Code::operator CodeStruct() const { - return { ( AST_Struct* )ast }; + return { (AST_Struct*)ast }; } AST::operator CodeTemplate() @@ -2670,7 +2670,7 @@ AST::operator CodeTemplate() Code::operator CodeTemplate() const { - return { ( AST_Template* )ast }; + return { (AST_Template*)ast }; } AST::operator CodeType() @@ -2680,7 +2680,7 @@ AST::operator CodeType() Code::operator CodeType() const { - return { ( AST_Type* )ast }; + return { (AST_Type*)ast }; } AST::operator CodeTypedef() @@ -2690,7 +2690,7 @@ AST::operator CodeTypedef() Code::operator CodeTypedef() const { - return { ( AST_Typedef* )ast }; + return { (AST_Typedef*)ast }; } AST::operator CodeUnion() @@ -2700,7 +2700,7 @@ AST::operator CodeUnion() Code::operator CodeUnion() const { - return { ( AST_Union* )ast }; + return { (AST_Union*)ast }; } AST::operator CodeUsing() @@ -2710,7 +2710,7 @@ AST::operator CodeUsing() Code::operator CodeUsing() const { - return { ( AST_Using* )ast }; + return { (AST_Using*)ast }; } AST::operator CodeVar() @@ -2720,7 +2720,7 @@ AST::operator CodeVar() Code::operator CodeVar() const { - return { ( AST_Var* )ast }; + return { (AST_Var*)ast }; } #pragma endregion generated AST / Code cast implementation diff --git a/project/components/gen/ecode.hpp b/project/components/gen/ecode.hpp index 77f84f6..c051775 100644 --- a/project/components/gen/ecode.hpp +++ b/project/components/gen/ecode.hpp @@ -136,7 +136,7 @@ namespace ECode { sizeof( "Using_Namespace" ), "Using_Namespace" }, { sizeof( "Variable" ), "Variable" }, }; - return lookup[ type ]; + return lookup[type]; } } // namespace ECode diff --git a/project/components/gen/eoperator.hpp b/project/components/gen/eoperator.hpp index 1e6e7f1..f47f638 100644 --- a/project/components/gen/eoperator.hpp +++ b/project/components/gen/eoperator.hpp @@ -52,57 +52,65 @@ namespace EOperator PtrToMemOfPtr, FunctionCall, Comma, + New, + NewArray, + Delete, + DeleteArray, NumOps }; StrC to_str( Type op ) { local_persist StrC lookup[] { - { sizeof( "INVALID" ), "INVALID" }, - { sizeof( "=" ), "=" }, - { sizeof( "+=" ), "+=" }, - { sizeof( "-=" ), "-=" }, - { sizeof( "*=" ), "*=" }, - { sizeof( "/=" ), "/=" }, - { sizeof( "%=" ), "%=" }, - { sizeof( "&=" ), "&=" }, - { sizeof( "|=" ), "|=" }, - { sizeof( "^=" ), "^=" }, - { sizeof( "<<=" ), "<<=" }, - { sizeof( ">>=" ), ">>=" }, - { sizeof( "++" ), "++" }, - { sizeof( "--" ), "--" }, - { sizeof( "+" ), "+" }, - { sizeof( "-" ), "-" }, - { sizeof( "!" ), "!" }, - { sizeof( "+" ), "+" }, - { sizeof( "-" ), "-" }, - { sizeof( "*" ), "*" }, - { sizeof( "/" ), "/" }, - { sizeof( "%" ), "%" }, - { sizeof( "~" ), "~" }, - { sizeof( "&" ), "&" }, - { sizeof( "|" ), "|" }, - { sizeof( "^" ), "^" }, - { sizeof( "<<" ), "<<" }, - { sizeof( ">>" ), ">>" }, - { sizeof( "&&" ), "&&" }, - { sizeof( "||" ), "||" }, - { sizeof( "==" ), "==" }, - { sizeof( "!=" ), "!=" }, - { sizeof( "<" ), "<" }, - { sizeof( ">" ), ">" }, - { sizeof( "<=" ), "<=" }, - { sizeof( ">=" ), ">=" }, - { sizeof( "[]" ), "[]" }, - { sizeof( "*" ), "*" }, - { sizeof( "&" ), "&" }, - { sizeof( "->" ), "->" }, - { sizeof( "->*" ), "->*" }, - { sizeof( "()" ), "()" }, - { sizeof( "," ), "," }, + { sizeof( "INVALID" ), "INVALID" }, + { sizeof( "=" ), "=" }, + { sizeof( "+=" ), "+=" }, + { sizeof( "-=" ), "-=" }, + { sizeof( "*=" ), "*=" }, + { sizeof( "/=" ), "/=" }, + { sizeof( "%=" ), "%=" }, + { sizeof( "&=" ), "&=" }, + { sizeof( "|=" ), "|=" }, + { sizeof( "^=" ), "^=" }, + { sizeof( "<<=" ), "<<=" }, + { sizeof( ">>=" ), ">>=" }, + { sizeof( "++" ), "++" }, + { sizeof( "--" ), "--" }, + { sizeof( "+" ), "+" }, + { sizeof( "-" ), "-" }, + { sizeof( "!" ), "!" }, + { sizeof( "+" ), "+" }, + { sizeof( "-" ), "-" }, + { sizeof( "*" ), "*" }, + { sizeof( "/" ), "/" }, + { sizeof( "%" ), "%" }, + { sizeof( "~" ), "~" }, + { sizeof( "&" ), "&" }, + { sizeof( "|" ), "|" }, + { sizeof( "^" ), "^" }, + { sizeof( "<<" ), "<<" }, + { sizeof( ">>" ), ">>" }, + { sizeof( "&&" ), "&&" }, + { sizeof( "||" ), "||" }, + { sizeof( "==" ), "==" }, + { sizeof( "!=" ), "!=" }, + { sizeof( "<" ), "<" }, + { sizeof( ">" ), ">" }, + { sizeof( "<=" ), "<=" }, + { sizeof( ">=" ), ">=" }, + { sizeof( "[]" ), "[]" }, + { sizeof( "*" ), "*" }, + { sizeof( "&" ), "&" }, + { sizeof( "->" ), "->" }, + { sizeof( "->*" ), "->*" }, + { sizeof( "()" ), "()" }, + { sizeof( "," ), "," }, + { sizeof( "new" ), "new" }, + { sizeof( "new[]" ), "new[]" }, + { sizeof( "delete" ), "delete" }, + { sizeof( "delete[]" ), "delete[]" }, }; - return lookup[ op ]; + return lookup[op]; } } // namespace EOperator diff --git a/project/components/gen/especifier.hpp b/project/components/gen/especifier.hpp index 8184187..945f49f 100644 --- a/project/components/gen/especifier.hpp +++ b/project/components/gen/especifier.hpp @@ -73,22 +73,22 @@ namespace ESpecifier { sizeof( "= 0" ), "= 0" }, { sizeof( "volatile" ), "volatile" }, }; - return lookup[ type ]; + return lookup[type]; } Type to_type( StrC str ) { - local_persist u32 keymap[ NumSpecifiers ]; + local_persist u32 keymap[NumSpecifiers]; do_once_start for ( u32 index = 0; index < NumSpecifiers; index++ ) { - StrC enum_str = to_str( ( Type )index ); - keymap[ index ] = crc32( enum_str.Ptr, enum_str.Len - 1 ); + StrC enum_str = to_str( (Type)index ); + keymap[index] = crc32( enum_str.Ptr, enum_str.Len - 1 ); } do_once_end u32 hash = crc32( str.Ptr, str.Len ); for ( u32 index = 0; index < NumSpecifiers; index++ ) { - if ( keymap[ index ] == hash ) - return ( Type )index; + if ( keymap[index] == hash ) + return (Type)index; } return Invalid; } diff --git a/project/components/gen/etoktype.cpp b/project/components/gen/etoktype.cpp index 63dae8c..9ffe8ed 100644 --- a/project/components/gen/etoktype.cpp +++ b/project/components/gen/etoktype.cpp @@ -9,7 +9,7 @@ namespace parser { namespace ETokType { -#define GEN_DEFINE_ATTRIBUTE_TOKENS Entry( API_Export, GEN_API_Export_Code ) Entry( API_Import, GEN_API_Import_Code ) +#define GEN_DEFINE_ATTRIBUTE_TOKENS Entry( Attribute_API_Export, "GEN_API_Export_Code" ) Entry( Attribute_API_Import, "GEN_API_Import_Code" ) enum Type : u32 { @@ -108,8 +108,8 @@ namespace parser Type_MS_W64, Varadic_Argument, __Attributes_Start, - API_Export, - API_Import, + Attribute_API_Export, + Attribute_API_Import, NumTokens }; @@ -214,22 +214,22 @@ namespace parser { sizeof( "GEN_API_Export_Code" ), "GEN_API_Export_Code" }, { sizeof( "GEN_API_Import_Code" ), "GEN_API_Import_Code" }, }; - return lookup[ type ]; + return lookup[type]; } Type to_type( StrC str ) { - local_persist u32 keymap[ NumTokens ]; + local_persist u32 keymap[NumTokens]; do_once_start for ( u32 index = 0; index < NumTokens; index++ ) { - StrC enum_str = to_str( ( Type )index ); - keymap[ index ] = crc32( enum_str.Ptr, enum_str.Len - 1 ); + StrC enum_str = to_str( (Type)index ); + keymap[index] = crc32( enum_str.Ptr, enum_str.Len - 1 ); } do_once_end u32 hash = crc32( str.Ptr, str.Len ); for ( u32 index = 0; index < NumTokens; index++ ) { - if ( keymap[ index ] == hash ) - return ( Type )index; + if ( keymap[index] == hash ) + return (Type)index; } return Invalid; } diff --git a/project/components/interface.parsing.cpp b/project/components/interface.parsing.cpp index 72a1622..726f9e4 100644 --- a/project/components/interface.parsing.cpp +++ b/project/components/interface.parsing.cpp @@ -33,8 +33,54 @@ CodeConstructor parse_constructor( StrC def ) if ( toks.Arr == nullptr ) return CodeInvalid; - Context.Tokens = toks; - CodeConstructor result = parse_constructor(); + // TODO(Ed): Constructors can have prefix attributes + + CodeSpecifiers specifiers; + SpecifierT specs_found[ 16 ] { ESpecifier::NumSpecifiers }; + s32 NumSpecifiers = 0; + + while ( left && currtok.is_specifier() ) + { + SpecifierT spec = ESpecifier::to_type( currtok ); + + b32 ignore_spec = false; + + switch ( spec ) + { + case ESpecifier::Constexpr : + case ESpecifier::Explicit: + case ESpecifier::Inline : + case ESpecifier::ForceInline : + case ESpecifier::NeverInline : + break; + + case ESpecifier::Const : + ignore_spec = true; + break; + + default : + log_failure( "Invalid specifier %s for variable\n%s", ESpecifier::to_str( spec ), Context.to_string() ); + Context.pop(); + return CodeInvalid; + } + + // Every specifier after would be considered part of the type type signature + if (ignore_spec) + break; + + specs_found[ NumSpecifiers ] = spec; + NumSpecifiers++; + eat( currtok.Type ); + } + + if ( NumSpecifiers ) + { + specifiers = def_specifiers( NumSpecifiers, specs_found ); + // ... + } + + Context.Tokens = toks; + CodeConstructor result = parse_constructor( specifiers ); return result; } @@ -47,7 +93,10 @@ CodeDestructor parse_destructor( StrC def ) if ( toks.Arr == nullptr ) return CodeInvalid; - Context.Tokens = toks; + // TODO(Ed): Destructors can have prefix attributes + // TODO(Ed): Destructors can have virtual + + Context.Tokens = toks; CodeDestructor result = parse_destructor(); return result; } diff --git a/project/components/interface.upfront.cpp b/project/components/interface.upfront.cpp index b198745..f0ca08f 100644 --- a/project/components/interface.upfront.cpp +++ b/project/components/interface.upfront.cpp @@ -159,7 +159,6 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy case Unary_Plus: case Unary_Minus: - case BNot: if ( ! params_code ) is_member_symbol = true; @@ -194,6 +193,41 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy } break; + case BNot: + { + // Some compilers let you do this... + #if 0 + if ( ! ret_type.is_equal( t_bool) ) + { + log_failure( "gen::def_operator: return type is not a boolean - %s", params_code.debug_str() ); + return OpValidateResult::Fail; + } + #endif + + if ( ! params_code ) + is_member_symbol = true; + + else + { + if ( params_code->Type != ECode::Parameters ) + { + log_failure( "gen::def_operator: params is not of Parameters type - %s", params_code.debug_str() ); + return OpValidateResult::Fail; + } + + if ( params_code->NumEntries > 1 ) + { + log_failure( + "gen::def_operator: operator%s may not have more than one parameter - param count: %d", + to_str( op ), + params_code->NumEntries + ); + return OpValidateResult::Fail; + } + } + break; + } + case Add: case Subtract: case Multiply: @@ -325,6 +359,11 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy case Comma: check_params(); break; + + case New: + case Delete: + // This library doesn't support validating new and delete yet. + break; # undef specs } @@ -520,7 +559,7 @@ CodeClass def_class( StrC name return CodeInvalid; } - if ( parent && (parent->Type != Class || parent->Type != Struct || parent->Type != Typename || parent->Type != Untyped) ) + if ( parent && ( parent->Type != Class && parent->Type != Struct && parent->Type != Typename && parent->Type != Untyped ) ) { log_failure( "gen::def_class: parent provided is not type 'Class', 'Struct', 'Typeanme', or 'Untyped': %s", parent.debug_str() ); return CodeInvalid; @@ -546,6 +585,7 @@ CodeClass def_class( StrC name result->Type = Class; result->Body = body; + result->Body->Parent = result; // TODO(Ed): Review this? } else { @@ -578,17 +618,25 @@ CodeDefine def_define( StrC name, StrC content ) name_check( def_define, name ); + // Defines can be empty definitions +#if 0 if ( content.Len <= 0 || content.Ptr == nullptr ) { log_failure( "gen::def_define: Invalid value provided" ); return CodeInvalid; } +#endif CodeDefine result = (CodeDefine) make_code(); result->Type = Preprocess_Define; result->Name = get_cached_string( name ); - result->Content = get_cached_string( content ); + if ( content.Len <= 0 || content.Ptr == nullptr ) + { + result->Content = get_cached_string( txt("") ); + } + else + result->Content = get_cached_string( content ); return result; } diff --git a/project/components/lexer.cpp b/project/components/lexer.cpp index fcb005b..7437df5 100644 --- a/project/components/lexer.cpp +++ b/project/components/lexer.cpp @@ -13,11 +13,12 @@ enum TokFlags : u32 TF_Preprocess = bit(2), TF_Preprocess_Cond = bit(3), TF_Attribute = bit(6), - TF_AccessSpecifier = bit(7), - TF_Specifier = bit(8), - TF_EndDefinition = bit(9), // Either ; or } - TF_Formatting = bit(10), - TF_Literal = bit(11), + TF_AccessOperator = bit( 7 ), + TF_AccessSpecifier = bit( 8 ), + TF_Specifier = bit( 9 ), + TF_EndDefinition = bit( 10 ), // Either ; or } + TF_Formatting = bit( 11 ), + TF_Literal = bit( 12 ), TF_Null = 0, }; @@ -41,6 +42,11 @@ struct Token return { Length, Text }; } + bool is_access_operator() + { + return bitfield_is_equal( u32, Flags, TF_AccessOperator ); + } + bool is_access_specifier() { return bitfield_is_equal( u32, Flags, TF_AccessSpecifier ); @@ -141,7 +147,7 @@ struct TokArray while ( Arr[idx].Type == TokType::NewLine ) idx++; - return Arr[idx]; + return Arr[idx + 1]; } return Arr[idx + 1]; @@ -153,7 +159,7 @@ struct TokArray } }; -global Arena_64KB defines_map_arena; +global Arena_128KB defines_map_arena; global HashTable defines; global Array Tokens; @@ -451,6 +457,16 @@ void lex_found_token( StrC& content TokType type = ETokType::to_type( token ); + if (type <= TokType::Access_Public && type >= TokType::Access_Private ) + { + token.Flags |= TF_AccessSpecifier; + } + + if ( type > TokType::__Attributes_Start ) + { + token.Flags |= TF_Attribute; + } + if ( type == ETokType::Decl_Extern_Linkage ) { SkipWhitespace(); @@ -565,7 +581,7 @@ TokArray lex( StrC content ) scanner++; length ++; } - if ( scanner[1] == '(' ) + if ( scanner[0] == '(' ) { length++; } @@ -634,7 +650,7 @@ TokArray lex( StrC content ) token.Text = scanner; token.Length = 1; token.Type = TokType::Access_MemberSymbol; - token.Flags = TF_AccessSpecifier; + token.Flags = TF_AccessOperator; if (left) { move_forward(); @@ -1003,7 +1019,7 @@ TokArray lex( StrC content ) { token.Length++; // token.Type = TokType::Access_PointerToMemberSymbol; - token.Flags |= TF_AccessSpecifier; + token.Flags |= TF_AccessOperator; move_forward(); if ( current == '*' ) diff --git a/project/components/parser.cpp b/project/components/parser.cpp index 0fbad44..6f131b9 100644 --- a/project/components/parser.cpp +++ b/project/components/parser.cpp @@ -136,7 +136,7 @@ void init() , ( LexAllocator_Size - sizeof( Array::Header ) ) / sizeof(Token) ); - defines_map_arena = Arena_64KB::init(); + defines_map_arena = Arena_128KB::init(); defines = HashTable::init( defines_map_arena ); } @@ -187,10 +187,12 @@ internal Code parse_complicated_definition ( TokType which ) internal CodeBody parse_class_struct_body ( TokType which, Token name = NullToken ); internal Code parse_class_struct ( TokType which, bool inplace_def ); internal CodeDefine parse_define (); -internal Code parse_forward_or_definition ( TokType which, bool is_inplace ); +internal Code parse_expression (); +internal Code parse_forward_or_definition ( TokType which, bool is_inplace ); internal CodeFn parse_function_after_name ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType ret_type, Token name ); internal Code parse_function_body (); internal Code parse_global_nspace (); +internal Code parse_global_nspace_constructor_destructor( CodeSpecifiers specifiers ); internal Token parse_identifier ( bool* possible_member_function = nullptr ); internal CodeInclude parse_include (); internal CodeOperator parse_operator_after_ret_type ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType ret_type ); @@ -205,7 +207,7 @@ internal CodeVar parse_variable_after_name ( ModuleFlag mfla internal CodeVar parse_variable_declaration_list (); internal CodeClass parse_class ( bool inplace_def = false ); -internal CodeConstructor parse_constructor (); +internal CodeConstructor parse_constructor ( CodeSpecifiers specifiers ); internal CodeDestructor parse_destructor ( CodeSpecifiers specifiers = NoCode ); internal CodeEnum parse_enum ( bool inplace_def = false ); internal CodeBody parse_export_body (); @@ -218,7 +220,7 @@ internal CodeOpCast parse_operator_cast ( CodeSpecifiers specifiers = NoC internal CodeStruct parse_struct ( bool inplace_def = false ); internal CodeVar parse_variable (); internal CodeTemplate parse_template (); -internal CodeType parse_type ( bool* is_function = nullptr ); +internal CodeType parse_type ( bool from_template = false, bool* is_function = nullptr ); internal CodeTypedef parse_typedef (); internal CodeUnion parse_union ( bool inplace_def = false ); internal CodeUsing parse_using (); @@ -557,72 +559,90 @@ CodeAttributes parse_attributes() { push_scope(); - Token start = NullToken; - s32 len = 0; + Token start = currtok; + s32 len = 0; - if ( check(TokType::Attribute_Open) ) + // There can be more than one attribute. If there is flatten them to a single string. + // TODO(Ed): Support keeping an linked list of attributes similar to parameters + while ( left && currtok.is_attribute() ) { - eat( TokType::Attribute_Open); - // [[ + if ( check( TokType::Attribute_Open ) ) + { + eat( TokType::Attribute_Open ); + // [[ - start = currtok; - while ( left && currtok.Type != TokType::Attribute_Close ) + while ( left && currtok.Type != TokType::Attribute_Close ) + { + eat( currtok.Type ); + } + // [[ + + eat( TokType::Attribute_Close ); + // [[ ]] + + len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; + } + else if ( check( TokType::Decl_GNU_Attribute ) ) + { + eat( TokType::Decl_GNU_Attribute ); + eat( TokType::Capture_Start ); + eat( TokType::Capture_Start ); + // __attribute__(( + + while ( left && currtok.Type != TokType::Capture_End ) + { + eat( currtok.Type ); + } + // __attribute__(( + + eat( TokType::Capture_End ); + eat( TokType::Capture_End ); + // __attribute__(( )) + + len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; + } + else if ( check( TokType::Decl_MSVC_Attribute ) ) + { + eat( TokType::Decl_MSVC_Attribute ); + eat( TokType::Capture_Start ); + // __declspec( + + while ( left && currtok.Type != TokType::Capture_End ) + { + eat( currtok.Type ); + } + // __declspec( + + eat( TokType::Capture_End ); + // __declspec( ) + + len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; + } + else if ( currtok.is_attribute() ) { eat( currtok.Type ); + // + + // If its a macro based attribute, this could be a functional macro such as Unreal's UE_DEPRECATED(...) + if ( check( TokType::Capture_Start)) + { + eat( TokType::Capture_Start ); + + s32 level = 0; + while (left && currtok.Type != TokType::Capture_End && level == 0) + { + if (currtok.Type == TokType::Capture_Start) + ++ level; + if (currtok.Type == TokType::Capture_End) + --level; + eat(currtok.Type); + } + eat(TokType::Capture_End); + } + + len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; + // ( ... ) } - // [[ - - eat( TokType::Attribute_Close ); - // [[ ]] - - s32 len = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)start.Text; - } - - else if ( check(TokType::Decl_GNU_Attribute) ) - { - eat(TokType::Decl_GNU_Attribute); - eat(TokType::Capture_Start); - eat(TokType::Capture_Start); - // __attribute__(( - - start = currtok; - while ( left && currtok.Type != TokType::Capture_End ) - { - eat(currtok.Type); - } - // __attribute__(( - - eat(TokType::Capture_End); - eat(TokType::Capture_End); - // __attribute__(( )) - - s32 len = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)start.Text; - } - - else if ( check(TokType::Decl_MSVC_Attribute) ) - { - eat( TokType::Decl_MSVC_Attribute ); - eat( TokType::Capture_Start); - // __declspec( - - start = currtok; - while ( left && currtok.Type != TokType::Capture_End ) - { - eat(currtok.Type); - } - // __declspec( - - eat(TokType::Capture_End); - // __declspec( ) - - s32 len = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)start.Text; - } - - else if ( currtok.is_attribute() ) - { - eat(currtok.Type); - s32 len = start.Length; - // } if ( len > 0 ) @@ -632,14 +652,13 @@ CodeAttributes parse_attributes() String name_stripped = strip_formatting( attribute_txt, strip_formatting_dont_preserve_newlines ); - Code - result = make_code(); + Code result = make_code(); result->Type = ECode::PlatformAttributes; result->Name = get_cached_string( name_stripped ); result->Content = result->Name; - // result->Token = + // result->Token = - return (CodeAttributes) result; + return ( CodeAttributes )result; } Context.pop(); @@ -699,6 +718,7 @@ Code parse_class_struct( TokType which, bool inplace_def = false ) { access = currtok.to_access_specifier(); // : + eat( currtok.Type ); } Token parent_tok = parse_identifier(); @@ -778,13 +798,20 @@ CodeBody parse_class_struct_body( TokType which, Token name ) bool expects_function = false; - Context.Scope->Start = currtok_noskip; + // Context.Scope->Start = currtok_noskip; if ( currtok_noskip.Type == TokType::Preprocess_Hash ) eat( TokType::Preprocess_Hash ); switch ( currtok_noskip.Type ) { + case TokType::Statement_End: + { + // TODO(Ed): Convert this to a general warning procedure + log_fmt("Dangling end statement found %S\n", currtok_noskip.to_string()); + eat( TokType::Statement_End ); + continue; + } case TokType::NewLine: member = fmt_newline; eat( TokType::NewLine ); @@ -935,12 +962,14 @@ CodeBody parse_class_struct_body( TokType which, Token name ) case TokType::Spec_Consteval: case TokType::Spec_Constexpr: case TokType::Spec_Constinit: + case TokType::Spec_Explicit: case TokType::Spec_ForceInline: case TokType::Spec_Inline: case TokType::Spec_Mutable: case TokType::Spec_NeverInline: case TokType::Spec_Static: case TokType::Spec_Volatile: + case TokType::Spec_Virtual: { SpecifierT specs_found[16] { ESpecifier::NumSpecifiers }; s32 NumSpecifiers = 0; @@ -949,28 +978,40 @@ CodeBody parse_class_struct_body( TokType which, Token name ) { SpecifierT spec = ESpecifier::to_type( currtok ); + b32 ignore_spec = false; + switch ( spec ) { case ESpecifier::Constexpr: case ESpecifier::Constinit: + case ESpecifier::Explicit: case ESpecifier::Inline: case ESpecifier::ForceInline: case ESpecifier::Mutable: case ESpecifier::NeverInline: case ESpecifier::Static: case ESpecifier::Volatile: + case ESpecifier::Virtual: break; case ESpecifier::Consteval: expects_function = true; break; + case ESpecifier::Const : + ignore_spec = true; + break; + default: log_failure( "Invalid specifier %s for variable\n%s", ESpecifier::to_str(spec), Context.to_string() ); Context.pop(); return CodeInvalid; } + // Every specifier after would be considered part of the type type signature + if (ignore_spec) + break; + specs_found[NumSpecifiers] = spec; NumSpecifiers++; eat( currtok.Type ); @@ -982,6 +1023,24 @@ CodeBody parse_class_struct_body( TokType which, Token name ) } // + if ( currtok.is_attribute() ) + { + // Unfortuantely Unreal has code where there is attirbutes before specifiers + CodeAttributes more_attributes = parse_attributes(); + + if ( attributes ) + { + String fused = String::make_reserve( GlobalAllocator, attributes->Content.length() + more_attributes->Content.length() ); + fused.append_fmt( "%S %S", attributes->Content, more_attributes->Content ); + + attributes->Name = get_cached_string(fused); + attributes->Content = attributes->Name; + // + } + + attributes = more_attributes; + } + if ( currtok.Type == TokType::Operator && currtok.Text[0] == '~' ) { member = parse_destructor( specifiers ); @@ -1012,7 +1071,7 @@ CodeBody parse_class_struct_body( TokType which, Token name ) { if ( str_compare( name.Text, currtok.Text, name.Length ) == 0 ) { - member = parse_constructor(); + member = parse_constructor( specifiers ); // () break; } @@ -1082,21 +1141,21 @@ Code parse_complicated_definition( TokType which ) TokArray tokens = Context.Tokens; - s32 idx = tokens.Idx; - s32 level = 0; - for ( ; idx < tokens.Arr.num(); idx ++ ) + s32 idx = tokens.Idx; + s32 level = 0; + for ( ; idx < tokens.Arr.num(); idx++ ) { - if ( tokens[idx].Type == TokType::BraceCurly_Open ) + if ( tokens[ idx ].Type == TokType::BraceCurly_Open ) level++; - if ( tokens[idx].Type == TokType::BraceCurly_Close ) + if ( tokens[ idx ].Type == TokType::BraceCurly_Close ) level--; - if ( level == 0 && tokens[idx].Type == TokType::Statement_End ) + if ( level == 0 && tokens[ idx ].Type == TokType::Statement_End ) break; } - if ( (idx - 2 ) == tokens.Idx ) + if ( ( idx - 2 ) == tokens.Idx ) { // Its a forward declaration only Code result = parse_forward_or_definition( which, is_inplace ); @@ -1106,14 +1165,38 @@ Code parse_complicated_definition( TokType which ) } Token tok = tokens[ idx - 1 ]; + if ( tok.is_specifier() && is_trailing( ESpecifier::to_type(tok)) ) + { + // (...) ...; + + s32 spec_idx = idx - 1; + Token spec = tokens[spec_idx]; + while ( spec.is_specifier() && is_trailing( ESpecifier::to_type(spec)) ) + { + -- spec_idx; + spec = tokens[spec_idx]; + } + + if ( tokens[spec_idx].Type == TokType::Capture_End ) + { + // Forward declaration with trailing specifiers for a procedure + tok = tokens[spec_idx]; + + Code result = parse_operator_function_or_variable( false, { nullptr }, { nullptr } ); + // , or Name> ... + Context.pop(); + return result; + } + + log_failure( "Unsupported or bad member definition after %s declaration\n%s", to_str(which), Context.to_string() ); + Context.pop(); + return CodeInvalid; + } if ( tok.Type == TokType::Identifier ) { tok = tokens[ idx - 2 ]; - - bool is_indirection = tok.Type == TokType::Ampersand - || tok.Type == TokType::Star; - - bool ok_to_parse = false; + bool is_indirection = tok.Type == TokType::Ampersand || tok.Type == TokType::Star; + bool ok_to_parse = false; if ( tok.Type == TokType::BraceCurly_Close ) { @@ -1128,6 +1211,19 @@ Code parse_complicated_definition( TokType which ) // ; ok_to_parse = true; } + else if ( tok.Type == TokType::Assign_Classifer + && ( ( tokens[idx - 5].Type == which && tokens[idx - 4].Type == TokType::Decl_Class ) + || ( tokens[idx - 4].Type == which)) + ) + { + // Its a forward declaration of an enum + // : ; + // : ; + ok_to_parse = true; + Code result = parse_enum(); + Context.pop(); + return result; + } else if ( is_indirection ) { // Its a indirection type with type ID using struct namespace. @@ -1137,7 +1233,7 @@ Code parse_complicated_definition( TokType which ) if ( ! ok_to_parse ) { - log_failure( "Unsupported or bad member definition after struct declaration\n%s", Context.to_string() ); + log_failure( "Unsupported or bad member definition after %s declaration\n%s", to_str(which), Context.to_string() ); Context.pop(); return CodeInvalid; } @@ -1147,6 +1243,27 @@ Code parse_complicated_definition( TokType which ) Context.pop(); return result; } + else if ( tok.Type >= TokType::Type_Unsigned && tok.Type <= TokType::Type_MS_W64 ) + { + tok = tokens[ idx - 2 ]; + + if ( tok.Type != TokType::Assign_Classifer + || ( ( tokens[idx - 5].Type != which && tokens[idx - 4].Type != TokType::Decl_Class ) + && ( tokens[idx - 4].Type != which)) + ) + { + log_failure( "Unsupported or bad member definition after %s declaration\n%s", to_str(which), Context.to_string() ); + Context.pop(); + return CodeInvalid; + } + + // Its a forward declaration of an enum class + // : ; + // : ; + Code result = parse_enum(); + Context.pop(); + return result; + } else if ( tok.Type == TokType::BraceCurly_Close ) { // Its a definition @@ -1155,7 +1272,7 @@ Code parse_complicated_definition( TokType which ) Context.pop(); return result; } - else if ( tok.Type == TokType::BraceSquare_Close) + else if ( tok.Type == TokType::BraceSquare_Close ) { // Its an array definition Code result = parse_operator_function_or_variable( false, { nullptr }, { nullptr } ); @@ -1165,7 +1282,7 @@ Code parse_complicated_definition( TokType which ) } else { - log_failure( "Unsupported or bad member definition after struct declaration\n%s", Context.to_string() ); + log_failure( "Unsupported or bad member definition after %s declaration\n%S", to_str(which).Ptr, Context.to_string() ); Context.pop(); return CodeInvalid; } @@ -1219,6 +1336,40 @@ CodeDefine parse_define() return define; } +internal inline +Code parse_assignment_expression() +{ + Code expr = { nullptr }; + + eat( TokType::Operator ); + // = + + Token expr_tok = currtok; + + if ( currtok.Type == TokType::Statement_End && currtok.Type != TokType::Comma ) + { + log_failure( "Expected expression after assignment operator\n%s", Context.to_string() ); + Context.pop(); + return CodeInvalid; + } + + s32 level = 0; + while ( left && currtok.Type != TokType::Statement_End && (currtok.Type != TokType::Comma || level > 0) ) + { + if (currtok.Type == TokType::Capture_Start) + level++; + else if (currtok.Type == TokType::Capture_End) + level--; + + eat( currtok.Type ); + } + + expr_tok.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )expr_tok.Text - 1; + expr = untyped_str( expr_tok ); + // = + return expr; +} + internal inline Code parse_forward_or_definition( TokType which, bool is_inplace ) { @@ -1294,6 +1445,20 @@ CodeFn parse_function_after_name( } // ( ) { } } + else if ( check(TokType::Operator) && currtok.Text[0] == '=' ) + { + eat(TokType::Operator); + specifiers.append( ESpecifier::Pure ); + + eat( TokType::Number); + Token stmt_end = currtok; + eat( TokType::Statement_End ); + // ( ) = 0; + + if ( currtok_noskip.Type == TokType::Comment && currtok_noskip.Line == stmt_end.Line ) + inline_cmt = parse_comment(); + // ( ) ; + } else { Token stmt_end = currtok; @@ -1340,6 +1505,9 @@ CodeFn parse_function_after_name( result->Type = Function_Fwd; } + if ( attributes ) + result->Attributes = attributes; + if ( specifiers ) result->Specs = specifiers; @@ -1402,6 +1570,8 @@ CodeBody parse_global_nspace( CodeT which ) { using namespace ECode; + push_scope(); + if ( which != Namespace_Body && which != Global_Body && which != Export_Body && which != Extern_Linkage_Body ) return CodeInvalid; @@ -1421,13 +1591,20 @@ CodeBody parse_global_nspace( CodeT which ) bool expects_function = false; - Context.Scope->Start = currtok_noskip; + // Context.Scope->Start = currtok_noskip; if ( currtok_noskip.Type == TokType::Preprocess_Hash ) eat( TokType::Preprocess_Hash ); switch ( currtok_noskip.Type ) { + case TokType::Statement_End: + { + // TODO(Ed): Convert this to a general warning procedure + log_fmt("Dangling end statement found %S\n", currtok_noskip.to_string()); + eat( TokType::Statement_End ); + continue; + } case TokType::NewLine: // Empty lines are auto skipped by Tokens.current() member = fmt_newline; @@ -1608,6 +1785,7 @@ CodeBody parse_global_nspace( CodeT which ) StrC spec_str = ESpecifier::to_str(spec); log_failure( "Invalid specifier %.*s for variable\n%s", spec_str.Len, spec_str, Context.to_string() ); + Context.pop(); return CodeInvalid; } @@ -1637,8 +1815,16 @@ CodeBody parse_global_nspace( CodeT which ) case TokType::Type_double: case TokType::Type_int: { - bool found_operator_cast = false; - s32 idx = Context.Tokens.Idx; + Code constructor_destructor = parse_global_nspace_constructor_destructor( specifiers ); + // Possible constructor implemented at global file scope. + if ( constructor_destructor ) + { + member = constructor_destructor; + break; + } + + bool found_operator_cast_outside_class_implmentation = false; + s32 idx = Context.Tokens.Idx; for ( ; idx < Context.Tokens.Arr.num(); idx++ ) { @@ -1655,12 +1841,12 @@ CodeBody parse_global_nspace( CodeT which ) } if ( tok.Type == TokType::Decl_Operator ) - found_operator_cast = true; + found_operator_cast_outside_class_implmentation = true; break; } - if ( found_operator_cast ) + if ( found_operator_cast_outside_class_implmentation ) { member = parse_operator_cast(); // ::operator () { ... } @@ -1675,6 +1861,7 @@ CodeBody parse_global_nspace( CodeT which ) if ( member == Code::Invalid ) { log_failure( "Failed to parse member\n%s", Context.to_string() ); + Context.pop(); return CodeInvalid; } @@ -1686,6 +1873,135 @@ CodeBody parse_global_nspace( CodeT which ) eat( TokType::BraceCurly_Close ); // { } + Context.pop(); + return result; +} + +internal inline +Code parse_global_nspace_constructor_destructor( CodeSpecifiers specifiers ) +{ + Code result = { nullptr }; + + /* + To check if a definition is for a constructor we can go straight to the opening parenthesis for its parameters + From There we work backwards to see if we come across two identifiers with the same name between an member access + :: operator, there can be template parameters on the left of the :: so we ignore those. + Whats important is that its back to back. + + This has multiple possible faults. What we parse using this method may not filter out if something has a "return type" + This is bad since technically you could have a namespace nested into another namespace with the same name. + If this awful pattern is done the only way to distiguish with this coarse parse is to know there is no return type defined. + + TODO(Ed): We could fix this by attempting to parse a type, but we would have to have a way to have it soft fail and rollback. + */ + TokArray tokens = Context.Tokens; + + s32 idx = tokens.Idx; + Token nav = tokens[ idx ]; + for ( ; idx < tokens.Arr.num(); idx++, nav = tokens[ idx ] ) + { + if ( nav.Text[0] == '<' ) + { + // Skip templated expressions as they mey have expressions with the () operators + s32 capture_level = 0; + s32 template_level = 0; + for ( ; idx < tokens.Arr.num(); idx++, nav = tokens[idx] ) + { + if (nav.Text[ 0 ] == '<') + ++ template_level; + + if (nav.Text[ 0 ] == '>') + -- template_level; + if (nav.Type == TokType::Operator && nav.Text[1] == '>') + -- template_level; + + if ( nav.Type == ETokType::Capture_Start) + { + if (template_level != 0 ) + ++ capture_level; + else + break; + } + + if ( template_level != 0 && nav.Type == ETokType::Capture_End) + -- capture_level; + } + } + + if ( nav.Type == TokType::Capture_Start ) + break; + } + + -- idx; + Token tok_right = tokens[idx]; + Token tok_left = NullToken; + + if (tok_right.Type != TokType::Identifier) + { + // We're not dealing with a constructor if there is no identifier right before the opening of a parameter's scope. + return result; + } + + -- idx; + tok_left = tokens[idx]; + // ... + + bool possible_destructor = false; + if ( tok_left.Type == TokType::Operator && tok_left.Text[0] == '~') + { + possible_destructor = true; + -- idx; + tok_left = tokens[idx]; + } + + if ( tok_left.Type != TokType::Access_StaticSymbol ) + return result; + + -- idx; + tok_left = tokens[idx]; + // ... :: + + // We search toward the left until we find the next valid identifier + s32 capture_level = 0; + s32 template_level = 0; + while ( idx != tokens.Idx ) + { + if (tok_left.Text[ 0 ] == '<') + ++ template_level; + + if (tok_left.Text[ 0 ] == '>') + -- template_level; + if (tok_left.Type == TokType::Operator && tok_left.Text[1] == '>') + -- template_level; + + if ( template_level != 0 && tok_left.Type == ETokType::Capture_Start) + ++ capture_level; + + if ( template_level != 0 && tok_left.Type == ETokType::Capture_End) + -- capture_level; + + if ( capture_level == 0 && template_level == 0 && tok_left.Type == TokType::Identifier ) + break; + + -- idx; + tok_left = tokens[idx]; + } + + bool is_same = str_compare( tok_right.Text, tok_left.Text, tok_right.Length ) == 0; + if (tok_left.Type == TokType::Identifier && is_same) + { + // We have found the pattern we desired + if (possible_destructor) + { + // :: ~ ( + result = parse_destructor( specifiers ); + } + else { + // :: ( + result = parse_constructor( specifiers ); + } + } + return result; } @@ -1717,6 +2033,21 @@ Token parse_identifier( bool* possible_member_function ) return { nullptr, 0, TokType::Invalid }; } + if ( currtok.Type == TokType::Operator && currtok.Text[0] == '~' ) + { + bool is_destructor = str_compare( Context.Scope->Prev->ProcName, "parse_destructor" ) == 0; + if (is_destructor) + { + name.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )name.Text; + Context.pop(); + return name; + } + + log_failure( "Error, had a ~ operator after %S but not a destructor\n%s", ETokType::to_str( prevtok.Type ), Context.to_string() ); + Context.pop(); + return { nullptr, 0, TokType::Invalid }; + } + if ( currtok.Type == TokType::Operator && currtok.Text[0] == '*' && currtok.Length == 1 ) { if ( possible_member_function ) @@ -1819,6 +2150,8 @@ CodeOperator parse_operator_after_ret_type( Context.Scope->Name = currtok; + bool was_new_or_delete = false; + OperatorT op = Invalid; switch ( currtok.Text[0] ) { @@ -2009,7 +2342,65 @@ CodeOperator parse_operator_after_ret_type( break; default: { - break; + StrC str_new = to_str(OperatorT::New); + StrC str_delete = to_str(OperatorT::Delete); + if ( str_compare( currtok.Text, str_new.Ptr, max(str_new.Len - 1, currtok.Length)) == 0) + { + op = OperatorT::New; + eat( ETokType::Identifier ); + was_new_or_delete = true; + + s32 idx = Context.Tokens.Idx + 1; + { + while ( Context.Tokens[ idx ].Type == TokType::NewLine ) + idx++; + } + Token next = Context.Tokens[idx]; + if ( currtok.Type == TokType::Operator && str_compare(currtok.Text, "[]", 2) == 0) + { + eat(ETokType::Operator); + op = OperatorT::NewArray; + } + else if ( currtok.Type == TokType::BraceSquare_Open && next.Type == TokType::BraceSquare_Close) + { + eat(ETokType::BraceSquare_Open); + eat(ETokType::BraceSquare_Close); + op = OperatorT::NewArray; + } + } + else if ( str_compare( currtok.Text, str_delete.Ptr, max(str_delete.Len - 1, currtok.Length )) == 0) + { + op = OperatorT::Delete; + eat(ETokType::Identifier); + was_new_or_delete = true; + + s32 idx = Context.Tokens.Idx + 1; + { + while ( Context.Tokens[ idx ].Type == TokType::NewLine ) + idx++; + } + Token next = Context.Tokens[idx]; + if ( currtok.Type == TokType::Operator && str_compare(currtok.Text, "[]", 2) == 0) + { + eat(ETokType::Operator); + op = OperatorT::DeleteArray; + } + else if ( currtok.Type == TokType::BraceSquare_Open && next.Type == TokType::BraceSquare_Close) + { + eat(ETokType::BraceSquare_Open); + eat(ETokType::BraceSquare_Close); + op = OperatorT::DeleteArray; + } + } + else + { + if ( op == Invalid ) + { + log_failure( "Invalid operator '%s'\n%s", prevtok.Text, Context.to_string() ); + Context.pop(); + return CodeInvalid; + } + } } } @@ -2020,7 +2411,8 @@ CodeOperator parse_operator_after_ret_type( return CodeInvalid; } - eat( currtok.Type ); + if ( ! was_new_or_delete) + eat( currtok.Type ); // operator // Parse Params @@ -2200,23 +2592,23 @@ CodeParam parse_params( bool use_template_capture ) if ( ! use_template_capture ) eat( TokType::Capture_Start ); - // ( + // ( else { - if ( check ( TokType::Operator ) && currtok.Text[0] == '<' ) + if ( check( TokType::Operator ) && currtok.Text[ 0 ] == '<' ) eat( TokType::Operator ); - // < + // < } - if ( ! use_template_capture && check(TokType::Capture_End) ) + if ( ! use_template_capture && check( TokType::Capture_End ) ) { eat( TokType::Capture_End ); // ) Context.pop(); return { nullptr }; } - else if ( check ( TokType::Operator ) && currtok.Text[0] == '>' ) + else if ( check( TokType::Operator ) && currtok.Text[ 0 ] == '>' ) { eat( TokType::Operator ); // > @@ -2224,10 +2616,12 @@ CodeParam parse_params( bool use_template_capture ) return { nullptr }; } + Code macro = { nullptr }; CodeType type = { nullptr }; Code value = { nullptr }; + Token name = NullToken; - if ( check( TokType::Varadic_Argument) ) + if ( check( TokType::Varadic_Argument ) ) { eat( TokType::Varadic_Argument ); // ( or < ... @@ -2238,26 +2632,42 @@ CodeParam parse_params( bool use_template_capture ) // or < ... > } - type = parse_type(); - if ( type == Code::Invalid ) + #define CheckEndParams() \ + (use_template_capture ? (currtok.Text[ 0 ] != '>') : (currtok.Type != TokType::Capture_End)) + + // Ex: Unreal has this type of macro: vvvvvvvvv + // COREUOBJECT_API void CallFunction( FFrame& Stack, RESULT_DECL, UFunction* Function ); + // and: vvvv + // AddComponentByClass(UPARAM(meta = (AllowAbstract = "false")) TSubclassOf Class, bool bManualAttachment, ... + if ( check(TokType::Preprocess_Macro)) { - Context.pop(); - return CodeInvalid; + macro = parse_simple_preprocess(ETokType::Preprocess_Macro); + // ( } - // ( - - Token name = NullToken; - - if ( check( TokType::Identifier ) ) + if ( currtok.Type != TokType::Comma ) { - name = currtok; - eat( TokType::Identifier ); - // ( + type = parse_type( use_template_capture ); + if ( type == Code::Invalid ) + { + Context.pop(); + return CodeInvalid; + } + // ( - if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) ) + if ( check( TokType::Identifier ) ) + { + name = currtok; + eat( TokType::Identifier ); + // ( + } + + // In template captures you can have a typename have direct assignment without a name + // typename = typename ... + // Which would result in a static value type from a struct expansion (traditionally) + if ( ( name.Text || use_template_capture ) && bitfield_is_equal( u32, currtok.Flags, TF_Assign ) ) { eat( TokType::Operator ); - // ( = + // ( = Token value_tok = currtok; @@ -2268,23 +2678,37 @@ CodeParam parse_params( bool use_template_capture ) return CodeInvalid; } - while ( left - && currtok.Type != TokType::Comma - && currtok.Type != TokType::Capture_End - ) + s32 capture_level = 0; + s32 template_level = 0; + while ( left && (currtok.Type != TokType::Comma) && template_level >= 0 && CheckEndParams() || capture_level > 0 || template_level > 0 ) { - value_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)value_tok.Text; + if (currtok.Text[ 0 ] == '<') + ++ template_level; + + if (currtok.Text[ 0 ] == '>') + -- template_level; + if (currtok.Type == TokType::Operator && currtok.Text[1] == '>') + -- template_level; + + if ( currtok.Type == ETokType::Capture_Start) + ++ capture_level; + + if ( currtok.Type == ETokType::Capture_End) + -- capture_level; + + value_tok.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )value_tok.Text; eat( currtok.Type ); } value = untyped_str( strip_formatting( value_tok, strip_formatting_dont_preserve_newlines ) ); - // ( = + // ( = } } - CodeParam - result = (CodeParam) make_code(); - result->Type = Parameters; + CodeParam result = ( CodeParam )make_code(); + result->Type = Parameters; + + result->Macro = macro; if ( name.Length > 0 ) result->Name = get_cached_string( name ); @@ -2296,45 +2720,57 @@ CodeParam parse_params( bool use_template_capture ) result->NumEntries++; - while ( left - && use_template_capture ? - currtok.Type != TokType::Operator && currtok.Text[0] != '>' - : currtok.Type != TokType::Capture_End ) + while ( check(TokType::Comma) ) { eat( TokType::Comma ); - // ( = , + // ( = , Code type = { nullptr }; Code value = { nullptr }; - if ( check( TokType::Varadic_Argument) ) + if ( check( TokType::Varadic_Argument ) ) { eat( TokType::Varadic_Argument ); result.append( param_varadic ); continue; - // ( = , ... + // ( = , ... } - type = parse_type(); - if ( type == Code::Invalid ) + // Ex: Unreal has this type of macro: vvvvvvvvv + // COREUOBJECT_API void CallFunction( FFrame& Stack, RESULT_DECL, UFunction* Function ); + // and: vvvv + // AddComponentByClass(UPARAM(meta = (AllowAbstract = "false")) TSubclassOf Class, bool bManualAttachment, ... + if ( check(TokType::Preprocess_Macro)) { - Context.pop(); - return CodeInvalid; + macro = parse_simple_preprocess(ETokType::Preprocess_Macro); + // ( } - // ( = , - - name = { nullptr, 0, TokType::Invalid, false }; - - if ( check( TokType::Identifier ) ) + if ( currtok.Type != TokType::Comma ) { - name = currtok; - eat( TokType::Identifier ); - // ( = , + type = parse_type( use_template_capture ); + if ( type == Code::Invalid ) + { + Context.pop(); + return CodeInvalid; + } + // ( = , - if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) ) + name = { nullptr, 0, TokType::Invalid, false }; + + if ( check( TokType::Identifier ) ) + { + name = currtok; + eat( TokType::Identifier ); + // ( = , + } + + // In template captures you can have a typename have direct assignment without a name + // typename = typename ... + // Which would result in a static value type from a struct expansion (traditionally) + if ( ( name.Text || use_template_capture ) && bitfield_is_equal( u32, currtok.Flags, TF_Assign ) ) { eat( TokType::Operator ); - // ( = , = + // ( = , = Token value_tok = currtok; @@ -2345,23 +2781,42 @@ CodeParam parse_params( bool use_template_capture ) return CodeInvalid; } + s32 capture_level = 0; + s32 template_level = 0; while ( left - && currtok.Type != TokType::Comma && currtok.Type != TokType::Capture_End - ) + && currtok.Type != TokType::Comma + && template_level >= 0 + && CheckEndParams() + || capture_level > 0 || template_level > 0 ) { - value_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)value_tok.Text; + if (currtok.Text[ 0 ] == '<') + ++ template_level; + + if (currtok.Text[ 0 ] == '>') + -- template_level; + if (currtok.Type == TokType::Operator && currtok.Text[1] == '>') + -- template_level; + + if ( currtok.Type == ETokType::Capture_Start) + ++ capture_level; + + if ( currtok.Type == ETokType::Capture_End) + -- capture_level; + + value_tok.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )value_tok.Text; eat( currtok.Type ); } value = untyped_str( strip_formatting( value_tok, strip_formatting_dont_preserve_newlines ) ); - // ( = , = + // ( = , = } + // ( = , = , .. } - // ( = , = , .. - CodeParam - param = (CodeParam) make_code(); - param->Type = Parameters; + CodeParam param = ( CodeParam )make_code(); + param->Type = Parameters; + + param->Macro = macro; if ( name.Length > 0 ) param->Name = get_cached_string( name ); @@ -2376,23 +2831,23 @@ CodeParam parse_params( bool use_template_capture ) if ( ! use_template_capture ) eat( TokType::Capture_End ); - // ( = , = , .. ) + // ( = , = , .. ) else { - if ( ! check( TokType::Operator) || currtok.Text[0] != '>' ) + if ( ! check( TokType::Operator ) || currtok.Text[ 0 ] != '>' ) { - log_failure("Expected '<' after 'template' keyword\n%s", Context.to_string() ); + log_failure( "Expected '<' after 'template' keyword\n%s", Context.to_string() ); Context.pop(); return CodeInvalid; } eat( TokType::Operator ); - // < = , = , .. > + // < = , = , .. > } Context.pop(); return result; -# undef context +#undef context } internal @@ -2558,29 +3013,33 @@ Code parse_static_assert() internal inline void parse_template_args( Token& token ) { - if ( currtok.Type == TokType::Operator && currtok.Text[0] == '<' && currtok.Length == 1 ) + if ( currtok.Type == TokType::Operator && currtok.Text[ 0 ] == '<' && currtok.Length == 1 ) { eat( TokType::Operator ); // < s32 level = 0; - while ( left && ( currtok.Text[0] != '>' || level > 0 )) + while ( left && level >= 0 && ( currtok.Text[ 0 ] != '>' || level > 0 ) ) { - if ( currtok.Text[0] == '<' ) + if ( currtok.Text[ 0 ] == '<' ) level++; - if ( currtok.Text[0] == '>' ) + if ( currtok.Text[ 0 ] == '>' ) + level--; + if ( currtok.Type == TokType::Operator && currtok.Text[1] == '>') level--; eat( currtok.Type ); } // < - eat( TokType::Operator ); + // Due to the >> token, this could have been eaten early... + if (level == 0) + eat( TokType::Operator ); // < > // Extend length of name to last token - token.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)token.Text; + token.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )token.Text; } } @@ -2602,26 +3061,8 @@ CodeVar parse_variable_after_name( if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) ) { - eat( TokType::Operator ); - // = - - Token expr_tok = currtok; - - if ( currtok.Type == TokType::Statement_End || currtok.Type != TokType::Comma ) - { - log_failure( "Expected expression after assignment operator\n%s", Context.to_string() ); - Context.pop(); - return CodeInvalid; - } - - while ( left && currtok.Type != TokType::Statement_End || currtok.Type != TokType::Comma ) - { - eat( currtok.Type ); - } - - expr_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)expr_tok.Text - 1; - expr = untyped_str( expr_tok ); // = + expr = parse_assignment_expression(); } if ( currtok.Type == TokType::BraceCurly_Open ) @@ -2837,12 +3278,12 @@ CodeClass parse_class( bool inplace_def ) } internal -CodeConstructor parse_constructor() +CodeConstructor parse_constructor( CodeSpecifiers specifiers ) { push_scope(); - Token identifier = parse_identifier(); - CodeParam params = parse_params(); + Token identifier = parse_identifier(); + CodeParam params = parse_params(); // ( ) Code initializer_list = NoCode; @@ -2856,24 +3297,27 @@ CodeConstructor parse_constructor() eat( TokType::Assign_Classifer ); // ( ) : - Token initializer_list_tok = NullToken; + Token initializer_list_tok = currtok; - s32 level = 0; + s32 level = 0; while ( left && ( currtok.Type != TokType::BraceCurly_Open || level > 0 ) ) { - if ( currtok.Type == TokType::BraceCurly_Open ) + if (currtok.Type == TokType::Capture_Start) level++; - else if ( currtok.Type == TokType::BraceCurly_Close ) + else if ( currtok.Type == TokType::Capture_End ) level--; eat( currtok.Type ); } - initializer_list_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)initializer_list_tok.Text; + initializer_list_tok.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )initializer_list_tok.Text; // ( ) : initializer_list = untyped_str( initializer_list_tok ); - body = parse_function_body(); + + // TODO(Ed): Constructors can have post-fix specifiers + + body = parse_function_body(); // ( ) : { } } else if ( check( TokType::BraceCurly_Open ) ) @@ -2881,6 +3325,10 @@ CodeConstructor parse_constructor() body = parse_function_body(); // ( ) { } } + else if ( check( TokType::Operator) && currtok.Text[ 0 ] == '=' ) + { + body = parse_assignment_expression(); + } else { Token stmt_end = currtok; @@ -2889,10 +3337,14 @@ CodeConstructor parse_constructor() if ( currtok_noskip.Type == TokType::Comment && currtok_noskip.Line == stmt_end.Line ) inline_cmt = parse_comment(); - // ( ); + // ( ); } - CodeConstructor result = (CodeConstructor) make_code(); + CodeConstructor result = ( CodeConstructor )make_code(); + + result->Name = get_cached_string(identifier); + + result->Specs = specifiers; if ( params ) result->Params = params; @@ -2900,7 +3352,7 @@ CodeConstructor parse_constructor() if ( initializer_list ) result->InitializerList = initializer_list; - if ( body ) + if ( body && body->Type == ECode::Function_Body ) { result->Body = body; result->Type = ECode::Constructor; @@ -2920,6 +3372,9 @@ CodeDestructor parse_destructor( CodeSpecifiers specifiers ) { push_scope(); + bool has_context = Context.Scope && Context.Scope->Prev; + bool is_in_global_nspace = has_context && str_compare( Context.Scope->Prev->ProcName, "parse_global_nspace" ) == 0; + if ( check( TokType::Spec_Virtual ) ) { if ( specifiers ) @@ -2930,7 +3385,11 @@ CodeDestructor parse_destructor( CodeSpecifiers specifiers ) } // - if ( left && currtok.Text[0] == '~' ) + Token prefix_identifier = NullToken; + if (is_in_global_nspace) + prefix_identifier = parse_identifier(); + + if ( left && currtok.Text[ 0 ] == '~' ) eat( TokType::Operator ); else { @@ -2950,21 +3409,28 @@ CodeDestructor parse_destructor( CodeSpecifiers specifiers ) bool pure_virtual = false; - if ( check( TokType::Operator ) && currtok.Text[0] == '=' ) + if ( check( TokType::Operator ) && currtok.Text[ 0 ] == '=' ) { - eat( TokType::Operator ); // ~() = - if ( left && currtok.Text[0] == '0' ) + bool skip_formatting = true; + Token next = Context.Tokens.next(skip_formatting); + if ( left && next.Text[ 0 ] == '0' ) { + eat( TokType::Operator ); eat( TokType::Number ); // ~() = 0 specifiers.append( ESpecifier::Pure ); } + else if ( left && str_compare( next.Text, "default", sizeof("default") - 1 ) == 0) + { + body = parse_assignment_expression(); + // ~< + } else { - log_failure( "Pure specifier expected due to '=' token\n%s", Context.to_string() ); + log_failure( "Pure or default specifier expected due to '=' token\n%s", Context.to_string() ); return CodeInvalid; } @@ -2973,7 +3439,7 @@ CodeDestructor parse_destructor( CodeSpecifiers specifiers ) if ( ! pure_virtual && check( TokType::BraceCurly_Open ) ) body = parse_function_body(); - // ~() { ... } + // ~() { ... } else { Token stmt_end = currtok; @@ -2982,15 +3448,21 @@ CodeDestructor parse_destructor( CodeSpecifiers specifiers ) if ( currtok_noskip.Type == TokType::Comment && currtok_noskip.Line == stmt_end.Line ) inline_cmt = parse_comment(); - // ~() ; + // ~() ; } - CodeDestructor result = (CodeDestructor) make_code(); + CodeDestructor result = ( CodeDestructor )make_code(); + + if ( prefix_identifier ) + { + prefix_identifier.Length += 1 + identifier.Length; + result->Name = get_cached_string( prefix_identifier ); + } if ( specifiers ) result->Specs = specifiers; - if ( body ) + if ( body && body->Type == ECode::Function_Body ) { result->Body = body; result->Type = ECode::Destructor; @@ -3153,10 +3625,17 @@ CodeEnum parse_enum( bool inplace_def ) } // = + // Unreal UMETA macro support + if ( currtok.Type == TokType::Preprocess_Macro ) + { + eat( TokType::Preprocess_Macro ); + // = + } + if ( currtok.Type == TokType::Comma ) { eat( TokType::Comma ); - // = , + // = , } entry.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)entry.Text; @@ -3299,41 +3778,44 @@ CodeFriend parse_friend() if ( currtok.Type == TokType::Identifier ) { // Name - Token name = parse_identifier(); + Token name = parse_identifier(); Context.Scope->Name = name; // friend + function = parse_function_after_name( ModuleFlag::None, NoCode, NoCode, type, name ); + // Parameter list - CodeParam params = parse_params(); + // CodeParam params = parse_params(); // friend ( ) - function = make_code(); - function->Type = Function_Fwd; - function->Name = get_cached_string( name ); - function->ReturnType = type; + // function = make_code(); + // function->Type = Function_Fwd; + // function->Name = get_cached_string( name ); + // function->ReturnType = type; - if ( params ) - function->Params = params; + // if ( params ) + // function->Params = params; } - Token stmt_end = currtok; - eat( TokType::Statement_End ); - // friend ; - // friend ( ); - CodeComment inline_cmt = NoCode; - if ( currtok_noskip.Type == TokType::Comment && currtok_noskip.Line == stmt_end.Line ) - inline_cmt = parse_comment(); + if ( function && function->Type == ECode::Function_Fwd ) + { + Token stmt_end = currtok; + eat( TokType::Statement_End ); + // friend ; + // friend ( ); + + if ( currtok_noskip.Type == TokType::Comment && currtok_noskip.Line == stmt_end.Line ) + inline_cmt = parse_comment(); // friend ; // friend ( ); + } - CodeFriend - result = (CodeFriend) make_code(); - result->Type = Friend; + CodeFriend result = ( CodeFriend )make_code(); + result->Type = Friend; if ( function ) result->Declaration = function; - else result->Declaration = type; @@ -3650,13 +4132,13 @@ CodeStruct parse_struct( bool inplace_def ) internal CodeTemplate parse_template() { -# define UseTemplateCapture true +#define UseTemplateCapture true push_scope(); ModuleFlag mflags = ModuleFlag::None; - if ( check(TokType::Module_Export) ) + if ( check( TokType::Module_Export ) ) { mflags = ModuleFlag::Export; eat( TokType::Module_Export ); @@ -3699,7 +4181,7 @@ CodeTemplate parse_template() break; } - if ( check( TokType::Decl_Using )) + if ( check( TokType::Decl_Using ) ) { definition = parse_using(); // template< > using ... @@ -3707,73 +4189,123 @@ CodeTemplate parse_template() } // Its either a function or a variable - Token name = { nullptr, 0, TokType::Invalid }; + Token name = { nullptr, 0, TokType::Invalid }; CodeAttributes attributes = { nullptr }; - CodeSpecifiers specifiers = { nullptr }; + CodeSpecifiers specifiers = { nullptr }; - bool expects_function = false; + bool expects_function = false; - SpecifierT specs_found[16] { ESpecifier::NumSpecifiers }; + SpecifierT specs_found[ 16 ] { ESpecifier::NumSpecifiers }; s32 NumSpecifiers = 0; attributes = parse_attributes(); // template< > - while ( left && currtok.is_specifier() ) + // Specifiers Parsing { - SpecifierT spec = ESpecifier::to_type( currtok ); - - switch ( spec ) + while ( left && currtok.is_specifier() ) { - case ESpecifier::Const: - case ESpecifier::Constexpr: - case ESpecifier::Constinit: - case ESpecifier::External_Linkage: - case ESpecifier::Global: - case ESpecifier::Inline: - case ESpecifier::ForceInline: - case ESpecifier::Local_Persist: - case ESpecifier::Mutable: - case ESpecifier::Static: - case ESpecifier::Thread_Local: - case ESpecifier::Volatile: - break; + SpecifierT spec = ESpecifier::to_type( currtok ); - case ESpecifier::Consteval: - expects_function = true; - break; + switch ( spec ) + { + case ESpecifier::Const : + case ESpecifier::Constexpr : + case ESpecifier::Constinit : + case ESpecifier::External_Linkage : + case ESpecifier::Global : + case ESpecifier::Inline : + case ESpecifier::ForceInline : + case ESpecifier::Local_Persist : + case ESpecifier::Mutable : + case ESpecifier::Static : + case ESpecifier::Thread_Local : + case ESpecifier::Volatile : + break; - default: - log_failure( "Invalid specifier %s for variable or function\n%s", ESpecifier::to_str( spec ), Context.to_string() ); - Context.pop(); - return CodeInvalid; + case ESpecifier::Consteval : + expects_function = true; + break; + + default : + log_failure( "Invalid specifier %s for variable or function\n%s", ESpecifier::to_str( spec ), Context.to_string() ); + Context.pop(); + return CodeInvalid; + } + + // Ignore const it will be handled by the type + if ( spec == ESpecifier::Const ) + break; + + specs_found[ NumSpecifiers ] = spec; + NumSpecifiers++; + eat( currtok.Type ); } - // Ignore const it will be handled by the type - if ( spec == ESpecifier::Const ) - continue; - - specs_found[NumSpecifiers] = spec; - NumSpecifiers++; - eat( currtok.Type ); + if ( NumSpecifiers ) + { + specifiers = def_specifiers( NumSpecifiers, specs_found ); + } + // template< > } - if ( NumSpecifiers ) + + bool has_context = Context.Scope && Context.Scope->Prev; + bool is_in_global_nspace = has_context && str_compare( Context.Scope->Prev->ProcName, "parse_global_nspace" ) == 0; + + // Possible constructor implemented at global file scope. + if (is_in_global_nspace) { - specifiers = def_specifiers( NumSpecifiers, specs_found ); + Code constructor_destructor = parse_global_nspace_constructor_destructor( specifiers ); + if ( constructor_destructor ) + { + definition = constructor_destructor; + // :: () { ... } + break; + } } - // template< > - // TODO(Ed) : Port over operator cast detection from parse_global_nspace or parse_class_struct_body + // Possible user Defined operator casts + if (is_in_global_nspace) + { + bool found_operator_cast_outside_class_implmentation = false; + s32 idx = Context.Tokens.Idx; + + for ( ; idx < Context.Tokens.Arr.num(); idx++ ) + { + Token tok = Context.Tokens[ idx ]; + + if ( tok.Type == TokType::Identifier ) + { + idx++; + tok = Context.Tokens[ idx ]; + if ( tok.Type == TokType::Access_StaticSymbol ) + continue; + + break; + } + + if ( tok.Type == TokType::Decl_Operator ) + found_operator_cast_outside_class_implmentation = true; + + break; + } + + if ( found_operator_cast_outside_class_implmentation ) + { + definition = parse_operator_cast( specifiers ); + // :: operator () { ... } + break; + } + } definition = parse_operator_function_or_variable( expects_function, attributes, specifiers ); // template< > ... break; } - CodeTemplate - result = (CodeTemplate) make_code(); + CodeTemplate result = ( CodeTemplate )make_code(); result->Type = ECode::Template; result->Params = params; result->Declaration = definition; @@ -3781,7 +4313,7 @@ CodeTemplate parse_template() Context.pop(); return result; -# undef UseTemplateCapture +#undef UseTemplateCapture } /* @@ -3796,17 +4328,16 @@ CodeTemplate parse_template() The excess whitespace cannot be stripped however, because there is no semantic awareness within the first capture group. */ -internal -CodeType parse_type( bool* typedef_is_function ) +internal CodeType parse_type( bool from_template, bool* typedef_is_function ) { push_scope(); Token context_tok = prevtok; - SpecifierT specs_found[16] { ESpecifier::NumSpecifiers }; + SpecifierT specs_found[ 16 ] { ESpecifier::NumSpecifiers }; s32 NumSpecifiers = 0; - Token name = { nullptr, 0, TokType::Invalid }; + Token name = { nullptr, 0, TokType::Invalid }; // Attributes are assumed to be before the type signature CodeAttributes attributes = parse_attributes(); @@ -3824,7 +4355,7 @@ CodeType parse_type( bool* typedef_is_function ) return CodeInvalid; } - specs_found[NumSpecifiers] = spec; + specs_found[ NumSpecifiers ] = spec; NumSpecifiers++; eat( currtok.Type ); } @@ -3837,48 +4368,55 @@ CodeType parse_type( bool* typedef_is_function ) return CodeInvalid; } - // All kinds of nonsense can makeup a type signature, first we check for a in-place definition of a class, enum, struct, or union - if ( currtok.Type == TokType::Decl_Class - || currtok.Type == TokType::Decl_Enum - || currtok.Type == TokType::Decl_Struct - || currtok.Type == TokType::Decl_Union ) + if ( from_template && currtok.Type == TokType::Decl_Class ) { + // If a value's type is being parsed from a template, class can be used instead of typename. name = currtok; + eat(TokType::Decl_Class); + // + } + + // All kinds of nonsense can makeup a type signature, first we check for a in-place definition of a class, enum, struct, or union + else if ( currtok.Type == TokType::Decl_Class || currtok.Type == TokType::Decl_Enum || currtok.Type == TokType::Decl_Struct + || currtok.Type == TokType::Decl_Union ) + { eat( currtok.Type ); // - name.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)name.Text; - eat( TokType::Identifier ); + name = parse_identifier(); + + // name.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )name.Text; + // eat( TokType::Identifier ); Context.Scope->Name = name; // } // Decltype draft implementaiton #if 0 - else if ( currtok.Type == TokType::DeclType ) +else if ( currtok.Type == TokType::DeclType ) +{ + // Will have a capture and its own parsing rules, were going to just shove everything in a string (for now). + name = currtok; + eat( TokType::DeclType ); + // decltype + + eat( TokType::Capture_Start ); + while ( left && currtok.Type != TokType::Capture_End ) { - // Will have a capture and its own parsing rules, were going to just shove everything in a string (for now). - name = currtok; - eat( TokType::DeclType ); - // decltype + if ( currtok.Type == TokType::Capture_Start ) + level++; - eat( TokType::Capture_Start ); - while ( left && currtok.Type != TokType::Capture_End ) - { - if ( currtok.Type == TokType::Capture_Start ) - level++; + if ( currtok.Type == TokType::Capture_End ) + level--; - if ( currtok.Type == TokType::Capture_End ) - level--; - - eat( currtok.Type ); - } - eat( TokType::Capture_End ); - - name.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)name.Text; - Context.Scope->Name = name; - // decltype( ) + eat( currtok.Type ); } + eat( TokType::Capture_End ); + + name.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)name.Text; + Context.Scope->Name = name; + // decltype( ) +} #endif // Check if native type keywords are used, eat them for the signature. @@ -3894,14 +4432,20 @@ CodeType parse_type( bool* typedef_is_function ) eat( currtok.Type ); } - name.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)name.Text; + name.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )name.Text; // } + else if ( currtok.Type == TokType::Type_Typename ) + { + name = currtok; + eat(TokType::Type_Typename); + // + } // The usual Identifier type signature that may have namespace qualifiers else { - name = parse_identifier(); + name = parse_identifier(); Context.Scope->Name = name; if ( ! name ) { @@ -3918,17 +4462,14 @@ CodeType parse_type( bool* typedef_is_function ) { SpecifierT spec = ESpecifier::to_type( currtok ); - if ( spec != ESpecifier::Const - && spec != ESpecifier::Ptr - && spec != ESpecifier::Ref - && spec != ESpecifier::RValue ) + if ( spec != ESpecifier::Const && spec != ESpecifier::Ptr && spec != ESpecifier::Ref && spec != ESpecifier::RValue ) { log_failure( "Error, invalid specifier used in type definition: %s\n%s", currtok.Text, Context.to_string() ); Context.pop(); return CodeInvalid; } - specs_found[NumSpecifiers] = spec; + specs_found[ NumSpecifiers ] = spec; NumSpecifiers++; eat( currtok.Type ); } @@ -3936,7 +4477,7 @@ CodeType parse_type( bool* typedef_is_function ) #ifdef GEN_USE_NEW_TYPENAME_PARSING if ( NumSpecifiers ) { - specifiers = def_specifiers( NumSpecifiers, specs_found ); + specifiers = def_specifiers( NumSpecifiers, specs_found ); NumSpecifiers = 0; } #endif @@ -3950,8 +4491,8 @@ CodeType parse_type( bool* typedef_is_function ) CodeParam params_nested = NoCode; #endif - bool is_function_typename = false; - Token* last_capture = nullptr; + bool is_function_typename = false; + Token* last_capture = nullptr; { Token* scanner = Context.Tokens.Arr + Context.Tokens.Idx; @@ -3959,7 +4500,7 @@ CodeType parse_type( bool* typedef_is_function ) if ( typedef_is_function && scanner->Type == TokType::Identifier ) { is_function_typename = true; - ++ scanner; + ++scanner; } is_function_typename = scanner->Type == TokType::Capture_Start; @@ -3968,16 +4509,16 @@ CodeType parse_type( bool* typedef_is_function ) { // Go to the end of the signature while ( scanner->Type != TokType::Statement_End && scanner->Type != TokType::BraceCurly_Open ) - ++ scanner; + ++scanner; // Go back to the first capture start found while ( scanner->Type != TokType::Capture_Start ) - -- scanner; + --scanner; last_capture = scanner; } - bool has_context = Context.Scope && Context.Scope->Prev; + bool has_context = Context.Scope && Context.Scope->Prev; bool is_for_opcast = has_context && str_compare( Context.Scope->Prev->ProcName, "parse_operator_cast" ) == 0; if ( is_for_opcast && is_function_typename && last_capture ) { @@ -3999,7 +4540,7 @@ CodeType parse_type( bool* typedef_is_function ) // By this point, decltype should have been taken care of for return type, along with any all its specifiers // The previous information with exception to attributes will be considered the return type. - return_type = (CodeType) make_code(); + return_type = ( CodeType )make_code(); return_type->Type = ECode::Typename; // String @@ -4007,20 +4548,20 @@ CodeType parse_type( bool* typedef_is_function ) // name_stripped.strip_space(); return_type->Name = get_cached_string( name ); - #ifdef GEN_USE_NEW_TYPENAME_PARSING +#ifdef GEN_USE_NEW_TYPENAME_PARSING if ( specifiers ) { return_type->Specs = specifiers; specifiers = nullptr; } - #else +#else if ( NumSpecifiers ) - return_type->Specs = def_specifiers( NumSpecifiers, (SpecifierT*)specs_found ); + return_type->Specs = def_specifiers( NumSpecifiers, ( SpecifierT* )specs_found ); // Reset specifiers, the function itself will have its own suffix specifiers possibly. NumSpecifiers = 0; - #endif +#endif // name = { nullptr, 0, TokType::Invalid }; @@ -4033,7 +4574,8 @@ CodeType parse_type( bool* typedef_is_function ) } // - // If the next token is a capture start and is not the last capture, then we're dealing with function typename whoose identifier is within the capture. + // If the next token is a capture start and is not the last capture, then we're dealing with function typename whoose identifier is within the + // capture. else if ( ( Context.Tokens.Arr + Context.Tokens.Idx ) != last_capture ) { // WIP : Possible alternative without much pain... @@ -4041,10 +4583,10 @@ CodeType parse_type( bool* typedef_is_function ) // Eat Capture Start // Deal with possible binding specifiers (*, &, &&) and modifiers on those bindings (const, volatile) // Parse specifiers for the typename with an optional identifier, - // we can shove these specific specifiers into a specs, and then leave the suffix ones for a separate member of the AST. + // we can shove these specific specifiers into a specs, and then leave the suffix ones for a separate member of the AST. // Parse immeidate capture which would be with parse_params() // Eat Capture End - #ifdef GEN_USE_NEW_TYPENAME_PARSING +#ifdef GEN_USE_NEW_TYPENAME_PARSING eat( TokType::Capture_Start ); // ( @@ -4053,16 +4595,14 @@ CodeType parse_type( bool* typedef_is_function ) { SpecifierT spec = ESpecifier::to_type( currtok ); - if ( spec != ESpecifier::Ptr - && spec != ESpecifier::Ref - && spec != ESpecifier::RValue ) + if ( spec != ESpecifier::Ptr && spec != ESpecifier::Ref && spec != ESpecifier::RValue ) { log_failure( "Error, invalid specifier used in type definition: %s\n%s", currtok.Text, Context.to_string() ); Context.pop(); return CodeInvalid; } - specs_found[NumSpecifiers] = spec; + specs_found[ NumSpecifiers ] = spec; NumSpecifiers++; eat( currtok.Type ); } @@ -4074,20 +4614,20 @@ CodeType parse_type( bool* typedef_is_function ) NumSpecifiers = 0; // ( - if ( check( TokType::Identifier )) + if ( check( TokType::Identifier ) ) name = parse_identifier(); - // ( + // ( // Immeidate parameters - if ( check( TokType::Capture_Start )) + if ( check( TokType::Capture_Start ) ) params_nested = parse_params(); - // ( ( ) + // ( ( ) eat( TokType::Capture_End ); // ( ( ) ) - #else +#else // Starting immediatley with a capture, most likely declaring a typename for a member function pointer. // Everything within this capture will just be shoved into the name field including the capture tokens themselves. name = currtok; @@ -4096,7 +4636,7 @@ CodeType parse_type( bool* typedef_is_function ) // ( s32 level = 0; - while ( left && ( currtok.Type != TokType::Capture_End || level > 0 )) + while ( left && ( currtok.Type != TokType::Capture_End || level > 0 ) ) { if ( currtok.Type == TokType::Capture_Start ) level++; @@ -4109,8 +4649,8 @@ CodeType parse_type( bool* typedef_is_function ) eat( TokType::Capture_End ); // ( ) - name.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)name.Text; - #endif + name.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )name.Text; +#endif } // Were now dealing with the parameters of the function @@ -4122,34 +4662,34 @@ CodeType parse_type( bool* typedef_is_function ) { SpecifierT spec = ESpecifier::to_type( currtok ); - if ( spec != ESpecifier::Const - // TODO : Add support for NoExcept, l-value, volatile, l-value, etc - // && spec != ESpecifier::NoExcept - && spec != ESpecifier::RValue ) + if ( spec != ESpecifier::Const + // TODO : Add support for NoExcept, l-value, volatile, l-value, etc + // && spec != ESpecifier::NoExcept + && spec != ESpecifier::RValue ) { log_failure( "Error, invalid specifier used in type definition: %s\n%s", currtok.Text, Context.to_string() ); Context.pop(); return CodeInvalid; } - specs_found[NumSpecifiers] = spec; + specs_found[ NumSpecifiers ] = spec; NumSpecifiers++; eat( currtok.Type ); } - #ifdef GEN_USE_NEW_TYPENAME_PARSING +#ifdef GEN_USE_NEW_TYPENAME_PARSING if ( NumSpecifiers ) { func_suffix_specs = def_specifiers( NumSpecifiers, specs_found ); NumSpecifiers = 0; } - #endif +#endif // ( ) } // bool is_param_pack = false; - if ( check(TokType::Varadic_Argument) ) + if ( check( TokType::Varadic_Argument ) ) { is_param_pack = true; eat( TokType::Varadic_Argument ); @@ -4158,9 +4698,8 @@ CodeType parse_type( bool* typedef_is_function ) using namespace ECode; - CodeType - result = (CodeType) make_code(); - result->Type = Typename; + CodeType result = ( CodeType )make_code(); + result->Type = Typename; // result->Token = Context.Scope->Start; // Need to wait until were using the new parsing method to do this. @@ -4191,10 +4730,10 @@ CodeType parse_type( bool* typedef_is_function ) result->FuncSuffixSpecs = func_suffix_specs; } #else - if (NumSpecifiers) + if ( NumSpecifiers ) { - Code specifiers = def_specifiers( NumSpecifiers, (SpecifierT*)specs_found ); - result->Specs = specifiers; + Code specifiers = def_specifiers( NumSpecifiers, ( SpecifierT* )specs_found ); + result->Specs = specifiers; } #endif @@ -4350,8 +4889,11 @@ CodeTypedef parse_typedef() } } else - type = parse_type( & is_function ); + { + bool from_template = false; + type = parse_type( from_template, &is_function ); // typedef + } if ( check( TokType::Identifier ) ) { diff --git a/project/components/types.hpp b/project/components/types.hpp index 142f3d3..70c3ca1 100644 --- a/project/components/types.hpp +++ b/project/components/types.hpp @@ -16,9 +16,9 @@ using LogFailType = sw(*)(char const*, ...); enum class AccessSpec : u32 { Default, - Public, - Protected, Private, + Protected, + Public, Num_AccessSpec, Invalid, @@ -30,9 +30,9 @@ char const* to_str( AccessSpec type ) local_persist char const* lookup[ (u32)AccessSpec::Num_AccessSpec ] = { "", - "public", - "protected", "private", + "protected", + "public", }; if ( type > AccessSpec::Public ) diff --git a/project/enums/EOperator.csv b/project/enums/EOperator.csv index b8df2dc..e2c1c97 100644 --- a/project/enums/EOperator.csv +++ b/project/enums/EOperator.csv @@ -41,3 +41,7 @@ MemberOfPointer, "->" PtrToMemOfPtr, "->*" FunctionCall, "()" Comma, "," +New, "new" +NewArray, "new[]" +Delete, "delete" +DeleteArray, "delete[]" diff --git a/project/helpers/helper.hpp b/project/helpers/helper.hpp index 03f4c5b..b67b232 100644 --- a/project/helpers/helper.hpp +++ b/project/helpers/helper.hpp @@ -250,9 +250,9 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path ) char const* attribute_str = attribute_strs[idx].string; char const* entry_to_str = attribute_str_strs [idx].string; - attribute_entries.append_fmt( "%s,\n", attribute_str ); + attribute_entries.append_fmt( "Attribute_%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 ); + attribute_define_entries.append_fmt( "Entry( Attribute_%s, \"%s\" )", attribute_str, entry_to_str ); if ( idx < attribute_strs.num() - 1 ) attribute_define_entries.append( " \\\n"); @@ -265,6 +265,7 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path ) CodeDefine attribute_entires_def = def_define( name(GEN_DEFINE_ATTRIBUTE_TOKENS), attribute_define_entries ); #pragma pop_macro("GEN_DEFINE_ATTRIBUTE_TOKENS") + // We cannot parse this enum, it has Attribute names as enums CodeEnum enum_code = parse_enum(token_fmt("entries", (StrC)enum_entries, "attribute_toks", (StrC)attribute_entries, stringize( enum Type : u32 { diff --git a/scripts/.clang-format b/scripts/.clang-format index 06805ad..eeda36b 100644 --- a/scripts/.clang-format +++ b/scripts/.clang-format @@ -151,17 +151,17 @@ SpaceBeforeRangeBasedForLoopColon: true SpaceBeforeSquareBrackets: false SpacesBeforeTrailingComments: 4 -SpaceInEmptyBlock: true +SpaceInEmptyBlock: false SpaceInEmptyParentheses: false -SpacesInAngles: true -SpacesInCStyleCastParentheses: true -SpacesInConditionalStatement: true -SpacesInContainerLiterals: true +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: false SpacesInLineCommentPrefix: Minimum: 1 Maximum: 20 SpacesInParentheses: true -SpacesInSquareBrackets: true +SpacesInSquareBrackets: false Standard: c++17