Was able to parse UObject with gencpp!!!
This commit is contained in:
parent
7b9e277bc1
commit
48d21ddd15
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"autoHide.autoHideSideBar": false,
|
||||||
|
"autoHide.autoHidePanel": false
|
||||||
|
}
|
BIN
Project/Binaries/GasaGen_214406991.raddbgi
Normal file
BIN
Project/Binaries/GasaGen_214406991.raddbgi
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -4,6 +4,7 @@
|
|||||||
GameDefaultMap=/Game/Levels/StartupMap.StartupMap
|
GameDefaultMap=/Game/Levels/StartupMap.StartupMap
|
||||||
EditorStartupMap=/Game/Levels/StartupMap.StartupMap
|
EditorStartupMap=/Game/Levels/StartupMap.StartupMap
|
||||||
GlobalDefaultGameMode=/Game/Core/Game/BP_GameMode.BP_GameMode_C
|
GlobalDefaultGameMode=/Game/Core/Game/BP_GameMode.BP_GameMode_C
|
||||||
|
GameInstanceClass=/Script/Gasa.GasaGameInstance
|
||||||
|
|
||||||
[/Script/WindowsTargetPlatform.WindowsTargetSettings]
|
[/Script/WindowsTargetPlatform.WindowsTargetSettings]
|
||||||
DefaultGraphicsRHI=DefaultGraphicsRHI_DX12
|
DefaultGraphicsRHI=DefaultGraphicsRHI_DX12
|
||||||
|
BIN
Project/Content/Core/Pickups/BP_HealthPotion.uasset
(Stored with Git LFS)
BIN
Project/Content/Core/Pickups/BP_HealthPotion.uasset
(Stored with Git LFS)
Binary file not shown.
BIN
Project/Content/Levels/StartupMap.umap
(Stored with Git LFS)
BIN
Project/Content/Levels/StartupMap.umap
(Stored with Git LFS)
Binary file not shown.
@ -21,7 +21,6 @@ public:
|
|||||||
FGameplayAttributeData MaxMana;
|
FGameplayAttributeData MaxMana;
|
||||||
|
|
||||||
UGasaAttributeSet();
|
UGasaAttributeSet();
|
||||||
|
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
void Client_OnRep_Health( FGameplayAttributeData& PrevHealth );
|
void Client_OnRep_Health( FGameplayAttributeData& PrevHealth );
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#include "Camera/CameraComponent.h"
|
#include "Camera/CameraComponent.h"
|
||||||
#include "GameFramework/SpringArmComponent.h"
|
#include "GameFramework/SpringArmComponent.h"
|
||||||
|
|
||||||
|
|
||||||
ACameraMount::ACameraMount()
|
ACameraMount::ACameraMount()
|
||||||
{
|
{
|
||||||
PrimaryActorTick.bCanEverTick = true;
|
PrimaryActorTick.bCanEverTick = true;
|
||||||
|
@ -22,4 +22,3 @@ public:
|
|||||||
void PostInitializeComponents() override;
|
void PostInitializeComponents() override;
|
||||||
#pragma endregion Actor
|
#pragma endregion Actor
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,4 +5,7 @@ void UGasaGameInstance::Init()
|
|||||||
Super::Init();
|
Super::Init();
|
||||||
|
|
||||||
DevOptionsCache.CachedDevOptions();
|
DevOptionsCache.CachedDevOptions();
|
||||||
|
|
||||||
|
using namespace Gasa;
|
||||||
|
Log(FString::Printf(TEXT("UObject Size: %d RT: %d"), sizeof(UObject), UObject::StaticClass()->PropertiesSize ));
|
||||||
}
|
}
|
||||||
|
9
Project/Source/Gasa/ScratchMeta.h
Normal file
9
Project/Source/Gasa/ScratchMeta.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Don't keep this included anywhere
|
||||||
|
// Purely for inspection purposes
|
||||||
|
|
||||||
|
#include "GasaCommon.h"
|
||||||
|
|
||||||
|
void test()
|
||||||
|
{
|
||||||
|
UObject::StaticClass()->PropertiesSize
|
||||||
|
}
|
7
Project/Source/Gasa/UI/GasaUserWidget.cpp
Normal file
7
Project/Source/Gasa/UI/GasaUserWidget.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "GasaUserWidget.h"
|
||||||
|
|
||||||
|
UGasaUserWidget::UGasaUserWidget(FObjectInitializer const& ObjectInitializer)
|
||||||
|
: UUserWidget(ObjectInitializer)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
26
Project/Source/Gasa/UI/GasaUserWidget.h
Normal file
26
Project/Source/Gasa/UI/GasaUserWidget.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Blueprint/UserWidget.h"
|
||||||
|
|
||||||
|
#include "GasaUserWidget.generated.h"
|
||||||
|
|
||||||
|
UCLASS(Blueprintable)
|
||||||
|
class GASA_API UGasaUserWidget : public UUserWidget
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
public:
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadOnly)
|
||||||
|
TObjectPtr<UObject> WidgetController;
|
||||||
|
|
||||||
|
UGasaUserWidget(FObjectInitializer const& ObjectInitializer);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable)
|
||||||
|
void SetWidgetController(UObject* Controller)
|
||||||
|
{
|
||||||
|
WidgetController = Controller;
|
||||||
|
OnWidgetControllerSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintImplementableEvent)
|
||||||
|
void OnWidgetControllerSet();
|
||||||
|
};
|
9
Project/Source/Gasa/UI/ProgressBar.h
Normal file
9
Project/Source/Gasa/UI/ProgressBar.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Components/ProgressBar.h"
|
||||||
|
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class GASA_API UProgressIndicator : public UProgressBar
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
1
Project/Source/Gasa/UI/WidgetController.cpp
Normal file
1
Project/Source/Gasa/UI/WidgetController.cpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "WidgetController.h"
|
23
Project/Source/Gasa/UI/WidgetController.h
Normal file
23
Project/Source/Gasa/UI/WidgetController.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "GasaCommon.h"
|
||||||
|
#include "WidgetController.generated.h"
|
||||||
|
|
||||||
|
UCLASS(BlueprintType)
|
||||||
|
class GASA_API UWdgetController : public UObject
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
public:
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadOnly, Category="Player")
|
||||||
|
TObjectPtr<APlayerController> Controller;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadOnly, Category="Player")
|
||||||
|
TObjectPtr<APlayerState> PlayerState;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadOnly, Category="Player")
|
||||||
|
TObjectPtr<UAbilitySystemComponent> AbilitySystem;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadOnly, Category="Player")
|
||||||
|
TObjectPtr<UAttributeSet> Attributes;
|
||||||
|
};
|
@ -5,280 +5,136 @@
|
|||||||
#define GEN_IMPLEMENTATION
|
#define GEN_IMPLEMENTATION
|
||||||
#include "gen.cpp"
|
#include "gen.cpp"
|
||||||
#include "gen.builder.cpp"
|
#include "gen.builder.cpp"
|
||||||
|
#include "gen.scanner.hpp"
|
||||||
using namespace gen;
|
using namespace gen;
|
||||||
|
|
||||||
// Program assumes its working directory is the project
|
#include "GasaGenCommon.cpp"
|
||||||
#define path_config "./Source/Config/"
|
#include "GasaGen_UGasaAttributeSet.cpp"
|
||||||
#define path_module_gasa "./Source/Gasa/"
|
|
||||||
#define path_gasa_ability_system path_module_gasa "AbilitySystem/"
|
|
||||||
|
|
||||||
|
|
||||||
void def_attribute_properties( CodeBody body, Array<StringCached> properties )
|
|
||||||
{
|
|
||||||
for ( StringCached property : properties )
|
|
||||||
{
|
|
||||||
Code field_uproperty = code_fmt( "property", (StrC)property, stringize(
|
|
||||||
UPROPERTY(ReplicatedUsing=Client_OnRep_<property>, EditAnywhere, BlueprintReadWrite, Category="Attributes")
|
|
||||||
));
|
|
||||||
|
|
||||||
CodeType type_FGameplayAttributeData = def_type( txt("FGameplayAttributeData"));
|
|
||||||
|
|
||||||
body.append(fmt_newline);
|
|
||||||
body.append( field_uproperty );
|
|
||||||
body.append(fmt_newline);
|
|
||||||
body.append( def_variable( type_FGameplayAttributeData, StrC(property)) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void def_attribute_field_on_reps( CodeBody body, Array<StringCached> fields )
|
|
||||||
{
|
|
||||||
for ( StringCached field : fields )
|
|
||||||
{
|
|
||||||
Code umeta_UFUNCTION = code_str( UFUNCTION() );
|
|
||||||
|
|
||||||
body.append(fmt_newline);
|
|
||||||
body.append( umeta_UFUNCTION );
|
|
||||||
body.append(fmt_newline);
|
|
||||||
body.append( code_fmt( "field", (StrC)field, stringize(
|
|
||||||
void Client_OnRep_<field>(FGameplayAttributeData& Prev<field>);
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void def_attribute_field_property_getters( CodeBody body, StrC class_name, Array<StringCached> properties )
|
|
||||||
{
|
|
||||||
for ( String property : properties )
|
|
||||||
{
|
|
||||||
CodeFn generated_get_attribute = parse_function(
|
|
||||||
token_fmt( "class_name", class_name, "property", (StrC)property,
|
|
||||||
stringize(
|
|
||||||
static FGameplayAttribute Get<property>Attribute()
|
|
||||||
{
|
|
||||||
static FProperty* Prop = FindFieldChecked<FProperty>(<class_name>::StaticClass(), GET_MEMBER_NAME_CHECKED(<class_name>, <property>));
|
|
||||||
return Prop;
|
|
||||||
}
|
|
||||||
)));
|
|
||||||
body.append( generated_get_attribute );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void def_attribute_field_value_getters( CodeBody body, Array<StringCached> properties )
|
|
||||||
{
|
|
||||||
for ( String property : properties )
|
|
||||||
{
|
|
||||||
#pragma push_macro(FORCEINLINE)
|
|
||||||
#undef FORCEINLINE
|
|
||||||
|
|
||||||
body.append( code_fmt( "property", (StrC)property,
|
|
||||||
stringize(
|
|
||||||
FORCEINLINE float Get<property>() const
|
|
||||||
{
|
|
||||||
return <property>.GetCurrentValue();
|
|
||||||
}
|
|
||||||
)));
|
|
||||||
|
|
||||||
#pragma pop_macro(FORCEINLINE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void def_attribute_field_value_setters( CodeBody body, Array<StringCached> properties )
|
|
||||||
{
|
|
||||||
for ( String property : properties )
|
|
||||||
{
|
|
||||||
body.append( code_fmt( "property", (StrC)property,
|
|
||||||
stringize(
|
|
||||||
FORCEINLINE void Set<property>(float NewVal)
|
|
||||||
{
|
|
||||||
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
|
|
||||||
if (ensure(AbilityComp))
|
|
||||||
{
|
|
||||||
AbilityComp->SetNumericAttributeBase(Get<property>Attribute(), NewVal);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void def_attribute_field_initers ( CodeBody body, Array<StringCached> properties )
|
|
||||||
{
|
|
||||||
for ( String property : properties )
|
|
||||||
{
|
|
||||||
body.append( code_fmt( "property", (StrC)property,
|
|
||||||
stringize(
|
|
||||||
FORCEINLINE void Init<property>(float NewVal)
|
|
||||||
{
|
|
||||||
<property>.SetBaseValue(NewVal);
|
|
||||||
<property>.SetCurrentValue(NewVal);
|
|
||||||
}
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void impl_attribute_fields( CodeBody body, StrC class_name, Array<StringCached> properties )
|
|
||||||
{
|
|
||||||
for ( String property : properties )
|
|
||||||
{
|
|
||||||
body.append(fmt_newline);
|
|
||||||
|
|
||||||
CodeFn field_impl = parse_function( token_fmt( "class_name", class_name, "property", (StrC)property,
|
|
||||||
stringize(
|
|
||||||
void <class_name>::Client_OnRep_<property>(FGameplayAttributeData& Prev<property>)
|
|
||||||
{
|
|
||||||
GAMEPLAYATTRIBUTE_REPNOTIFY(<class_name>, <property>, Prev<property>)
|
|
||||||
}
|
|
||||||
)));
|
|
||||||
|
|
||||||
body.append( field_impl );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int gen_main()
|
int gen_main()
|
||||||
{
|
{
|
||||||
gen::init();
|
gen::init();
|
||||||
log_fmt("Generating code for the Gasa module");
|
log_fmt("Generating code for the Gasa module");
|
||||||
|
|
||||||
Code umeta_uclass = code_str( UCLASS() );
|
// Initialize Globals
|
||||||
Code umeta_generated_body = code_str( GENERATED_BODY() );
|
umeta_uclass = code_str( UCLASS() );
|
||||||
Code gasa_api = code_str( GASA_API );
|
umeta_generated_body = code_str( GENERATED_BODY() );
|
||||||
|
gasa_api = code_str( GASA_API );
|
||||||
|
|
||||||
CodeType type_UAttributeSet = def_type( txt("UAttributeSet") );
|
StrC str_generated_body = txt("GENERATED_BODY(");
|
||||||
|
StrC str_generated_uclass_body = txt("GENERATED_UCLASS_BODY(");
|
||||||
|
StrC str_property_binding_impl = txt("PROPERTY_BINDING_IMPLEMENTATION");
|
||||||
|
StrC str_uclass = txt("UCLASS(");
|
||||||
|
StrC str_ue_deprecated = txt("UE_DEPRECATED(");
|
||||||
|
StrC str_ufunction = txt("UFUNCTION(");
|
||||||
|
StrC str_uproperty = txt("UPROPERTY(");
|
||||||
|
StrC str_umg_api = txt("UMG_API");
|
||||||
|
|
||||||
CodeComment generation_notice = def_comment(txt("This was generated by GasaGen/GasaGen.cpp"));
|
StrC str_declare_log_category_extern = txt("DECLARE_LOG_CATEGORY_EXTERN(");
|
||||||
|
StrC str_enum_class_flags = txt("ENUM_CLASS_FLAGS(");
|
||||||
|
StrC str_declare_class = txt("DECLARE_CLASS(");
|
||||||
|
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_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_three_parameter = txt("DECLARE_MULTICAST_DELEGATE_ThreeParams(");
|
||||||
|
StrC str_declare_delegate_retval_one_param = txt("DECLARE_DELEGATE_RetVal_OneParam(");
|
||||||
|
StrC str_declare_function = txt("DECLARE_FUNCTION(");
|
||||||
|
StrC str_result_decl = txt("RESULT_DECL");
|
||||||
|
StrC str_property_binding_implementation = txt("PROPERTY_BINDING_IMPLEMENTATION(");
|
||||||
|
StrC str_FORCEINLINE = txt("FORCEINLINE");
|
||||||
|
|
||||||
Array<StringCached> attribute_fields = Array<StringCached>::init( GlobalAllocator);
|
PreprocessorDefines.append( get_cached_string(str_generated_body));
|
||||||
attribute_fields.append( get_cached_string(txt("Health")));
|
PreprocessorDefines.append( get_cached_string(str_generated_uclass_body));
|
||||||
attribute_fields.append( get_cached_string(txt("MaxHealth")));
|
PreprocessorDefines.append( get_cached_string(str_property_binding_impl));
|
||||||
attribute_fields.append( get_cached_string(txt("Mana")));
|
PreprocessorDefines.append( get_cached_string(str_ue_deprecated));
|
||||||
attribute_fields.append( get_cached_string(txt("MaxMana")));
|
PreprocessorDefines.append( get_cached_string(str_uclass));
|
||||||
|
PreprocessorDefines.append( get_cached_string(str_ufunction));
|
||||||
|
PreprocessorDefines.append( get_cached_string(str_uproperty));
|
||||||
|
PreprocessorDefines.append( get_cached_string(str_umg_api));
|
||||||
|
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_declare_class));
|
||||||
|
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_macro_text));
|
||||||
|
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_three_parameter));
|
||||||
|
PreprocessorDefines.append( get_cached_string(str_declare_delegate_retval_one_param));
|
||||||
|
PreprocessorDefines.append( get_cached_string(str_declare_function));
|
||||||
|
PreprocessorDefines.append( get_cached_string(str_result_decl));
|
||||||
|
PreprocessorDefines.append( get_cached_string(str_property_binding_implementation));
|
||||||
|
PreprocessorDefines.append( get_cached_string(str_FORCEINLINE));
|
||||||
|
|
||||||
|
#define path_UProgressBar \
|
||||||
|
"C:/projects/Unreal/Surgo/UE/Engine/Source/Runtime/UMG/Public/Components/ProgressBar.h"
|
||||||
|
|
||||||
StrC attributeset_name = txt("UGasaAttributeSet");
|
FileContents content = file_read_contents( GlobalAllocator, true, path_UProgressBar );
|
||||||
|
CodeBody parsed_uprogressbar = parse_global_body( StrC { content.size, (char const*)content.data });
|
||||||
|
|
||||||
Builder header = Builder::open( path_gasa_ability_system "GasaAttributeSet.h");
|
log_fmt("\n\n");
|
||||||
|
for ( Code gcode : parsed_uprogressbar )
|
||||||
{
|
{
|
||||||
header.print(generation_notice);
|
if ( gcode->Type == CodeT::Class )
|
||||||
header.print(fmt_newline);
|
|
||||||
{
|
{
|
||||||
CodeInclude Include_AttributeSet = def_include(txt("AttributeSet.h"));
|
log_fmt("Class %S - Definitions:\n", gcode->Name);
|
||||||
CodeInclude Include_AbilitySystemComponent = def_include(txt("AbilitySystemComponent.h"));
|
|
||||||
CodeInclude Include_GasaAttributeSet_Generated = def_include(txt("GasaAttributeSet.generated.h"));
|
|
||||||
|
|
||||||
CodeAttributes attributes = def_attributes( gasa_api->Name);
|
if (gcode->Body->Type != CodeT::Class_Body)
|
||||||
|
continue;
|
||||||
CodeClass GasaAttributeSet = {};
|
for ( Code class_code : gcode->Body->cast<CodeBody>() )
|
||||||
{
|
{
|
||||||
CodeBody body = def_body( CodeT::Class_Body );
|
switch ( class_code->Type )
|
||||||
{
|
{
|
||||||
body.append( umeta_generated_body);
|
case CodeT::Variable:
|
||||||
body.append( fmt_newline);
|
case CodeT::Function:
|
||||||
body.append( access_public );
|
case CodeT::Function_Fwd:
|
||||||
|
if ( class_code->Name )
|
||||||
def_attribute_properties( body, attribute_fields);
|
{
|
||||||
|
log_fmt("%s\n", class_code->Name );
|
||||||
body.append(fmt_newline);
|
}
|
||||||
body.append( def_constructor() );
|
break;
|
||||||
|
|
||||||
def_attribute_field_on_reps( body, attribute_fields);
|
|
||||||
|
|
||||||
body.append(fmt_newline);
|
|
||||||
|
|
||||||
body.append( fmt_newline );
|
|
||||||
body.append( def_pragma(code( region Getters )));
|
|
||||||
def_attribute_field_property_getters( body, attributeset_name, attribute_fields );
|
|
||||||
def_attribute_field_value_getters( body, attribute_fields );
|
|
||||||
body.append( def_pragma(code( endregion Getters )));
|
|
||||||
body.append( fmt_newline );
|
|
||||||
|
|
||||||
body.append( def_pragma(code( region Setters )));
|
|
||||||
def_attribute_field_value_setters( body, attribute_fields );
|
|
||||||
def_attribute_field_initers( body, attribute_fields );
|
|
||||||
body.append( def_pragma(code( endregion Setters )));
|
|
||||||
body.append( fmt_newline );
|
|
||||||
|
|
||||||
body.append( def_pragma( txt("region UObject")));
|
|
||||||
body.append( parse_function( code(
|
|
||||||
void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
|
||||||
)));
|
|
||||||
body.append( def_pragma( txt("endregion UObject")));
|
|
||||||
}
|
}
|
||||||
GasaAttributeSet = def_class( txt("UGasaAttributeSet"), body
|
|
||||||
, type_UAttributeSet
|
|
||||||
, AccessSpec::Public
|
|
||||||
, attributes
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeNS ns_gasa = parse_namespace( code(
|
|
||||||
namespace Gasa
|
|
||||||
{
|
|
||||||
inline
|
|
||||||
UGasaAttributeSet const* GetAttributeSet( UAbilitySystemComponent* ASC )
|
|
||||||
{
|
|
||||||
return Cast<UGasaAttributeSet>(ASC->GetAttributeSet( UGasaAttributeSet::StaticClass() ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
header.print( Include_AttributeSet);
|
|
||||||
header.print( Include_AbilitySystemComponent);
|
|
||||||
header.print( Include_GasaAttributeSet_Generated);
|
|
||||||
header.print( fmt_newline);
|
|
||||||
header.print(umeta_uclass);
|
|
||||||
header.print(GasaAttributeSet);
|
|
||||||
header.print(ns_gasa);
|
|
||||||
}
|
}
|
||||||
header.write();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder source = Builder::open( path_gasa_ability_system "GasaAttributeSet.cpp" );
|
#define path_UObject \
|
||||||
|
R"(C:\projects\Unreal\Surgo\UE\Engine\Source\Runtime\CoreUObject\Public\UObject\Object.h)"
|
||||||
|
|
||||||
|
content = file_read_contents( GlobalAllocator, true, path_UObject );
|
||||||
|
CodeBody parsed_uobject = parse_global_body( StrC { content.size, (char const*)content.data });
|
||||||
|
|
||||||
|
log_fmt("\n\n");
|
||||||
|
for ( Code gcode : parsed_uobject )
|
||||||
{
|
{
|
||||||
source.print(generation_notice);
|
if ( gcode->Type == CodeT::Class )
|
||||||
source.print( def_include( txt("GasaAttributeSet.h")));
|
|
||||||
source.print(fmt_newline);
|
|
||||||
source.print( def_include( txt("AbilitySystemComponent.h")));
|
|
||||||
source.print( def_include( txt("Net/UnrealNetwork.h")));
|
|
||||||
source.print( def_include( txt("Networking/GasaNetLibrary.h")));
|
|
||||||
{
|
{
|
||||||
CodeBody body = def_body( CodeT::Global_Body );
|
log_fmt("Class %S - Definitions:\n", gcode->Name);
|
||||||
body.append(fmt_newline);
|
|
||||||
body.append(code_str(
|
|
||||||
UGasaAttributeSet::UGasaAttributeSet()
|
|
||||||
{
|
|
||||||
InitHealth( 100.f );
|
|
||||||
InitMaxHealth( 100.f );
|
|
||||||
InitMana(( 50.f ));
|
|
||||||
InitMaxMana( 50.f );
|
|
||||||
}
|
|
||||||
));
|
|
||||||
body.append(fmt_newline);
|
|
||||||
|
|
||||||
impl_attribute_fields( body, attributeset_name, attribute_fields);
|
if (gcode->Body->Type != CodeT::Class_Body)
|
||||||
|
continue;
|
||||||
CodeFn GetLifetimeOfReplicatedProps;
|
for ( Code class_code : gcode->Body->cast<CodeBody>() )
|
||||||
{
|
{
|
||||||
CodeBody field_lifetimes = def_body( CodeT::Function_Body);
|
switch ( class_code->Type )
|
||||||
for (StringCached field : attribute_fields)
|
|
||||||
{
|
{
|
||||||
field_lifetimes.append( code_fmt( "field", (StrC)field, stringize(
|
case CodeT::Variable:
|
||||||
DOREPLIFETIME_DEFAULT_GAS(UGasaAttributeSet, <field>);
|
case CodeT::Function:
|
||||||
)));
|
case CodeT::Function_Fwd:
|
||||||
|
if ( class_code->Name )
|
||||||
|
{
|
||||||
|
log_fmt("%s\n", class_code->Name );
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
GetLifetimeOfReplicatedProps = parse_function( token_fmt( "body", (StrC)(field_lifetimes.to_string()), stringize(
|
|
||||||
void UGasaAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
|
||||||
{
|
|
||||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
|
||||||
<body>
|
|
||||||
}
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
body.append(GetLifetimeOfReplicatedProps);
|
|
||||||
|
|
||||||
source.print(body);
|
|
||||||
}
|
}
|
||||||
source.write();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// gen::deinit();
|
StrC str_gasa_api = txt("GASA_API");
|
||||||
|
|
||||||
|
gen_UGasaAttributeSet();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
13
Project/Source/GasaGen/GasaGenCommon.cpp
Normal file
13
Project/Source/GasaGen/GasaGenCommon.cpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Program assumes its working directory is the project
|
||||||
|
#define path_config "./Source/Config/"
|
||||||
|
#define path_module_gasa "./Source/Gasa/"
|
||||||
|
#define path_gasa_ability_system path_module_gasa "AbilitySystem/"
|
||||||
|
|
||||||
|
#pragma region Globals
|
||||||
|
// These Code objects are created before anything else after gencpp does its initializatioon
|
||||||
|
global Code umeta_uclass;
|
||||||
|
global Code umeta_generated_body;
|
||||||
|
global Code gasa_api;
|
||||||
|
#pragma endregion Globals
|
268
Project/Source/GasaGen/GasaGen_UGasaAttributeSet.cpp
Normal file
268
Project/Source/GasaGen/GasaGen_UGasaAttributeSet.cpp
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
// Used in the GasaGen.cpp translation unit
|
||||||
|
|
||||||
|
void def_attribute_properties ( CodeBody body, Array<StringCached> properties );
|
||||||
|
void def_attribute_field_on_reps ( CodeBody body, Array<StringCached> properties );
|
||||||
|
void def_attribute_field_property_getters( CodeBody body, StrC class_name, Array<StringCached> properties );
|
||||||
|
void def_attribute_field_value_getters ( CodeBody body, Array<StringCached> properties );
|
||||||
|
void def_attribute_field_value_setters ( CodeBody body, Array<StringCached> properties );
|
||||||
|
void def_attribute_field_initers ( CodeBody body, Array<StringCached> properties );
|
||||||
|
void impl_attribute_fields ( CodeBody body, StrC class_name, Array<StringCached> properties );
|
||||||
|
|
||||||
|
void gen_UGasaAttributeSet()
|
||||||
|
{
|
||||||
|
CodeType type_UAttributeSet = def_type( txt("UAttributeSet") );
|
||||||
|
CodeComment generation_notice = def_comment(txt("This was generated by GasaGen/GasaGen.cpp"));
|
||||||
|
|
||||||
|
Array<StringCached> attribute_fields = Array<StringCached>::init( GlobalAllocator);
|
||||||
|
attribute_fields.append( get_cached_string(txt("Health")));
|
||||||
|
attribute_fields.append( get_cached_string(txt("MaxHealth")));
|
||||||
|
attribute_fields.append( get_cached_string(txt("Mana")));
|
||||||
|
attribute_fields.append( get_cached_string(txt("MaxMana")));
|
||||||
|
|
||||||
|
StrC class_name = txt("UGasaAttributeSet");
|
||||||
|
|
||||||
|
Builder header = Builder::open( path_gasa_ability_system "GasaAttributeSet.h");
|
||||||
|
{
|
||||||
|
header.print(generation_notice);
|
||||||
|
header.print(fmt_newline);
|
||||||
|
{
|
||||||
|
CodeInclude Include_AttributeSet = def_include(txt("AttributeSet.h"));
|
||||||
|
CodeInclude Include_AbilitySystemComponent = def_include(txt("AbilitySystemComponent.h"));
|
||||||
|
CodeInclude Include_GasaAttributeSet_Generated = def_include(txt("GasaAttributeSet.generated.h"));
|
||||||
|
|
||||||
|
CodeAttributes api_attribute= def_attributes( gasa_api->Name);
|
||||||
|
|
||||||
|
CodeClass GasaAttributeSet = {};
|
||||||
|
{
|
||||||
|
CodeBody body = def_body( CodeT::Class_Body );
|
||||||
|
{
|
||||||
|
body.append( umeta_generated_body);
|
||||||
|
body.append( fmt_newline);
|
||||||
|
body.append( access_public );
|
||||||
|
|
||||||
|
def_attribute_properties( body, attribute_fields);
|
||||||
|
|
||||||
|
body.append(fmt_newline);
|
||||||
|
body.append( def_constructor() );
|
||||||
|
|
||||||
|
def_attribute_field_on_reps( body, attribute_fields);
|
||||||
|
|
||||||
|
body.append(fmt_newline);
|
||||||
|
|
||||||
|
body.append( fmt_newline );
|
||||||
|
body.append( def_pragma(code( region Getters )));
|
||||||
|
def_attribute_field_property_getters( body, class_name, attribute_fields );
|
||||||
|
def_attribute_field_value_getters( body, attribute_fields );
|
||||||
|
body.append( def_pragma(code( endregion Getters )));
|
||||||
|
body.append( fmt_newline );
|
||||||
|
|
||||||
|
body.append( def_pragma(code( region Setters )));
|
||||||
|
def_attribute_field_value_setters( body, attribute_fields );
|
||||||
|
def_attribute_field_initers( body, attribute_fields );
|
||||||
|
body.append( def_pragma(code( endregion Setters )));
|
||||||
|
body.append( fmt_newline );
|
||||||
|
|
||||||
|
body.append( def_pragma( txt("region UObject")));
|
||||||
|
body.append( parse_function( code(
|
||||||
|
void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||||
|
)));
|
||||||
|
body.append( def_pragma( txt("endregion UObject")));
|
||||||
|
}
|
||||||
|
GasaAttributeSet = def_class( class_name, body
|
||||||
|
, type_UAttributeSet, AccessSpec::Public
|
||||||
|
, api_attribute
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeNS ns_gasa = parse_namespace( code(
|
||||||
|
namespace Gasa
|
||||||
|
{
|
||||||
|
inline
|
||||||
|
UGasaAttributeSet const* GetAttributeSet( UAbilitySystemComponent* ASC )
|
||||||
|
{
|
||||||
|
return Cast<UGasaAttributeSet>(ASC->GetAttributeSet( UGasaAttributeSet::StaticClass() ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
header.print( Include_AttributeSet);
|
||||||
|
header.print( Include_AbilitySystemComponent);
|
||||||
|
header.print( Include_GasaAttributeSet_Generated);
|
||||||
|
header.print( fmt_newline);
|
||||||
|
header.print(umeta_uclass);
|
||||||
|
header.print(GasaAttributeSet);
|
||||||
|
header.print(ns_gasa);
|
||||||
|
}
|
||||||
|
header.write();
|
||||||
|
}
|
||||||
|
|
||||||
|
Builder source = Builder::open( path_gasa_ability_system "GasaAttributeSet.cpp" );
|
||||||
|
{
|
||||||
|
source.print(generation_notice);
|
||||||
|
header.print(fmt_newline);
|
||||||
|
source.print( def_include( txt("GasaAttributeSet.h")));
|
||||||
|
source.print(fmt_newline);
|
||||||
|
source.print( def_include( txt("AbilitySystemComponent.h")));
|
||||||
|
source.print( def_include( txt("Net/UnrealNetwork.h")));
|
||||||
|
source.print( def_include( txt("Networking/GasaNetLibrary.h")));
|
||||||
|
{
|
||||||
|
CodeBody body = def_body( CodeT::Global_Body );
|
||||||
|
body.append(fmt_newline);
|
||||||
|
|
||||||
|
CodeConstructor constructor_for_UGasaAttributeSet = parse_constructor( code(
|
||||||
|
UGasaAttributeSet::UGasaAttributeSet()
|
||||||
|
{
|
||||||
|
InitHealth( 100.f );
|
||||||
|
InitMaxHealth( 100.f );
|
||||||
|
InitMana(( 50.f ));
|
||||||
|
InitMaxMana( 50.f );
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
body.append(constructor_for_UGasaAttributeSet );
|
||||||
|
body.append(fmt_newline);
|
||||||
|
|
||||||
|
impl_attribute_fields( body, class_name, attribute_fields);
|
||||||
|
|
||||||
|
CodeFn GetLifetimeOfReplicatedProps;
|
||||||
|
{
|
||||||
|
CodeBody field_lifetimes = def_body( CodeT::Function_Body);
|
||||||
|
for (StringCached field : attribute_fields)
|
||||||
|
{
|
||||||
|
field_lifetimes.append( code_fmt( "field", (StrC)field, stringize(
|
||||||
|
DOREPLIFETIME_DEFAULT_GAS(UGasaAttributeSet, <field>);
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
GetLifetimeOfReplicatedProps = parse_function( token_fmt( "body", (StrC)(field_lifetimes.to_string()), stringize(
|
||||||
|
void UGasaAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||||
|
{
|
||||||
|
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||||
|
<body>
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
body.append(GetLifetimeOfReplicatedProps);
|
||||||
|
|
||||||
|
source.print(body);
|
||||||
|
}
|
||||||
|
source.write();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void def_attribute_properties( CodeBody body, Array<StringCached> properties )
|
||||||
|
{
|
||||||
|
for ( StringCached property : properties )
|
||||||
|
{
|
||||||
|
Code field_uproperty = code_fmt( "property", (StrC)property, stringize(
|
||||||
|
UPROPERTY(ReplicatedUsing=Client_OnRep_<property>, EditAnywhere, BlueprintReadWrite, Category="Attributes")
|
||||||
|
));
|
||||||
|
|
||||||
|
CodeType type_FGameplayAttributeData = def_type( txt("FGameplayAttributeData"));
|
||||||
|
|
||||||
|
body.append(fmt_newline);
|
||||||
|
body.append( field_uproperty );
|
||||||
|
body.append(fmt_newline);
|
||||||
|
body.append( def_variable( type_FGameplayAttributeData, StrC(property)) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void def_attribute_field_on_reps( CodeBody body, Array<StringCached> properties )
|
||||||
|
{
|
||||||
|
for ( StringCached property : properties )
|
||||||
|
{
|
||||||
|
Code umeta_UFUNCTION = code_str( UFUNCTION() );
|
||||||
|
|
||||||
|
body.append(fmt_newline);
|
||||||
|
body.append( umeta_UFUNCTION );
|
||||||
|
body.append(fmt_newline);
|
||||||
|
body.append( code_fmt( "property", (StrC)property, stringize(
|
||||||
|
void Client_OnRep_<property>(FGameplayAttributeData& Prev<property>);
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void def_attribute_field_property_getters( CodeBody body, StrC class_name, Array<StringCached> properties )
|
||||||
|
{
|
||||||
|
for ( String property : properties )
|
||||||
|
{
|
||||||
|
CodeFn generated_get_attribute = parse_function(
|
||||||
|
token_fmt( "class_name", class_name, "property", (StrC)property,
|
||||||
|
stringize(
|
||||||
|
static FGameplayAttribute Get<property>Attribute()
|
||||||
|
{
|
||||||
|
static FProperty* Prop = FindFieldChecked<FProperty>(<class_name>::StaticClass(), GET_MEMBER_NAME_CHECKED(<class_name>, <property>));
|
||||||
|
return Prop;
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
body.append( generated_get_attribute );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void def_attribute_field_value_getters( CodeBody body, Array<StringCached> properties )
|
||||||
|
{
|
||||||
|
for ( String property : properties )
|
||||||
|
{
|
||||||
|
#pragma push_macro(FORCEINLINE)
|
||||||
|
#undef FORCEINLINE
|
||||||
|
body.append( code_fmt( "property", (StrC)property,
|
||||||
|
stringize(
|
||||||
|
FORCEINLINE float Get<property>() const
|
||||||
|
{
|
||||||
|
return <property>.GetCurrentValue();
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
#pragma pop_macro(FORCEINLINE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void def_attribute_field_value_setters( CodeBody body, Array<StringCached> properties )
|
||||||
|
{
|
||||||
|
for ( String property : properties )
|
||||||
|
{
|
||||||
|
body.append( code_fmt( "property", (StrC)property,
|
||||||
|
stringize(
|
||||||
|
FORCEINLINE void Set<property>(float NewVal)
|
||||||
|
{
|
||||||
|
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
|
||||||
|
if (ensure(AbilityComp))
|
||||||
|
{
|
||||||
|
AbilityComp->SetNumericAttributeBase(Get<property>Attribute(), NewVal);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void def_attribute_field_initers ( CodeBody body, Array<StringCached> properties )
|
||||||
|
{
|
||||||
|
for ( String property : properties )
|
||||||
|
{
|
||||||
|
body.append( code_fmt( "property", (StrC)property,
|
||||||
|
stringize(
|
||||||
|
FORCEINLINE void Init<property>(float NewVal)
|
||||||
|
{
|
||||||
|
<property>.SetBaseValue(NewVal);
|
||||||
|
<property>.SetCurrentValue(NewVal);
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void impl_attribute_fields( CodeBody body, StrC class_name, Array<StringCached> properties )
|
||||||
|
{
|
||||||
|
for ( String property : properties )
|
||||||
|
{
|
||||||
|
body.append(fmt_newline);
|
||||||
|
|
||||||
|
CodeFn field_impl = parse_function( token_fmt( "class_name", class_name, "property", (StrC)property,
|
||||||
|
stringize(
|
||||||
|
void <class_name>::Client_OnRep_<property>(FGameplayAttributeData& Prev<property>)
|
||||||
|
{
|
||||||
|
GAMEPLAYATTRIBUTE_REPNOTIFY(<class_name>, <property>, Prev<property>)
|
||||||
|
}
|
||||||
|
)));
|
||||||
|
|
||||||
|
body.append( field_impl );
|
||||||
|
}
|
||||||
|
}
|
14
Project/Source/GasaGen/Readme.md
Normal file
14
Project/Source/GasaGen/Readme.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# GasaGen
|
||||||
|
|
||||||
|
This is a single translation unit meta-program for generating code for the Gasa modules.
|
||||||
|
It runs before UHT.
|
||||||
|
|
||||||
|
GasaGen.cpp is the effective translation unit.
|
||||||
|
All related code for GasaGen is prefixed with:
|
||||||
|
|
||||||
|
```GasaGen_```
|
||||||
|
|
||||||
|
Anything with the `gen` namespace (case sensitive, including the files), is related to the Gencpp header. Genccp is used.
|
||||||
|
Gencpp is a cpp library to make ergonomic use of stage metaprogramming for C++ in C++.
|
||||||
|
|
||||||
|
For how GasaGen is built see [`scripts/gen_pass_gasa.ps1`](../../../scripts/gen_pass_gasa.ps1)
|
@ -1564,7 +1564,12 @@ String CodeConstructor::to_string()
|
|||||||
void CodeConstructor::to_string_def( String& result )
|
void CodeConstructor::to_string_def( String& result )
|
||||||
{
|
{
|
||||||
AST* ClassStructParent = ast->Parent->Parent;
|
AST* ClassStructParent = ast->Parent->Parent;
|
||||||
result.append( ClassStructParent->Name );
|
if (ClassStructParent) {
|
||||||
|
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() );
|
||||||
@ -1588,12 +1593,15 @@ void CodeConstructor::to_string_fwd( String& result )
|
|||||||
if ( ast->Params )
|
if ( ast->Params )
|
||||||
result.append_fmt( "( %S )", ast->Params.to_string() );
|
result.append_fmt( "( %S )", ast->Params.to_string() );
|
||||||
else
|
else
|
||||||
{
|
result.append_fmt("()");
|
||||||
if ( ast->InlineCmt )
|
|
||||||
result.append_fmt( "(); // %S\n", ast->InlineCmt->Content );
|
if (ast->Body)
|
||||||
else
|
result.append_fmt( " = %S", ast->Body.to_string() );
|
||||||
result.append( "();\n" );
|
|
||||||
}
|
if ( ast->InlineCmt )
|
||||||
|
result.append_fmt( "; // %S\n", ast->InlineCmt->Content );
|
||||||
|
else
|
||||||
|
result.append( ";" );
|
||||||
}
|
}
|
||||||
|
|
||||||
String CodeClass::to_string()
|
String CodeClass::to_string()
|
||||||
@ -2263,15 +2271,21 @@ String CodeParam::to_string()
|
|||||||
|
|
||||||
void CodeParam::to_string( String& result )
|
void CodeParam::to_string( String& result )
|
||||||
{
|
{
|
||||||
if ( ast->ValueType.ast == nullptr )
|
if ( ast->Macro )
|
||||||
{
|
{
|
||||||
result.append_fmt( "%S", ast->Name );
|
// Were using the convention that if the value type is a macro we ignore everything else
|
||||||
|
// Related to parsing: ( <macro>, ... )
|
||||||
|
result.append( ast->Macro.ast->Content );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ast->Name )
|
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
|
else
|
||||||
result.append_fmt( "%S", ast->ValueType.to_string() );
|
result.append_fmt( "%S", ast->ValueType.to_string() );
|
||||||
|
|
||||||
@ -5826,11 +5840,12 @@ namespace parser
|
|||||||
TF_Preprocess = bit( 2 ),
|
TF_Preprocess = bit( 2 ),
|
||||||
TF_Preprocess_Cond = bit( 3 ),
|
TF_Preprocess_Cond = bit( 3 ),
|
||||||
TF_Attribute = bit( 6 ),
|
TF_Attribute = bit( 6 ),
|
||||||
TF_AccessSpecifier = bit( 7 ),
|
TF_AccessOperator = bit( 7 ),
|
||||||
TF_Specifier = bit( 8 ),
|
TF_AccessSpecifier = bit( 8 ),
|
||||||
TF_EndDefinition = bit( 9 ), // Either ; or }
|
TF_Specifier = bit( 9 ),
|
||||||
TF_Formatting = bit( 10 ),
|
TF_EndDefinition = bit( 10 ), // Either ; or }
|
||||||
TF_Literal = bit( 11 ),
|
TF_Formatting = bit( 11 ),
|
||||||
|
TF_Literal = bit( 12 ),
|
||||||
|
|
||||||
TF_Null = 0,
|
TF_Null = 0,
|
||||||
};
|
};
|
||||||
@ -5854,6 +5869,11 @@ namespace parser
|
|||||||
return { Length, Text };
|
return { Length, Text };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_access_operator()
|
||||||
|
{
|
||||||
|
return bitfield_is_equal( u32, Flags, TF_AccessOperator );
|
||||||
|
}
|
||||||
|
|
||||||
bool is_access_specifier()
|
bool is_access_specifier()
|
||||||
{
|
{
|
||||||
return bitfield_is_equal( u32, Flags, TF_AccessSpecifier );
|
return bitfield_is_equal( u32, Flags, TF_AccessSpecifier );
|
||||||
@ -6258,6 +6278,11 @@ namespace parser
|
|||||||
|
|
||||||
TokType type = ETokType::to_type( token );
|
TokType type = ETokType::to_type( token );
|
||||||
|
|
||||||
|
if (type <= TokType::Access_Public && type >= TokType::Access_Private )
|
||||||
|
{
|
||||||
|
token.Flags |= TF_AccessSpecifier;
|
||||||
|
}
|
||||||
|
|
||||||
if ( type == ETokType::Decl_Extern_Linkage )
|
if ( type == ETokType::Decl_Extern_Linkage )
|
||||||
{
|
{
|
||||||
SkipWhitespace();
|
SkipWhitespace();
|
||||||
@ -6370,7 +6395,7 @@ namespace parser
|
|||||||
scanner++;
|
scanner++;
|
||||||
length++;
|
length++;
|
||||||
}
|
}
|
||||||
if ( scanner[ 1 ] == '(' )
|
if ( scanner[ 0 ] == '(' )
|
||||||
{
|
{
|
||||||
length++;
|
length++;
|
||||||
}
|
}
|
||||||
@ -6439,7 +6464,7 @@ namespace parser
|
|||||||
token.Text = scanner;
|
token.Text = scanner;
|
||||||
token.Length = 1;
|
token.Length = 1;
|
||||||
token.Type = TokType::Access_MemberSymbol;
|
token.Type = TokType::Access_MemberSymbol;
|
||||||
token.Flags = TF_AccessSpecifier;
|
token.Flags = TF_AccessOperator;
|
||||||
|
|
||||||
if ( left )
|
if ( left )
|
||||||
{
|
{
|
||||||
@ -6805,7 +6830,7 @@ namespace parser
|
|||||||
{
|
{
|
||||||
token.Length++;
|
token.Length++;
|
||||||
// token.Type = TokType::Access_PointerToMemberSymbol;
|
// token.Type = TokType::Access_PointerToMemberSymbol;
|
||||||
token.Flags |= TF_AccessSpecifier;
|
token.Flags |= TF_AccessOperator;
|
||||||
move_forward();
|
move_forward();
|
||||||
|
|
||||||
if ( current == '*' )
|
if ( current == '*' )
|
||||||
@ -7199,6 +7224,7 @@ namespace parser
|
|||||||
internal CodeBody parse_class_struct_body( TokType which, Token name = NullToken );
|
internal CodeBody parse_class_struct_body( TokType which, Token name = NullToken );
|
||||||
internal Code parse_class_struct( TokType which, bool inplace_def );
|
internal Code parse_class_struct( TokType which, bool inplace_def );
|
||||||
internal CodeDefine parse_define();
|
internal CodeDefine parse_define();
|
||||||
|
internal Code parse_expression();
|
||||||
internal Code parse_forward_or_definition( TokType which, bool is_inplace );
|
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 CodeFn parse_function_after_name( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType ret_type, Token name );
|
||||||
internal Code parse_function_body();
|
internal Code parse_function_body();
|
||||||
@ -7217,7 +7243,7 @@ namespace parser
|
|||||||
internal CodeVar parse_variable_declaration_list();
|
internal CodeVar parse_variable_declaration_list();
|
||||||
|
|
||||||
internal CodeClass parse_class( bool inplace_def = false );
|
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 CodeDestructor parse_destructor( CodeSpecifiers specifiers = NoCode );
|
||||||
internal CodeEnum parse_enum( bool inplace_def = false );
|
internal CodeEnum parse_enum( bool inplace_def = false );
|
||||||
internal CodeBody parse_export_body();
|
internal CodeBody parse_export_body();
|
||||||
@ -7707,6 +7733,7 @@ namespace parser
|
|||||||
{
|
{
|
||||||
access = currtok.to_access_specifier();
|
access = currtok.to_access_specifier();
|
||||||
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier>
|
// <ModuleFlags> <class/struct> <Attributes> <Name> : <Access Specifier>
|
||||||
|
eat( currtok.Type );
|
||||||
}
|
}
|
||||||
|
|
||||||
Token parent_tok = parse_identifier();
|
Token parent_tok = parse_identifier();
|
||||||
@ -7791,6 +7818,13 @@ namespace parser
|
|||||||
|
|
||||||
switch ( currtok_noskip.Type )
|
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 :
|
case TokType::NewLine :
|
||||||
member = fmt_newline;
|
member = fmt_newline;
|
||||||
eat( TokType::NewLine );
|
eat( TokType::NewLine );
|
||||||
@ -7941,12 +7975,14 @@ namespace parser
|
|||||||
case TokType::Spec_Consteval :
|
case TokType::Spec_Consteval :
|
||||||
case TokType::Spec_Constexpr :
|
case TokType::Spec_Constexpr :
|
||||||
case TokType::Spec_Constinit :
|
case TokType::Spec_Constinit :
|
||||||
|
case TokType::Spec_Explicit:
|
||||||
case TokType::Spec_ForceInline :
|
case TokType::Spec_ForceInline :
|
||||||
case TokType::Spec_Inline :
|
case TokType::Spec_Inline :
|
||||||
case TokType::Spec_Mutable :
|
case TokType::Spec_Mutable :
|
||||||
case TokType::Spec_NeverInline :
|
case TokType::Spec_NeverInline :
|
||||||
case TokType::Spec_Static :
|
case TokType::Spec_Static :
|
||||||
case TokType::Spec_Volatile :
|
case TokType::Spec_Volatile :
|
||||||
|
case TokType::Spec_Virtual:
|
||||||
{
|
{
|
||||||
SpecifierT specs_found[ 16 ] { ESpecifier::NumSpecifiers };
|
SpecifierT specs_found[ 16 ] { ESpecifier::NumSpecifiers };
|
||||||
s32 NumSpecifiers = 0;
|
s32 NumSpecifiers = 0;
|
||||||
@ -7955,28 +7991,40 @@ namespace parser
|
|||||||
{
|
{
|
||||||
SpecifierT spec = ESpecifier::to_type( currtok );
|
SpecifierT spec = ESpecifier::to_type( currtok );
|
||||||
|
|
||||||
|
b32 ignore_spec = false;
|
||||||
|
|
||||||
switch ( spec )
|
switch ( spec )
|
||||||
{
|
{
|
||||||
case ESpecifier::Constexpr :
|
case ESpecifier::Constexpr :
|
||||||
case ESpecifier::Constinit :
|
case ESpecifier::Constinit :
|
||||||
|
case ESpecifier::Explicit:
|
||||||
case ESpecifier::Inline :
|
case ESpecifier::Inline :
|
||||||
case ESpecifier::ForceInline :
|
case ESpecifier::ForceInline :
|
||||||
case ESpecifier::Mutable :
|
case ESpecifier::Mutable :
|
||||||
case ESpecifier::NeverInline :
|
case ESpecifier::NeverInline :
|
||||||
case ESpecifier::Static :
|
case ESpecifier::Static :
|
||||||
case ESpecifier::Volatile :
|
case ESpecifier::Volatile :
|
||||||
|
case ESpecifier::Virtual:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ESpecifier::Consteval :
|
case ESpecifier::Consteval :
|
||||||
expects_function = true;
|
expects_function = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ESpecifier::Const :
|
||||||
|
ignore_spec = true;
|
||||||
|
break;
|
||||||
|
|
||||||
default :
|
default :
|
||||||
log_failure( "Invalid specifier %s for variable\n%s", ESpecifier::to_str( spec ), Context.to_string() );
|
log_failure( "Invalid specifier %s for variable\n%s", ESpecifier::to_str( spec ), Context.to_string() );
|
||||||
Context.pop();
|
Context.pop();
|
||||||
return CodeInvalid;
|
return CodeInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Every specifier after would be considered part of the type type signature
|
||||||
|
if (ignore_spec)
|
||||||
|
break;
|
||||||
|
|
||||||
specs_found[ NumSpecifiers ] = spec;
|
specs_found[ NumSpecifiers ] = spec;
|
||||||
NumSpecifiers++;
|
NumSpecifiers++;
|
||||||
eat( currtok.Type );
|
eat( currtok.Type );
|
||||||
@ -8018,7 +8066,7 @@ namespace parser
|
|||||||
{
|
{
|
||||||
if ( str_compare( name.Text, currtok.Text, name.Length ) == 0 )
|
if ( str_compare( name.Text, currtok.Text, name.Length ) == 0 )
|
||||||
{
|
{
|
||||||
member = parse_constructor();
|
member = parse_constructor( specifiers );
|
||||||
// <Attributes> <Specifiers> <Name>()
|
// <Attributes> <Specifiers> <Name>()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -8109,12 +8157,38 @@ namespace parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
Token tok = tokens[ idx - 1 ];
|
Token tok = tokens[ idx - 1 ];
|
||||||
|
if ( tok.is_specifier() && is_trailing( ESpecifier::to_type(tok)) )
|
||||||
|
{
|
||||||
|
// <which> <type_identifier>(...) <specifier> ...;
|
||||||
|
|
||||||
|
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 } );
|
||||||
|
// <Attributes> <Specifiers> <ReturnType/ValueType> <operator <Op>, 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 )
|
if ( tok.Type == TokType::Identifier )
|
||||||
{
|
{
|
||||||
tok = tokens[ idx - 2 ];
|
tok = tokens[ idx - 2 ];
|
||||||
|
|
||||||
bool is_indirection = tok.Type == TokType::Ampersand || tok.Type == TokType::Star;
|
bool is_indirection = tok.Type == TokType::Ampersand || tok.Type == TokType::Star;
|
||||||
|
|
||||||
bool ok_to_parse = false;
|
bool ok_to_parse = false;
|
||||||
|
|
||||||
if ( tok.Type == TokType::BraceCurly_Close )
|
if ( tok.Type == TokType::BraceCurly_Close )
|
||||||
@ -8130,6 +8204,17 @@ namespace parser
|
|||||||
// <which> <type_identifier> <identifier>;
|
// <which> <type_identifier> <identifier>;
|
||||||
ok_to_parse = true;
|
ok_to_parse = true;
|
||||||
}
|
}
|
||||||
|
else if ( tok.Type == TokType::Assign_Classifer
|
||||||
|
&& tokens[idx - 4].Type == TokType::Decl_Class
|
||||||
|
&& tokens[idx - 5].Type == which )
|
||||||
|
{
|
||||||
|
// Its a forward declaration of an enum class
|
||||||
|
// <enum> <class> <type_identifier> : <identifier>;
|
||||||
|
ok_to_parse = true;
|
||||||
|
Code result = parse_enum();
|
||||||
|
Context.pop();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
else if ( is_indirection )
|
else if ( is_indirection )
|
||||||
{
|
{
|
||||||
// Its a indirection type with type ID using struct namespace.
|
// Its a indirection type with type ID using struct namespace.
|
||||||
@ -8139,7 +8224,7 @@ namespace parser
|
|||||||
|
|
||||||
if ( ! ok_to_parse )
|
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();
|
Context.pop();
|
||||||
return CodeInvalid;
|
return CodeInvalid;
|
||||||
}
|
}
|
||||||
@ -8167,7 +8252,7 @@ namespace parser
|
|||||||
}
|
}
|
||||||
else
|
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();
|
Context.pop();
|
||||||
return CodeInvalid;
|
return CodeInvalid;
|
||||||
}
|
}
|
||||||
@ -8219,6 +8304,40 @@ namespace parser
|
|||||||
return define;
|
return define;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal inline
|
||||||
|
Code parse_assignment_expression()
|
||||||
|
{
|
||||||
|
Code expr = { nullptr };
|
||||||
|
|
||||||
|
eat( TokType::Operator );
|
||||||
|
// <Attributes> <Specifiers> <ValueType> <Name> =
|
||||||
|
|
||||||
|
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 );
|
||||||
|
// = <Expression>
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
internal inline Code parse_forward_or_definition( TokType which, bool is_inplace )
|
internal inline Code parse_forward_or_definition( TokType which, bool is_inplace )
|
||||||
{
|
{
|
||||||
Code result = CodeInvalid;
|
Code result = CodeInvalid;
|
||||||
@ -8416,6 +8535,13 @@ namespace parser
|
|||||||
|
|
||||||
switch ( currtok_noskip.Type )
|
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 :
|
case TokType::NewLine :
|
||||||
// Empty lines are auto skipped by Tokens.current()
|
// Empty lines are auto skipped by Tokens.current()
|
||||||
member = fmt_newline;
|
member = fmt_newline;
|
||||||
@ -8625,7 +8751,7 @@ namespace parser
|
|||||||
case TokType::Type_double :
|
case TokType::Type_double :
|
||||||
case TokType::Type_int :
|
case TokType::Type_int :
|
||||||
{
|
{
|
||||||
bool found_operator_cast = false;
|
bool found_operator_cast_outside_class_implmentation = false;
|
||||||
s32 idx = Context.Tokens.Idx;
|
s32 idx = Context.Tokens.Idx;
|
||||||
|
|
||||||
for ( ; idx < Context.Tokens.Arr.num(); idx++ )
|
for ( ; idx < Context.Tokens.Arr.num(); idx++ )
|
||||||
@ -8643,12 +8769,12 @@ namespace parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( tok.Type == TokType::Decl_Operator )
|
if ( tok.Type == TokType::Decl_Operator )
|
||||||
found_operator_cast = true;
|
found_operator_cast_outside_class_implmentation = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( found_operator_cast )
|
if ( found_operator_cast_outside_class_implmentation )
|
||||||
{
|
{
|
||||||
member = parse_operator_cast();
|
member = parse_operator_cast();
|
||||||
// <Attributes> <Specifiers> <Name>::operator <Type>() { ... }
|
// <Attributes> <Specifiers> <Name>::operator <Type>() { ... }
|
||||||
@ -9197,8 +9323,10 @@ namespace parser
|
|||||||
return { nullptr };
|
return { nullptr };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Code macro = { nullptr };
|
||||||
CodeType type = { nullptr };
|
CodeType type = { nullptr };
|
||||||
Code value = { nullptr };
|
Code value = { nullptr };
|
||||||
|
Token name = NullToken;
|
||||||
|
|
||||||
if ( check( TokType::Varadic_Argument ) )
|
if ( check( TokType::Varadic_Argument ) )
|
||||||
{
|
{
|
||||||
@ -9211,50 +9339,61 @@ namespace parser
|
|||||||
// or < ... >
|
// or < ... >
|
||||||
}
|
}
|
||||||
|
|
||||||
type = parse_type();
|
// Ex: Unreal has this type of macro: vvvvvvvv
|
||||||
if ( type == Code::Invalid )
|
// COREUOBJECT_API void CallFunction( FFrame& Stack, RESULT_DECL, UFunction* Function );
|
||||||
|
// This is so that a 'ValueType for the param is a preprocesor macro to support this nasty macro usage'
|
||||||
|
|
||||||
|
if ( ! check(TokType::Preprocess_Macro))
|
||||||
{
|
{
|
||||||
Context.pop();
|
type = parse_type();
|
||||||
return CodeInvalid;
|
if ( type == Code::Invalid )
|
||||||
}
|
|
||||||
// ( <ValueType>
|
|
||||||
|
|
||||||
Token name = NullToken;
|
|
||||||
|
|
||||||
if ( check( TokType::Identifier ) )
|
|
||||||
{
|
|
||||||
name = currtok;
|
|
||||||
eat( TokType::Identifier );
|
|
||||||
// ( <ValueType> <Name>
|
|
||||||
|
|
||||||
if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) )
|
|
||||||
{
|
{
|
||||||
eat( TokType::Operator );
|
Context.pop();
|
||||||
// ( <ValueType> <Name> =
|
return CodeInvalid;
|
||||||
|
|
||||||
Token value_tok = currtok;
|
|
||||||
|
|
||||||
if ( currtok.Type == TokType::Comma )
|
|
||||||
{
|
|
||||||
log_failure( "Expected value after assignment operator\n%s.", Context.to_string() );
|
|
||||||
Context.pop();
|
|
||||||
return CodeInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ( left && currtok.Type != TokType::Comma && currtok.Type != TokType::Capture_End )
|
|
||||||
{
|
|
||||||
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 ) );
|
|
||||||
// ( <ValueType> <Name> = <Expression>
|
|
||||||
}
|
}
|
||||||
|
// ( <ValueType>
|
||||||
|
|
||||||
|
if ( check( TokType::Identifier ) )
|
||||||
|
{
|
||||||
|
name = currtok;
|
||||||
|
eat( TokType::Identifier );
|
||||||
|
// ( <ValueType> <Name>
|
||||||
|
|
||||||
|
if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) )
|
||||||
|
{
|
||||||
|
eat( TokType::Operator );
|
||||||
|
// ( <ValueType> <Name> =
|
||||||
|
|
||||||
|
Token value_tok = currtok;
|
||||||
|
|
||||||
|
if ( currtok.Type == TokType::Comma )
|
||||||
|
{
|
||||||
|
log_failure( "Expected value after assignment operator\n%s.", Context.to_string() );
|
||||||
|
Context.pop();
|
||||||
|
return CodeInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( left && currtok.Type != TokType::Comma && currtok.Type != TokType::Capture_End )
|
||||||
|
{
|
||||||
|
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 ) );
|
||||||
|
// ( <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;
|
||||||
|
|
||||||
|
result->Macro = macro;
|
||||||
|
|
||||||
if ( name.Length > 0 )
|
if ( name.Length > 0 )
|
||||||
result->Name = get_cached_string( name );
|
result->Name = get_cached_string( name );
|
||||||
|
|
||||||
@ -9281,51 +9420,60 @@ namespace parser
|
|||||||
// ( <ValueType> <Name> = <Expression>, ...
|
// ( <ValueType> <Name> = <Expression>, ...
|
||||||
}
|
}
|
||||||
|
|
||||||
type = parse_type();
|
if ( ! check(TokType::Preprocess_Macro))
|
||||||
if ( type == Code::Invalid )
|
|
||||||
{
|
{
|
||||||
Context.pop();
|
type = parse_type();
|
||||||
return CodeInvalid;
|
if ( type == Code::Invalid )
|
||||||
}
|
|
||||||
// ( <ValueType> <Name> = <Expression>, <ValueType>
|
|
||||||
|
|
||||||
name = { nullptr, 0, TokType::Invalid, false };
|
|
||||||
|
|
||||||
if ( check( TokType::Identifier ) )
|
|
||||||
{
|
|
||||||
name = currtok;
|
|
||||||
eat( TokType::Identifier );
|
|
||||||
// ( <ValueType> <Name> = <Expression>, <ValueType> <Name>
|
|
||||||
|
|
||||||
if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) )
|
|
||||||
{
|
{
|
||||||
eat( TokType::Operator );
|
Context.pop();
|
||||||
// ( <ValueType> <Name> = <Expression>, <ValueType> <Name> =
|
return CodeInvalid;
|
||||||
|
|
||||||
Token value_tok = currtok;
|
|
||||||
|
|
||||||
if ( currtok.Type == TokType::Comma )
|
|
||||||
{
|
|
||||||
log_failure( "Expected value after assignment operator\n%s", Context.to_string() );
|
|
||||||
Context.pop();
|
|
||||||
return CodeInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ( left && currtok.Type != TokType::Comma && currtok.Type != TokType::Capture_End )
|
|
||||||
{
|
|
||||||
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 ) );
|
|
||||||
// ( <ValueType> <Name> = <Expression>, <ValueType> <Name> = <Expression>
|
|
||||||
}
|
}
|
||||||
|
// ( <ValueType> <Name> = <Expression>, <ValueType>
|
||||||
|
|
||||||
|
name = { nullptr, 0, TokType::Invalid, false };
|
||||||
|
|
||||||
|
if ( check( TokType::Identifier ) )
|
||||||
|
{
|
||||||
|
name = currtok;
|
||||||
|
eat( TokType::Identifier );
|
||||||
|
// ( <ValueType> <Name> = <Expression>, <ValueType> <Name>
|
||||||
|
|
||||||
|
if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) )
|
||||||
|
{
|
||||||
|
eat( TokType::Operator );
|
||||||
|
// ( <ValueType> <Name> = <Expression>, <ValueType> <Name> =
|
||||||
|
|
||||||
|
Token value_tok = currtok;
|
||||||
|
|
||||||
|
if ( currtok.Type == TokType::Comma )
|
||||||
|
{
|
||||||
|
log_failure( "Expected value after assignment operator\n%s", Context.to_string() );
|
||||||
|
Context.pop();
|
||||||
|
return CodeInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( left && currtok.Type != TokType::Comma && currtok.Type != TokType::Capture_End )
|
||||||
|
{
|
||||||
|
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 ) );
|
||||||
|
// ( <ValueType> <Name> = <Expression>, <ValueType> <Name> = <Expression>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ( <ValueType> <Name> = <Expression>, <ValueType> <Name> = <Expression>, ..
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
macro = parse_simple_preprocess(ETokType::Preprocess_Macro);
|
||||||
|
// ( ..., <Macro>
|
||||||
}
|
}
|
||||||
// ( <ValueType> <Name> = <Expression>, <ValueType> <Name> = <Expression>, ..
|
|
||||||
|
|
||||||
CodeParam param = ( CodeParam )make_code();
|
CodeParam param = ( CodeParam )make_code();
|
||||||
param->Type = Parameters;
|
param->Type = Parameters;
|
||||||
|
|
||||||
|
param->Macro = macro;
|
||||||
|
|
||||||
if ( name.Length > 0 )
|
if ( name.Length > 0 )
|
||||||
param->Name = get_cached_string( name );
|
param->Name = get_cached_string( name );
|
||||||
|
|
||||||
@ -9552,26 +9700,8 @@ namespace parser
|
|||||||
|
|
||||||
if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) )
|
if ( bitfield_is_equal( u32, currtok.Flags, TF_Assign ) )
|
||||||
{
|
{
|
||||||
eat( TokType::Operator );
|
|
||||||
// <Attributes> <Specifiers> <ValueType> <Name> =
|
|
||||||
|
|
||||||
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 );
|
|
||||||
// <Attributes> <Specifiers> <ValueType> <Name> = <Expression>
|
// <Attributes> <Specifiers> <ValueType> <Name> = <Expression>
|
||||||
|
expr = parse_assignment_expression();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( currtok.Type == TokType::BraceCurly_Open )
|
if ( currtok.Type == TokType::BraceCurly_Open )
|
||||||
@ -9789,7 +9919,7 @@ namespace parser
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal CodeConstructor parse_constructor()
|
internal CodeConstructor parse_constructor( CodeSpecifiers specifiers )
|
||||||
{
|
{
|
||||||
push_scope();
|
push_scope();
|
||||||
|
|
||||||
@ -9808,14 +9938,14 @@ namespace parser
|
|||||||
eat( TokType::Assign_Classifer );
|
eat( TokType::Assign_Classifer );
|
||||||
// <Name> ( <Parameters> ) :
|
// <Name> ( <Parameters> ) :
|
||||||
|
|
||||||
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 ) )
|
while ( left && ( currtok.Type != TokType::BraceCurly_Open || level > 0 ) )
|
||||||
{
|
{
|
||||||
if ( currtok.Type == TokType::BraceCurly_Open )
|
if (currtok.Type == TokType::Capture_Start)
|
||||||
level++;
|
level++;
|
||||||
else if ( currtok.Type == TokType::BraceCurly_Close )
|
else if ( currtok.Type == TokType::Capture_End )
|
||||||
level--;
|
level--;
|
||||||
|
|
||||||
eat( currtok.Type );
|
eat( currtok.Type );
|
||||||
@ -9833,6 +9963,10 @@ namespace parser
|
|||||||
body = parse_function_body();
|
body = parse_function_body();
|
||||||
// <Name> ( <Parameters> ) { <Body> }
|
// <Name> ( <Parameters> ) { <Body> }
|
||||||
}
|
}
|
||||||
|
else if ( check( TokType::Operator) && currtok.Text[ 0 ] == '=' )
|
||||||
|
{
|
||||||
|
body = parse_assignment_expression();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Token stmt_end = currtok;
|
Token stmt_end = currtok;
|
||||||
@ -9844,15 +9978,21 @@ 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->Specs = specifiers;
|
||||||
|
|
||||||
if ( params )
|
if ( params )
|
||||||
result->Params = params;
|
result->Params = params;
|
||||||
|
|
||||||
if ( initializer_list )
|
if ( initializer_list )
|
||||||
result->InitializerList = initializer_list;
|
result->InitializerList = initializer_list;
|
||||||
|
|
||||||
if ( body )
|
if ( body && body->Type == ECode::Function_Body )
|
||||||
{
|
{
|
||||||
result->Body = body;
|
result->Body = body;
|
||||||
result->Type = ECode::Constructor;
|
result->Type = ECode::Constructor;
|
||||||
@ -10660,54 +10800,58 @@ namespace parser
|
|||||||
s32 NumSpecifiers = 0;
|
s32 NumSpecifiers = 0;
|
||||||
|
|
||||||
attributes = parse_attributes();
|
attributes = parse_attributes();
|
||||||
// <export> template< <Parameters> > <Attributes>
|
// <export> template< <Parameters> > <Attributes> <specifiers.
|
||||||
|
|
||||||
while ( left && currtok.is_specifier() )
|
// Specifiers Parsing
|
||||||
{
|
{
|
||||||
SpecifierT spec = ESpecifier::to_type( currtok );
|
while ( left && currtok.is_specifier() )
|
||||||
|
|
||||||
switch ( spec )
|
|
||||||
{
|
{
|
||||||
case ESpecifier::Const :
|
SpecifierT spec = ESpecifier::to_type( currtok );
|
||||||
case ESpecifier::Constexpr :
|
|
||||||
case ESpecifier::Constinit :
|
switch ( spec )
|
||||||
case ESpecifier::External_Linkage :
|
{
|
||||||
case ESpecifier::Global :
|
case ESpecifier::Const :
|
||||||
case ESpecifier::Inline :
|
case ESpecifier::Constexpr :
|
||||||
case ESpecifier::ForceInline :
|
case ESpecifier::Constinit :
|
||||||
case ESpecifier::Local_Persist :
|
case ESpecifier::External_Linkage :
|
||||||
case ESpecifier::Mutable :
|
case ESpecifier::Global :
|
||||||
case ESpecifier::Static :
|
case ESpecifier::Inline :
|
||||||
case ESpecifier::Thread_Local :
|
case ESpecifier::ForceInline :
|
||||||
case ESpecifier::Volatile :
|
case ESpecifier::Local_Persist :
|
||||||
|
case ESpecifier::Mutable :
|
||||||
|
case ESpecifier::Static :
|
||||||
|
case ESpecifier::Thread_Local :
|
||||||
|
case ESpecifier::Volatile :
|
||||||
|
break;
|
||||||
|
|
||||||
|
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;
|
break;
|
||||||
|
|
||||||
case ESpecifier::Consteval :
|
specs_found[ NumSpecifiers ] = spec;
|
||||||
expects_function = true;
|
NumSpecifiers++;
|
||||||
break;
|
eat( currtok.Type );
|
||||||
|
|
||||||
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 ( NumSpecifiers )
|
||||||
if ( spec == ESpecifier::Const )
|
{
|
||||||
continue;
|
specifiers = def_specifiers( NumSpecifiers, specs_found );
|
||||||
|
}
|
||||||
specs_found[ NumSpecifiers ] = spec;
|
// <export> template< <Parameters> > <Attributes> <Specifiers>
|
||||||
NumSpecifiers++;
|
|
||||||
eat( currtok.Type );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( NumSpecifiers )
|
// TODO(Ed) : Port over user-defined operator cast detection from
|
||||||
{
|
//parse_global_nspace (which is a source defintion version) or parse_class_struct_body (which is an inline class definition)
|
||||||
specifiers = def_specifiers( NumSpecifiers, specs_found );
|
|
||||||
}
|
|
||||||
// <export> template< <Parameters> > <Attributes> <Specifiers>
|
|
||||||
|
|
||||||
// TODO(Ed) : Port over operator cast detection from parse_global_nspace or parse_class_struct_body
|
|
||||||
|
|
||||||
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> ...
|
||||||
@ -10781,12 +10925,13 @@ namespace parser
|
|||||||
if ( currtok.Type == TokType::Decl_Class || currtok.Type == TokType::Decl_Enum || currtok.Type == TokType::Decl_Struct
|
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 )
|
||||||
{
|
{
|
||||||
name = currtok;
|
|
||||||
eat( currtok.Type );
|
eat( currtok.Type );
|
||||||
// <Attributes> <Specifiers> <class, enum, struct, union>
|
// <Attributes> <Specifiers> <class, enum, struct, union>
|
||||||
|
|
||||||
name.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )name.Text;
|
name = parse_identifier();
|
||||||
eat( TokType::Identifier );
|
|
||||||
|
// name.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )name.Text;
|
||||||
|
// eat( TokType::Identifier );
|
||||||
Context.Scope->Name = name;
|
Context.Scope->Name = name;
|
||||||
// <Attributes> <Specifiers> <class, enum, struct, union> <Name>
|
// <Attributes> <Specifiers> <class, enum, struct, union> <Name>
|
||||||
}
|
}
|
||||||
@ -10835,6 +10980,12 @@ namespace parser
|
|||||||
name.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )name.Text;
|
name.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )name.Text;
|
||||||
// <Attributes> <Specifiers> <Compound type expression>
|
// <Attributes> <Specifiers> <Compound type expression>
|
||||||
}
|
}
|
||||||
|
else if ( currtok.Type == TokType::Type_Typename )
|
||||||
|
{
|
||||||
|
name = currtok;
|
||||||
|
eat(TokType::Type_Typename);
|
||||||
|
// <typename>
|
||||||
|
}
|
||||||
|
|
||||||
// The usual Identifier type signature that may have namespace qualifiers
|
// The usual Identifier type signature that may have namespace qualifiers
|
||||||
else
|
else
|
||||||
@ -11685,8 +11836,54 @@ CodeConstructor parse_constructor( StrC def )
|
|||||||
if ( toks.Arr == nullptr )
|
if ( toks.Arr == nullptr )
|
||||||
return CodeInvalid;
|
return CodeInvalid;
|
||||||
|
|
||||||
|
// 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 );
|
||||||
|
// <specifiers> ...
|
||||||
|
}
|
||||||
|
|
||||||
Context.Tokens = toks;
|
Context.Tokens = toks;
|
||||||
CodeConstructor result = parse_constructor();
|
CodeConstructor result = parse_constructor( specifiers );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11699,6 +11896,9 @@ CodeDestructor parse_destructor( StrC def )
|
|||||||
if ( toks.Arr == nullptr )
|
if ( toks.Arr == nullptr )
|
||||||
return CodeInvalid;
|
return CodeInvalid;
|
||||||
|
|
||||||
|
// TODO(Ed): Destructors can have prefix attributes
|
||||||
|
// TODO(Ed): Destructors can have virtual
|
||||||
|
|
||||||
Context.Tokens = toks;
|
Context.Tokens = toks;
|
||||||
CodeDestructor result = parse_destructor();
|
CodeDestructor result = parse_destructor();
|
||||||
return result;
|
return result;
|
||||||
|
@ -70,9 +70,9 @@ using LogFailType = sw ( * )( char const*, ... );
|
|||||||
enum class AccessSpec : u32
|
enum class AccessSpec : u32
|
||||||
{
|
{
|
||||||
Default,
|
Default,
|
||||||
Public,
|
|
||||||
Protected,
|
|
||||||
Private,
|
Private,
|
||||||
|
Protected,
|
||||||
|
Public,
|
||||||
|
|
||||||
Num_AccessSpec,
|
Num_AccessSpec,
|
||||||
Invalid,
|
Invalid,
|
||||||
@ -82,9 +82,9 @@ inline char const* to_str( AccessSpec type )
|
|||||||
{
|
{
|
||||||
local_persist char const* lookup[ ( u32 )AccessSpec::Num_AccessSpec ] = {
|
local_persist char const* lookup[ ( u32 )AccessSpec::Num_AccessSpec ] = {
|
||||||
"",
|
"",
|
||||||
"public",
|
|
||||||
"protected",
|
|
||||||
"private",
|
"private",
|
||||||
|
"protected",
|
||||||
|
"public",
|
||||||
};
|
};
|
||||||
|
|
||||||
if ( type > AccessSpec::Public )
|
if ( type > AccessSpec::Public )
|
||||||
@ -814,6 +814,7 @@ struct AST
|
|||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
AST* Macro; // Parameter
|
||||||
AST* BitfieldSize; // Variable (Class/Struct Data Member)
|
AST* BitfieldSize; // Variable (Class/Struct Data Member)
|
||||||
AST* Params; // Constructor, Function, Operator, Template, Typename
|
AST* Params; // Constructor, Function, Operator, Template, Typename
|
||||||
};
|
};
|
||||||
@ -2014,7 +2015,7 @@ struct AST_Constructor
|
|||||||
Code Next;
|
Code Next;
|
||||||
parser::Token* Tok;
|
parser::Token* Tok;
|
||||||
Code Parent;
|
Code Parent;
|
||||||
char _PAD_NAME_[ sizeof( StringCached ) ];
|
StringCached Name;
|
||||||
CodeT Type;
|
CodeT Type;
|
||||||
char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ];
|
char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ];
|
||||||
};
|
};
|
||||||
@ -2616,11 +2617,11 @@ struct AST_Param
|
|||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
char _PAD_PROPERTIES_2_[ sizeof( AST* ) * 3 ];
|
char _PAD_PROPERTIES_1_[ sizeof( AST* ) * 3 ];
|
||||||
CodeType ValueType;
|
CodeType ValueType;
|
||||||
char _PAD_PROPERTIES_[ sizeof( AST* ) ];
|
Code Macro;
|
||||||
Code Value;
|
Code Value;
|
||||||
char _PAD_PROPERTIES_3_[ sizeof( AST* ) ];
|
char _PAD_PROPERTIES_2_[ sizeof( AST* ) ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ Implementation design perfs:
|
|||||||
* Lift to more specific or generalized code-pathsonly when necessary
|
* Lift to more specific or generalized code-pathsonly when necessary
|
||||||
* Minimize distinct code-paths
|
* Minimize distinct code-paths
|
||||||
* Use classes as "filters", keep things "mega-structed"
|
* Use classes as "filters", keep things "mega-structed"
|
||||||
|
* Use composition for large sets of entiites (when possible).
|
||||||
* Never pre-emtively make interfaces or interface-like patterns
|
* Never pre-emtively make interfaces or interface-like patterns
|
||||||
* Keep everything data-wise in the runtime unless there is a measurable performance cost.
|
* Keep everything data-wise in the runtime unless there is a measurable performance cost.
|
||||||
* Some exploratory optimizations for educational purposes.
|
* Some exploratory optimizations for educational purposes.
|
||||||
|
@ -105,7 +105,7 @@ function run-gengasa
|
|||||||
|
|
||||||
$path_AbilitySystem = join-path $path_gasa 'AbilitySystem'
|
$path_AbilitySystem = join-path $path_gasa 'AbilitySystem'
|
||||||
$include = @(
|
$include = @(
|
||||||
'GasaAttributeSet.h', 'GasaAttributeSet.cpp'
|
'GasaAttributeSet.h', 'GasaAttributeSet.cpp', 'LETS_SEE.h'
|
||||||
)
|
)
|
||||||
format-cpp $path_AbilitySystem $include $null
|
format-cpp $path_AbilitySystem $include $null
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user