Can parse AActor with gencpp
This commit is contained in:
		| @@ -9,7 +9,7 @@ UGasaAttributeSet::UGasaAttributeSet() | |||||||
| { | { | ||||||
| 	InitHealth( 100.f ); | 	InitHealth( 100.f ); | ||||||
| 	InitMaxHealth( 100.f ); | 	InitMaxHealth( 100.f ); | ||||||
| 	InitMana( ( 50.f ) ); | 	InitMana( 50.f ); | ||||||
| 	InitMaxMana( 50.f ); | 	InitMaxMana( 50.f ); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -26,16 +26,12 @@ int gen_main() | |||||||
| 	StrC str_generated_uclass_body                                 = txt("GENERATED_UCLASS_BODY("); | 	StrC str_generated_uclass_body                                 = txt("GENERATED_UCLASS_BODY("); | ||||||
| 	StrC str_property_binding_impl                                 = txt("PROPERTY_BINDING_IMPLEMENTATION"); | 	StrC str_property_binding_impl                                 = txt("PROPERTY_BINDING_IMPLEMENTATION"); | ||||||
| 	StrC str_uclass                                                = txt("UCLASS("); | 	StrC str_uclass                                                = txt("UCLASS("); | ||||||
| 	StrC str_ue_deprecated         = txt("UE_DEPRECATED("); |  | ||||||
| 	StrC str_ufunction                                             = txt("UFUNCTION("); | 	StrC str_ufunction                                             = txt("UFUNCTION("); | ||||||
| 	StrC str_uproperty                                             = txt("UPROPERTY("); | 	StrC str_uproperty                                             = txt("UPROPERTY("); | ||||||
| 	StrC str_umg_api               = txt("UMG_API"); |  | ||||||
|  |  | ||||||
| 	StrC str_declare_log_category_extern                           = txt("DECLARE_LOG_CATEGORY_EXTERN("); | 	StrC str_declare_log_category_extern                           = txt("DECLARE_LOG_CATEGORY_EXTERN("); | ||||||
| 	StrC str_enum_class_flags                                      = txt("ENUM_CLASS_FLAGS("); | 	StrC str_enum_class_flags                                      = txt("ENUM_CLASS_FLAGS("); | ||||||
| 	StrC str_declare_class                                         = txt("DECLARE_CLASS("); | 	StrC str_declare_class                                         = txt("DECLARE_CLASS("); | ||||||
| 	StrC str_define_default_object_initializer_constructor_call    = txt("DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL("); | 	StrC str_define_default_object_initializer_constructor_call    = txt("DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL("); | ||||||
| 	StrC str_core_object_api = txt("COREUOBJECT_API"); |  | ||||||
| 	StrC str_macro_text                                            = txt("TEXT("); | 	StrC str_macro_text                                            = txt("TEXT("); | ||||||
| 	StrC str_declare_multicast_delegate_one_parameter              = txt("DECLARE_MULTICAST_DELEGATE_OneParam("); | 	StrC str_declare_multicast_delegate_one_parameter              = txt("DECLARE_MULTICAST_DELEGATE_OneParam("); | ||||||
| 	StrC str_declare_multicast_delegate_two_parameter              = txt("DECLARE_MULTICAST_DELEGATE_TwoParams("); | 	StrC str_declare_multicast_delegate_two_parameter              = txt("DECLARE_MULTICAST_DELEGATE_TwoParams("); | ||||||
| @@ -45,20 +41,36 @@ int gen_main() | |||||||
| 	StrC str_result_decl                                           = txt("RESULT_DECL"); | 	StrC str_result_decl                                           = txt("RESULT_DECL"); | ||||||
| 	StrC str_property_binding_implementation                       = txt("PROPERTY_BINDING_IMPLEMENTATION("); | 	StrC str_property_binding_implementation                       = txt("PROPERTY_BINDING_IMPLEMENTATION("); | ||||||
| 	StrC str_FORCEINLINE                                           = txt("FORCEINLINE"); | 	StrC str_FORCEINLINE                                           = txt("FORCEINLINE"); | ||||||
|  | 	StrC str_UENUM                                                 = txt("UENUM("); | ||||||
|  | 	StrC str_UMETA                                                 = txt("UMETA("); | ||||||
|  | 	StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams  = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams("); | ||||||
|  | 	StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SevenParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SevenParams("); | ||||||
|  | 	StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams  = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams("); | ||||||
|  | 	StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams  = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams("); | ||||||
|  | 	StrC str_DECLARE_DELEGATE_SixParams                            = txt("DECLARE_DELEGATE_SixParams("); | ||||||
|  | 	StrC str_DECLARE_EVENT_TwoParams                               = txt("DECLARE_EVENT_TwoParams("); | ||||||
|  | 	StrC str_DECLARE_DELEGATE_RetVal_ThreeParams                   = txt("DECLARE_DELEGATE_RetVal_ThreeParams("); | ||||||
|  | 	StrC str_PRAGMA_DISABLE_DEPRECATION_WARNINGS                   = txt("PRAGMA_DISABLE_DEPRECATION_WARNINGS"); | ||||||
|  | 	StrC str_PRAGMA_ENABLE_DEPRECATION_WARNINGS                    = txt("PRAGMA_ENABLE_DEPRECATION_WARNINGS"); | ||||||
|  | 	StrC str_DEFINE_ACTORDESC_TYPE                                 = txt("DEFINE_ACTORDESC_TYPE("); | ||||||
|  | 	StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams   = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams("); | ||||||
|  | 	StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam    = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam("); | ||||||
|  | 	StrC str_UPARAM                                                = txt("UPARAM("); | ||||||
|  | 	StrC str_FORCEINLINE_DEBUGGABLE                                = txt("FORCEINLINE_DEBUGGABLE"); | ||||||
|  |  | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_generated_body)); | 	PreprocessorDefines.append( get_cached_string(str_generated_body)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_generated_uclass_body)); | 	PreprocessorDefines.append( get_cached_string(str_generated_uclass_body)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_property_binding_impl)); | 	PreprocessorDefines.append( get_cached_string(str_property_binding_impl)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_ue_deprecated)); | 	// PreprocessorDefines.append( get_cached_string(str_ue_deprecated)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_uclass)); | 	PreprocessorDefines.append( get_cached_string(str_uclass)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_ufunction)); | 	PreprocessorDefines.append( get_cached_string(str_ufunction)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_uproperty)); | 	PreprocessorDefines.append( get_cached_string(str_uproperty)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_umg_api)); | 	// PreprocessorDefines.append( get_cached_string(str_umg_api)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_declare_log_category_extern)); | 	PreprocessorDefines.append( get_cached_string(str_declare_log_category_extern)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_enum_class_flags)); | 	PreprocessorDefines.append( get_cached_string(str_enum_class_flags)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_declare_class)); | 	PreprocessorDefines.append( get_cached_string(str_declare_class)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_define_default_object_initializer_constructor_call)); | 	PreprocessorDefines.append( get_cached_string(str_define_default_object_initializer_constructor_call)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_core_object_api)); | 	// PreprocessorDefines.append( get_cached_string(str_core_object_api)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_macro_text)); | 	PreprocessorDefines.append( get_cached_string(str_macro_text)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_declare_multicast_delegate_one_parameter)); | 	PreprocessorDefines.append( get_cached_string(str_declare_multicast_delegate_one_parameter)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_declare_multicast_delegate_two_parameter)); | 	PreprocessorDefines.append( get_cached_string(str_declare_multicast_delegate_two_parameter)); | ||||||
| @@ -68,11 +80,31 @@ int gen_main() | |||||||
| 	PreprocessorDefines.append( get_cached_string(str_result_decl)); | 	PreprocessorDefines.append( get_cached_string(str_result_decl)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_property_binding_implementation)); | 	PreprocessorDefines.append( get_cached_string(str_property_binding_implementation)); | ||||||
| 	PreprocessorDefines.append( get_cached_string(str_FORCEINLINE)); | 	PreprocessorDefines.append( get_cached_string(str_FORCEINLINE)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_UENUM)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_UMETA)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SevenParams)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_DECLARE_DELEGATE_SixParams)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_DECLARE_EVENT_TwoParams)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_DECLARE_DELEGATE_RetVal_ThreeParams)); | ||||||
|  | 	// PreprocessorDefines.append( get_cached_string(str_ENGINE_API)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_PRAGMA_DISABLE_DEPRECATION_WARNINGS)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_PRAGMA_ENABLE_DEPRECATION_WARNINGS)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_DEFINE_ACTORDESC_TYPE)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_UPARAM)); | ||||||
|  | 	PreprocessorDefines.append( get_cached_string(str_FORCEINLINE_DEBUGGABLE)); | ||||||
|  |  | ||||||
|  | 	FileContents content; | ||||||
|  |  | ||||||
| #define path_UProgressBar \ | #define path_UProgressBar \ | ||||||
| 	"C:/projects/Unreal/Surgo/UE/Engine/Source/Runtime/UMG/Public/Components/ProgressBar.h" | 	"C:/projects/Unreal/Surgo/UE/Engine/Source/Runtime/UMG/Public/Components/ProgressBar.h" | ||||||
|  |  | ||||||
| 	FileContents content = file_read_contents( GlobalAllocator, true, path_UProgressBar ); | #if 0 | ||||||
|  | 	content = file_read_contents( GlobalAllocator, true, path_UProgressBar ); | ||||||
| 	CodeBody parsed_uprogressbar = parse_global_body( StrC { content.size, (char const*)content.data }); | 	CodeBody parsed_uprogressbar = parse_global_body( StrC { content.size, (char const*)content.data }); | ||||||
|  |  | ||||||
| 	log_fmt("\n\n"); | 	log_fmt("\n\n"); | ||||||
| @@ -93,22 +125,63 @@ int gen_main() | |||||||
| 					case CodeT::Function_Fwd: | 					case CodeT::Function_Fwd: | ||||||
| 						if ( class_code->Name ) | 						if ( class_code->Name ) | ||||||
| 						{ | 						{ | ||||||
| 							log_fmt("%s\n", class_code->Name ); | 							// log_fmt("%s\n", class_code->Name ); | ||||||
|  | 							log_fmt("%s\n", class_code->to_string() ); | ||||||
| 						} | 						} | ||||||
| 					break; | 					break; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #define path_UObject \ | #define path_UObject \ | ||||||
| 	R"(C:\projects\Unreal\Surgo\UE\Engine\Source\Runtime\CoreUObject\Public\UObject\Object.h)" | 	R"(C:\projects\Unreal\Surgo\UE\Engine\Source\Runtime\CoreUObject\Public\UObject\Object.h)" | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
| 	content = file_read_contents( GlobalAllocator, true, path_UObject ); | 	content = file_read_contents( GlobalAllocator, true, path_UObject ); | ||||||
| 	CodeBody parsed_uobject = parse_global_body( StrC { content.size, (char const*)content.data }); | 	CodeBody parsed_uobject = parse_global_body( StrC { content.size, (char const*)content.data }); | ||||||
|  |  | ||||||
| 	log_fmt("\n\n"); | 	log_fmt("\n\n"); | ||||||
| 	for ( Code gcode : parsed_uobject ) | 	for ( Code gcode : parsed_uobject ) | ||||||
|  | 	{ | ||||||
|  | 		if ( gcode->Type == CodeT::Class ) | ||||||
|  | 		{ | ||||||
|  | 			log_fmt("Class %S - Definitions:\n", gcode->Name); | ||||||
|  | 			// log_fmt("%s\n", gcode->to_string() ); | ||||||
|  |  | ||||||
|  | 			if (gcode->Body->Type != CodeT::Class_Body) | ||||||
|  | 				continue; | ||||||
|  | 			for ( Code class_code : gcode->Body->cast<CodeBody>() ) | ||||||
|  | 			{ | ||||||
|  | 				switch ( class_code->Type ) | ||||||
|  | 				{ | ||||||
|  | 					case CodeT::Constructor: | ||||||
|  | 					case CodeT::Constructor_Fwd: | ||||||
|  | 					case CodeT::Variable: | ||||||
|  | 					case CodeT::Function: | ||||||
|  | 					case CodeT::Function_Fwd: | ||||||
|  | 						if ( class_code->Name ) | ||||||
|  | 						{ | ||||||
|  | 							log_fmt("%s\n", class_code->Name ); | ||||||
|  | 							// log_fmt("%s\n", class_code->to_string() ); | ||||||
|  | 						} | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #define path_AActor \ | ||||||
|  | 	R"(C:\projects\Unreal\Surgo\UE\Engine\Source\Runtime\Engine\Classes\GameFramework\Actor.h)" | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
|  | 	content = file_read_contents( GlobalAllocator, true, path_AActor ); | ||||||
|  | 	CodeBody parsed_aactor = parse_global_body( StrC { content.size, (char const*)content.data }); | ||||||
|  |  | ||||||
|  | 	log_fmt("\n\n"); | ||||||
|  | 	for ( Code gcode : parsed_aactor ) | ||||||
| 	{ | 	{ | ||||||
| 		if ( gcode->Type == CodeT::Class ) | 		if ( gcode->Type == CodeT::Class ) | ||||||
| 		{ | 		{ | ||||||
| @@ -121,8 +194,8 @@ int gen_main() | |||||||
| 				switch ( class_code->Type ) | 				switch ( class_code->Type ) | ||||||
| 				{ | 				{ | ||||||
| 					case CodeT::Variable: | 					case CodeT::Variable: | ||||||
| 					case CodeT::Function: | 					// case CodeT::Function: | ||||||
| 					case CodeT::Function_Fwd: | 					// case CodeT::Function_Fwd: | ||||||
| 						if ( class_code->Name ) | 						if ( class_code->Name ) | ||||||
| 						{ | 						{ | ||||||
| 							log_fmt("%s\n", class_code->Name ); | 							log_fmt("%s\n", class_code->Name ); | ||||||
| @@ -132,8 +205,9 @@ int gen_main() | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
| 	StrC str_gasa_api = txt("GASA_API"); | 	// StrC str_gasa_api = txt("GASA_API"); | ||||||
|  |  | ||||||
| 	gen_UGasaAttributeSet(); | 	gen_UGasaAttributeSet(); | ||||||
| 	return 0; | 	return 0; | ||||||
|   | |||||||
| @@ -114,7 +114,7 @@ void gen_UGasaAttributeSet() | |||||||
| 				{ | 				{ | ||||||
| 					InitHealth( 100.f ); | 					InitHealth( 100.f ); | ||||||
| 					InitMaxHealth( 100.f ); | 					InitMaxHealth( 100.f ); | ||||||
| 					InitMana(( 50.f )); | 					InitMana( 50.f ); | ||||||
| 					InitMaxMana( 50.f ); | 					InitMaxMana( 50.f ); | ||||||
| 				} | 				} | ||||||
| 			)); | 			)); | ||||||
|   | |||||||
| @@ -1588,7 +1588,12 @@ void CodeConstructor::to_string_def( String& result ) | |||||||
| void CodeConstructor::to_string_fwd( String& result ) | void CodeConstructor::to_string_fwd( String& result ) | ||||||
| { | { | ||||||
| 	AST* ClassStructParent = ast->Parent->Parent; | 	AST* ClassStructParent = ast->Parent->Parent; | ||||||
|  | 	if (ClassStructParent) { | ||||||
| 		result.append( ClassStructParent->Name ); | 		result.append( ClassStructParent->Name ); | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		result.append( ast->Name ); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if ( ast->Params ) | 	if ( ast->Params ) | ||||||
| 		result.append_fmt( "( %S )", ast->Params.to_string() ); | 		result.append_fmt( "( %S )", ast->Params.to_string() ); | ||||||
| @@ -2273,10 +2278,9 @@ void CodeParam::to_string( String& result ) | |||||||
| { | { | ||||||
| 	if ( ast->Macro ) | 	if ( ast->Macro ) | ||||||
| 	{ | 	{ | ||||||
| 		// Were using the convention that if the value type is a macro we ignore everything else |  | ||||||
| 		// Related to parsing: ( <macro>, ... ) | 		// Related to parsing: ( <macro>, ... ) | ||||||
| 		result.append( ast->Macro.ast->Content ); | 		result.append( ast->Macro.ast->Content ); | ||||||
| 		return; | 		// Could also be: ( <macro> <type <name>, ... ) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if ( ast->Name ) | 	if ( ast->Name ) | ||||||
| @@ -2285,8 +2289,9 @@ void CodeParam::to_string( String& result ) | |||||||
| 			result.append_fmt( " %S", ast->Name ); | 			result.append_fmt( " %S", ast->Name ); | ||||||
| 		else | 		else | ||||||
| 			result.append_fmt( " %S %S", ast->ValueType.to_string(), ast->Name ); | 			result.append_fmt( " %S %S", ast->ValueType.to_string(), ast->Name ); | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
| 	else | 	else if ( ast->ValueType ) | ||||||
| 		result.append_fmt( " %S", ast->ValueType.to_string() ); | 		result.append_fmt( " %S", ast->ValueType.to_string() ); | ||||||
|  |  | ||||||
| 	if ( ast->Value ) | 	if ( ast->Value ) | ||||||
| @@ -5599,7 +5604,14 @@ namespace parser | |||||||
| { | { | ||||||
| 	namespace ETokType | 	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( API_Export, "GEN_API_Export_Code" ) \ | ||||||
|  | 	Entry( API_Import, "GEN_API_Import_Code" ) \ | ||||||
|  | 	Entry( UE_DEPRECATED, "UE_DEPRECATED(" ) \ | ||||||
|  | 	Entry( UMG_API, "UMG_API" ) \ | ||||||
|  | 	Entry( COREUOBJECT_API, "COREUOBJECT_API" ) \ | ||||||
|  | 	Entry( ENGINE_API, "ENGINE_API" ) \ | ||||||
|  | 	Entry( GASA_API, "GASA_API" ) | ||||||
|  |  | ||||||
| 		enum Type : u32 | 		enum Type : u32 | ||||||
| 		{ | 		{ | ||||||
| @@ -5700,6 +5712,11 @@ namespace parser | |||||||
| 			__Attributes_Start, | 			__Attributes_Start, | ||||||
| 			API_Export, | 			API_Export, | ||||||
| 			API_Import, | 			API_Import, | ||||||
|  | 			UE_DEPRECATED, | ||||||
|  | 			UMG_API, | ||||||
|  | 			COREUOBJECT_API, | ||||||
|  | 			ENGINE_API, | ||||||
|  | 			GASA_API, | ||||||
| 			NumTokens | 			NumTokens | ||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| @@ -5803,6 +5820,11 @@ namespace parser | |||||||
| 				{ sizeof( "__attrib_start__" ),    "__attrib_start__"    }, | 				{ sizeof( "__attrib_start__" ),    "__attrib_start__"    }, | ||||||
| 				{ sizeof( "GEN_API_Export_Code" ), "GEN_API_Export_Code" }, | 				{ sizeof( "GEN_API_Export_Code" ), "GEN_API_Export_Code" }, | ||||||
| 				{ sizeof( "GEN_API_Import_Code" ), "GEN_API_Import_Code" }, | 				{ sizeof( "GEN_API_Import_Code" ), "GEN_API_Import_Code" }, | ||||||
|  | 				{ sizeof( "UE_DEPRECATED" ),       "UE_DEPRECATED"       }, | ||||||
|  | 				{ sizeof( "UMG_API" ),             "UMG_API"             }, | ||||||
|  | 				{ sizeof( "COREUOBJECT_API" ),     "COREUOBJECT_API"     }, | ||||||
|  | 				{ sizeof( "ENGINE_API" ),          "ENGINE_API"          }, | ||||||
|  | 				{ sizeof( "GASA_API" ),            "GASA_API"            }, | ||||||
| 			}; | 			}; | ||||||
| 			return lookup[ type ]; | 			return lookup[ type ]; | ||||||
| 		} | 		} | ||||||
| @@ -5982,7 +6004,7 @@ namespace parser | |||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	global Arena_64KB defines_map_arena; | 	global Arena_128KB defines_map_arena; | ||||||
| 	global HashTable< StrC > defines; | 	global HashTable< StrC > defines; | ||||||
| 	global Array< Token > Tokens; | 	global Array< Token > Tokens; | ||||||
|  |  | ||||||
| @@ -6283,6 +6305,11 @@ namespace parser | |||||||
| 			token.Flags |= TF_AccessSpecifier; | 			token.Flags |= TF_AccessSpecifier; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		if ( type > TokType::__Attributes_Start ) | ||||||
|  | 		{ | ||||||
|  | 			token.Flags |= TF_Attribute; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		if ( type == ETokType::Decl_Extern_Linkage ) | 		if ( type == ETokType::Decl_Extern_Linkage ) | ||||||
| 		{ | 		{ | ||||||
| 			SkipWhitespace(); | 			SkipWhitespace(); | ||||||
| @@ -7174,7 +7201,7 @@ namespace parser | |||||||
| 	{ | 	{ | ||||||
| 		Tokens            = Array< Token >::init_reserve( LexArena, ( LexAllocator_Size - sizeof( Array< Token >::Header ) ) / sizeof( Token ) ); | 		Tokens            = Array< Token >::init_reserve( LexArena, ( LexAllocator_Size - sizeof( Array< Token >::Header ) ) / sizeof( Token ) ); | ||||||
|  |  | ||||||
| 		defines_map_arena = Arena_64KB::init(); | 		defines_map_arena = Arena_128KB::init(); | ||||||
| 		defines           = HashTable< StrC >::init( defines_map_arena ); | 		defines           = HashTable< StrC >::init( defines_map_arena ); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -7256,7 +7283,7 @@ namespace parser | |||||||
| 	internal CodeStruct      parse_struct( bool inplace_def = false ); | 	internal CodeStruct      parse_struct( bool inplace_def = false ); | ||||||
| 	internal CodeVar         parse_variable(); | 	internal CodeVar         parse_variable(); | ||||||
| 	internal CodeTemplate    parse_template(); | 	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 CodeTypedef     parse_typedef(); | ||||||
| 	internal CodeUnion       parse_union( bool inplace_def = false ); | 	internal CodeUnion       parse_union( bool inplace_def = false ); | ||||||
| 	internal CodeUsing       parse_using(); | 	internal CodeUsing       parse_using(); | ||||||
| @@ -7594,15 +7621,18 @@ namespace parser | |||||||
| 	{ | 	{ | ||||||
| 		push_scope(); | 		push_scope(); | ||||||
|  |  | ||||||
| 		Token start = NullToken; | 		Token start = currtok; | ||||||
| 		s32   len   = 0; | 		s32   len   = 0; | ||||||
|  |  | ||||||
|  | 		// 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() ) | ||||||
|  | 		{ | ||||||
| 			if ( check( TokType::Attribute_Open ) ) | 			if ( check( TokType::Attribute_Open ) ) | ||||||
| 			{ | 			{ | ||||||
| 				eat( 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( currtok.Type ); | ||||||
| @@ -7612,9 +7642,8 @@ namespace parser | |||||||
| 				eat( TokType::Attribute_Close ); | 				eat( TokType::Attribute_Close ); | ||||||
| 				// [[ <Content> ]] | 				// [[ <Content> ]] | ||||||
|  |  | ||||||
| 			s32 len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; | 				len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			else if ( check( TokType::Decl_GNU_Attribute ) ) | 			else if ( check( TokType::Decl_GNU_Attribute ) ) | ||||||
| 			{ | 			{ | ||||||
| 				eat( TokType::Decl_GNU_Attribute ); | 				eat( TokType::Decl_GNU_Attribute ); | ||||||
| @@ -7622,7 +7651,6 @@ namespace parser | |||||||
| 				eat( TokType::Capture_Start ); | 				eat( TokType::Capture_Start ); | ||||||
| 				// __attribute__(( | 				// __attribute__(( | ||||||
|  |  | ||||||
| 			start = currtok; |  | ||||||
| 				while ( left && currtok.Type != TokType::Capture_End ) | 				while ( left && currtok.Type != TokType::Capture_End ) | ||||||
| 				{ | 				{ | ||||||
| 					eat( currtok.Type ); | 					eat( currtok.Type ); | ||||||
| @@ -7633,16 +7661,14 @@ namespace parser | |||||||
| 				eat( TokType::Capture_End ); | 				eat( TokType::Capture_End ); | ||||||
| 				// __attribute__(( <Content> )) | 				// __attribute__(( <Content> )) | ||||||
|  |  | ||||||
| 			s32 len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; | 				len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			else if ( check( TokType::Decl_MSVC_Attribute ) ) | 			else if ( check( TokType::Decl_MSVC_Attribute ) ) | ||||||
| 			{ | 			{ | ||||||
| 				eat( TokType::Decl_MSVC_Attribute ); | 				eat( TokType::Decl_MSVC_Attribute ); | ||||||
| 				eat( TokType::Capture_Start ); | 				eat( TokType::Capture_Start ); | ||||||
| 				// __declspec( | 				// __declspec( | ||||||
|  |  | ||||||
| 			start = currtok; |  | ||||||
| 				while ( left && currtok.Type != TokType::Capture_End ) | 				while ( left && currtok.Type != TokType::Capture_End ) | ||||||
| 				{ | 				{ | ||||||
| 					eat( currtok.Type ); | 					eat( currtok.Type ); | ||||||
| @@ -7652,14 +7678,33 @@ namespace parser | |||||||
| 				eat( TokType::Capture_End ); | 				eat( TokType::Capture_End ); | ||||||
| 				// __declspec( <Content> ) | 				// __declspec( <Content> ) | ||||||
|  |  | ||||||
| 			s32 len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; | 				len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			else if ( currtok.is_attribute() ) | 			else if ( currtok.is_attribute() ) | ||||||
| 			{ | 			{ | ||||||
| 				eat( currtok.Type ); | 				eat( currtok.Type ); | ||||||
| 			s32 len = start.Length; |  | ||||||
| 				// <Attribute> | 				// <Attribute> | ||||||
|  |  | ||||||
|  | 				// 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; | ||||||
|  | 				// <Attribute> ( ... ) | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if ( len > 0 ) | 		if ( len > 0 ) | ||||||
| @@ -8036,6 +8081,24 @@ namespace parser | |||||||
| 					} | 					} | ||||||
| 					// <Attributes> <Specifiers> | 					// <Attributes> <Specifiers> | ||||||
|  |  | ||||||
|  | 					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> <Specifiers> <Attributes> | ||||||
|  | 						} | ||||||
|  |  | ||||||
|  | 						attributes = more_attributes; | ||||||
|  | 					} | ||||||
|  |  | ||||||
| 					if ( currtok.Type == TokType::Operator && currtok.Text[ 0 ] == '~' ) | 					if ( currtok.Type == TokType::Operator && currtok.Text[ 0 ] == '~' ) | ||||||
| 					{ | 					{ | ||||||
| 						member = parse_destructor( specifiers ); | 						member = parse_destructor( specifiers ); | ||||||
| @@ -8451,6 +8514,9 @@ namespace parser | |||||||
| 			result->Type = Function_Fwd; | 			result->Type = Function_Fwd; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		if ( attributes ) | ||||||
|  | 			result->Attributes = attributes; | ||||||
|  |  | ||||||
| 		if ( specifiers ) | 		if ( specifiers ) | ||||||
| 			result->Specs = specifiers; | 			result->Specs = specifiers; | ||||||
|  |  | ||||||
| @@ -9339,30 +9405,42 @@ namespace parser | |||||||
| 			// or < ... > | 			// or < ... > | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Ex: Unreal has this type of macro:                 vvvvvvvv | 		#define CheckEndParams() \ | ||||||
| 		// COREUOBJECT_API void CallFunction( FFrame& Stack, RESULT_DECL, UFunction* Function ); | 			(use_template_capture ? (currtok.Text[ 0 ] != '>') : (currtok.Type != TokType::Capture_End)) | ||||||
| 		// This is so that a 'ValueType for the param is a preprocesor macro to support this nasty macro usage' |  | ||||||
|  |  | ||||||
| 		if ( ! check(TokType::Preprocess_Macro)) | 		// 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<UActorComponent> Class, bool bManualAttachment, ... | ||||||
|  | 		if ( check(TokType::Preprocess_Macro)) | ||||||
| 		{ | 		{ | ||||||
| 			type = parse_type(); | 			macro = parse_simple_preprocess(ETokType::Preprocess_Macro); | ||||||
|  | 			// ( <Macro> | ||||||
|  | 		} | ||||||
|  | 		if ( currtok.Type != TokType::Comma ) | ||||||
|  | 		{ | ||||||
|  | 			type = parse_type( use_template_capture ); | ||||||
| 			if ( type == Code::Invalid ) | 			if ( type == Code::Invalid ) | ||||||
| 			{ | 			{ | ||||||
| 				Context.pop(); | 				Context.pop(); | ||||||
| 				return CodeInvalid; | 				return CodeInvalid; | ||||||
| 			} | 			} | ||||||
| 			// ( <ValueType> | 			// ( <Macro> <ValueType> | ||||||
|  |  | ||||||
| 			if ( check( TokType::Identifier ) ) | 			if ( check( TokType::Identifier ) ) | ||||||
| 			{ | 			{ | ||||||
| 				name = currtok; | 				name = currtok; | ||||||
| 				eat( TokType::Identifier ); | 				eat( TokType::Identifier ); | ||||||
| 				// ( <ValueType> <Name> | 				// ( <Macro> <ValueType> <Name> | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 				if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) ) | 			// 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 ); | 				eat( TokType::Operator ); | ||||||
| 					// ( <ValueType> <Name> = | 				// ( <Macro> <ValueType> <Name> = | ||||||
|  |  | ||||||
| 				Token value_tok = currtok; | 				Token value_tok = currtok; | ||||||
|  |  | ||||||
| @@ -9373,21 +9451,32 @@ namespace parser | |||||||
| 					return CodeInvalid; | 					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 ) | ||||||
| 				{ | 				{ | ||||||
|  | 					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; | 					value_tok.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )value_tok.Text; | ||||||
| 					eat( currtok.Type ); | 					eat( currtok.Type ); | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				value = untyped_str( strip_formatting( value_tok, strip_formatting_dont_preserve_newlines ) ); | 				value = untyped_str( strip_formatting( value_tok, strip_formatting_dont_preserve_newlines ) ); | ||||||
| 					// ( <ValueType> <Name> = <Expression> | 				// ( <Macro> <ValueType> <Name> = <Expression> | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		} |  | ||||||
| 		else { |  | ||||||
| 			macro = parse_simple_preprocess(ETokType::Preprocess_Macro); |  | ||||||
| 			// ( <Macro> |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		CodeParam result = ( CodeParam )make_code(); | 		CodeParam result = ( CodeParam )make_code(); | ||||||
| 		result->Type     = Parameters; | 		result->Type     = Parameters; | ||||||
| @@ -9404,10 +9493,10 @@ namespace parser | |||||||
|  |  | ||||||
| 		result->NumEntries++; | 		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 ); | 			eat( TokType::Comma ); | ||||||
| 			// ( <ValueType> <Name> = <Expression>, | 			// ( <Macro> <ValueType> <Name> = <Expression>, | ||||||
|  |  | ||||||
| 			Code type  = { nullptr }; | 			Code type  = { nullptr }; | ||||||
| 			Code value = { nullptr }; | 			Code value = { nullptr }; | ||||||
| @@ -9417,18 +9506,27 @@ namespace parser | |||||||
| 				eat( TokType::Varadic_Argument ); | 				eat( TokType::Varadic_Argument ); | ||||||
| 				result.append( param_varadic ); | 				result.append( param_varadic ); | ||||||
| 				continue; | 				continue; | ||||||
| 				// ( <ValueType> <Name> = <Expression>, ... | 				// ( <Macro> <ValueType> <Name> = <Expression>, ... | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if ( ! check(TokType::Preprocess_Macro)) | 			// 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<UActorComponent> Class, bool bManualAttachment, ... | ||||||
|  | 			if ( check(TokType::Preprocess_Macro)) | ||||||
| 			{ | 			{ | ||||||
| 				type = parse_type(); | 				macro = parse_simple_preprocess(ETokType::Preprocess_Macro); | ||||||
|  | 				// ( <Macro> | ||||||
|  | 			} | ||||||
|  | 			if ( currtok.Type != TokType::Comma ) | ||||||
|  | 			{ | ||||||
|  | 				type = parse_type( use_template_capture ); | ||||||
| 				if ( type == Code::Invalid ) | 				if ( type == Code::Invalid ) | ||||||
| 				{ | 				{ | ||||||
| 					Context.pop(); | 					Context.pop(); | ||||||
| 					return CodeInvalid; | 					return CodeInvalid; | ||||||
| 				} | 				} | ||||||
| 				// ( <ValueType> <Name> = <Expression>, <ValueType> | 				// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> | ||||||
|  |  | ||||||
| 				name = { nullptr, 0, TokType::Invalid, false }; | 				name = { nullptr, 0, TokType::Invalid, false }; | ||||||
|  |  | ||||||
| @@ -9436,12 +9534,16 @@ namespace parser | |||||||
| 				{ | 				{ | ||||||
| 					name = currtok; | 					name = currtok; | ||||||
| 					eat( TokType::Identifier ); | 					eat( TokType::Identifier ); | ||||||
| 					// ( <ValueType> <Name> = <Expression>, <ValueType> <Name> | 					// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name> | ||||||
|  | 				} | ||||||
|  |  | ||||||
| 					if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) ) | 				// 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 ); | 					eat( TokType::Operator ); | ||||||
| 						// ( <ValueType> <Name> = <Expression>, <ValueType> <Name> = | 					// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name> = | ||||||
|  |  | ||||||
| 					Token value_tok = currtok; | 					Token value_tok = currtok; | ||||||
|  |  | ||||||
| @@ -9452,21 +9554,36 @@ namespace parser | |||||||
| 						return CodeInvalid; | 						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 ) | ||||||
| 					{ | 					{ | ||||||
|  | 						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; | 						value_tok.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )value_tok.Text; | ||||||
| 						eat( currtok.Type ); | 						eat( currtok.Type ); | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
| 					value = untyped_str( strip_formatting( value_tok, strip_formatting_dont_preserve_newlines ) ); | 					value = untyped_str( strip_formatting( value_tok, strip_formatting_dont_preserve_newlines ) ); | ||||||
| 						// ( <ValueType> <Name> = <Expression>, <ValueType> <Name> = <Expression> | 					// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name> = <Expression> | ||||||
| 				} | 				} | ||||||
| 				} | 				// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name> = <Expression>, .. | ||||||
| 				// ( <ValueType> <Name> = <Expression>, <ValueType> <Name> = <Expression>, .. |  | ||||||
| 			} |  | ||||||
| 			else { |  | ||||||
| 				macro = parse_simple_preprocess(ETokType::Preprocess_Macro); |  | ||||||
| 				// ( ..., <Macro> |  | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			CodeParam param = ( CodeParam )make_code(); | 			CodeParam param = ( CodeParam )make_code(); | ||||||
| @@ -9487,7 +9604,7 @@ namespace parser | |||||||
|  |  | ||||||
| 		if ( ! use_template_capture ) | 		if ( ! use_template_capture ) | ||||||
| 			eat( TokType::Capture_End ); | 			eat( TokType::Capture_End ); | ||||||
| 		// ( <ValueType> <Name> = <Expression>, <ValueType> <Name> = <Expression>, .. ) | 		// ( <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name> = <Expression>, .. ) | ||||||
|  |  | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| @@ -9498,7 +9615,7 @@ namespace parser | |||||||
| 				return CodeInvalid; | 				return CodeInvalid; | ||||||
| 			} | 			} | ||||||
| 			eat( TokType::Operator ); | 			eat( TokType::Operator ); | ||||||
| 			// < <ValueType> <Name> = <Expression>, <ValueType> <Name> = <Expression>, .. > | 			// < <Macro> <ValueType> <Name> = <Expression>, <Macro> <ValueType> <Name> = <Expression>, .. > | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		Context.pop(); | 		Context.pop(); | ||||||
| @@ -9669,18 +9786,22 @@ namespace parser | |||||||
| 			// < | 			// < | ||||||
|  |  | ||||||
| 			s32 level = 0; | 			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++; | 					level++; | ||||||
|  |  | ||||||
| 				if ( currtok.Text[ 0 ] == '>' ) | 				if ( currtok.Text[ 0 ] == '>' ) | ||||||
| 					level--; | 					level--; | ||||||
|  | 				if ( currtok.Type == TokType::Operator && currtok.Text[1] == '>') | ||||||
|  | 					level--; | ||||||
|  |  | ||||||
| 				eat( currtok.Type ); | 				eat( currtok.Type ); | ||||||
| 			} | 			} | ||||||
| 			// < <Content> | 			// < <Content> | ||||||
|  |  | ||||||
|  | 			// Due to the >> token, this could have been eaten early... | ||||||
|  | 			if (level == 0) | ||||||
| 				eat( TokType::Operator ); | 				eat( TokType::Operator ); | ||||||
| 			// < <Content> > | 			// < <Content> > | ||||||
|  |  | ||||||
| @@ -9955,6 +10076,9 @@ namespace parser | |||||||
| 			// <Name> ( <Parameters> ) : <InitializerList> | 			// <Name> ( <Parameters> ) : <InitializerList> | ||||||
|  |  | ||||||
| 			initializer_list = untyped_str( initializer_list_tok ); | 			initializer_list = untyped_str( initializer_list_tok ); | ||||||
|  |  | ||||||
|  | 			// TODO(Ed): Constructors can have post-fix specifiers | ||||||
|  |  | ||||||
| 			body = parse_function_body(); | 			body = parse_function_body(); | ||||||
| 			// <Name> ( <Parameters> ) : <InitializerList> { <Body> } | 			// <Name> ( <Parameters> ) : <InitializerList> { <Body> } | ||||||
| 		} | 		} | ||||||
| @@ -9978,8 +10102,6 @@ namespace parser | |||||||
| 			// <Name> ( <Parameters> ); <InlineCmt> | 			// <Name> ( <Parameters> ); <InlineCmt> | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// TODO(Ed): Constructors can have post-fix specifiers |  | ||||||
|  |  | ||||||
| 		CodeConstructor result = ( CodeConstructor )make_code(); | 		CodeConstructor result = ( CodeConstructor )make_code(); | ||||||
|  |  | ||||||
| 		result->Name = get_cached_string(identifier); | 		result->Name = get_cached_string(identifier); | ||||||
| @@ -10243,10 +10365,18 @@ namespace parser | |||||||
| 						} | 						} | ||||||
| 						// <Name> = <Expression> | 						// <Name> = <Expression> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 						// Unreal UMETA macro support | ||||||
|  | 						if ( currtok.Type == TokType::Preprocess_Macro ) | ||||||
|  | 						{ | ||||||
|  | 							eat( TokType::Preprocess_Macro ); | ||||||
|  | 							// <Name> = <Expression> <Macro> | ||||||
|  | 						} | ||||||
|  |  | ||||||
| 						if ( currtok.Type == TokType::Comma ) | 						if ( currtok.Type == TokType::Comma ) | ||||||
| 						{ | 						{ | ||||||
| 							eat( TokType::Comma ); | 							eat( TokType::Comma ); | ||||||
| 							// <Name> = <Expression>, | 							// <Name> = <Expression> <Macro>, | ||||||
| 						} | 						} | ||||||
|  |  | ||||||
| 						entry.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )entry.Text; | 						entry.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )entry.Text; | ||||||
| @@ -10800,7 +10930,7 @@ namespace parser | |||||||
| 			s32        NumSpecifiers = 0; | 			s32        NumSpecifiers = 0; | ||||||
|  |  | ||||||
| 			attributes = parse_attributes(); | 			attributes = parse_attributes(); | ||||||
| 			// <export> template< <Parameters> > <Attributes> <specifiers. | 			// <export> template< <Parameters> > <Attributes> | ||||||
|  |  | ||||||
| 			// Specifiers Parsing | 			// Specifiers Parsing | ||||||
| 			{ | 			{ | ||||||
| @@ -10850,8 +10980,121 @@ namespace parser | |||||||
| 				// <export> template< <Parameters> > <Attributes> <Specifiers> | 				// <export> template< <Parameters> > <Attributes> <Specifiers> | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// TODO(Ed) : Port over user-defined operator cast detection from | 			// Possible constructor implemented at global file scope. | ||||||
| 			//parse_global_nspace (which is a source defintion version) or parse_class_struct_body (which is an inline class definition) | 			{ | ||||||
|  | 				/* | ||||||
|  | 					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. | ||||||
|  |  | ||||||
|  | 					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; | ||||||
|  | 				s32 level       = 0; | ||||||
|  | 				for ( ; idx < tokens.Arr.num(); idx++ ) | ||||||
|  | 				{ | ||||||
|  | 					if ( level == 0 && tokens[ idx ].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. | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				-- idx; | ||||||
|  | 				tok_left = tokens[idx]; | ||||||
|  | 				// <Attributes> <Specifiers> ... <Identifier> | ||||||
|  |  | ||||||
|  | 				if ( tok_left.Type != TokType::Access_StaticSymbol ) | ||||||
|  | 					break; | ||||||
|  |  | ||||||
|  | 				-- idx; | ||||||
|  | 				tok_left = tokens[idx]; | ||||||
|  | 				// <Attributes> <Specifiers> ... :: <Identifier> | ||||||
|  |  | ||||||
|  | 				// 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 | ||||||
|  | 					// <Name> :: <Name> ( | ||||||
|  |  | ||||||
|  | 					definition = parse_constructor( specifiers ); | ||||||
|  | 					// <Attributes> <Specifiers> <Name> :: <Name> <Type> () { ... } | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// User Defined operator casts | ||||||
|  | 			{ | ||||||
|  | 				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 ); | ||||||
|  | 					// <Attributes> <Specifiers> <Name> :: operator <Type> () { ... } | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			definition = parse_operator_function_or_variable( expects_function, attributes, specifiers ); | 			definition = parse_operator_function_or_variable( expects_function, attributes, specifiers ); | ||||||
| 			// <export> template< <Parameters> > <Attributes> <Specifiers> ... | 			// <export> template< <Parameters> > <Attributes> <Specifiers> ... | ||||||
| @@ -10881,7 +11124,7 @@ namespace parser | |||||||
|  |  | ||||||
| 	    The excess whitespace cannot be stripped however, because there is no semantic awareness within the first capture group. | 	    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(); | 		push_scope(); | ||||||
|  |  | ||||||
| @@ -10921,8 +11164,16 @@ namespace parser | |||||||
| 			return CodeInvalid; | 			return CodeInvalid; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		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); | ||||||
|  | 			// <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 | 		// 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 | 		else if ( currtok.Type == TokType::Decl_Class || currtok.Type == TokType::Decl_Enum || currtok.Type == TokType::Decl_Struct | ||||||
| 		     || currtok.Type == TokType::Decl_Union ) | 		     || currtok.Type == TokType::Decl_Union ) | ||||||
| 		{ | 		{ | ||||||
| 			eat( currtok.Type ); | 			eat( currtok.Type ); | ||||||
| @@ -11429,7 +11680,7 @@ namespace parser | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 				type = parse_type( &is_function ); | 				type = parse_type( false, &is_function ); | ||||||
| 			// <ModuleFalgs> typedef <UnderlyingType> | 			// <ModuleFalgs> typedef <UnderlyingType> | ||||||
|  |  | ||||||
| 			if ( check( TokType::Identifier ) ) | 			if ( check( TokType::Identifier ) ) | ||||||
|   | |||||||
| @@ -121,6 +121,20 @@ | |||||||
| 		</Expand> | 		</Expand> | ||||||
| 	</Type> | 	</Type> | ||||||
|  |  | ||||||
|  | 	<Type Name="gen::AST_Constructor"> | ||||||
|  | 		<DisplayString>{Name} Type: {Type}</DisplayString> | ||||||
|  | 		<Expand> | ||||||
|  | 			<Item Name="InlineCmt">InlineCmt</Item> | ||||||
|  | 			<Item Name="Specs">Specs</Item> | ||||||
|  | 			<Item Name="InitializerList">InitializerList</Item> | ||||||
|  | 			<Item Name="Params">Params</Item> | ||||||
|  | 			<Item Name="Body">Body</Item> | ||||||
|  | 			<Item Name="Parent">Parent</Item> | ||||||
|  | 			<Item Name="Prev">Prev</Item> | ||||||
|  | 			<Item Name="Next">Next</Item> | ||||||
|  | 		</Expand> | ||||||
|  | 	</Type> | ||||||
|  |  | ||||||
| 	<Type Name="gen::AST_Class"> | 	<Type Name="gen::AST_Class"> | ||||||
| 		<DisplayString>{Name} Type: {Type}</DisplayString> | 		<DisplayString>{Name} Type: {Type}</DisplayString> | ||||||
| 		<Expand> | 		<Expand> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user