Updates to GasaGen, replace engine's void SBlueprintActionMenu::Construct with new code
This commit is contained in:
parent
72316023a0
commit
6058e8af01
46
GASATHON.10x
Normal file
46
GASATHON.10x
Normal file
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0"?>
|
||||
<N10X>
|
||||
<Workspace>
|
||||
<IncludeFilter>*.*</IncludeFilter>
|
||||
<ExcludeFilter>*.obj,*.lib,*.pch,*.dll,*.pdb,.vs,Debug,Release,x64,obj,*.user,Intermediate</ExcludeFilter>
|
||||
<SyncFiles>true</SyncFiles>
|
||||
<Recursive>true</Recursive>
|
||||
<ShowEmptyFolders>true</ShowEmptyFolders>
|
||||
<IncludeFilesWithoutExt>false</IncludeFilesWithoutExt>
|
||||
<IsVirtual>false</IsVirtual>
|
||||
<IsFolder>false</IsFolder>
|
||||
<BuildCommand></BuildCommand>
|
||||
<RebuildCommand></RebuildCommand>
|
||||
<BuildFileCommand></BuildFileCommand>
|
||||
<CleanCommand></CleanCommand>
|
||||
<BuildWorkingDirectory></BuildWorkingDirectory>
|
||||
<CancelBuild></CancelBuild>
|
||||
<RunCommand></RunCommand>
|
||||
<RunCommandWorkingDirectory></RunCommandWorkingDirectory>
|
||||
<DebugCommand></DebugCommand>
|
||||
<ExePathCommand></ExePathCommand>
|
||||
<DebugSln></DebugSln>
|
||||
<UseVisualStudioEnvBat>false</UseVisualStudioEnvBat>
|
||||
<Configurations>
|
||||
<Configuration>Debug</Configuration>
|
||||
<Configuration>Release</Configuration>
|
||||
</Configurations>
|
||||
<Platforms>
|
||||
<Platform>x64</Platform>
|
||||
</Platforms>
|
||||
<AdditionalIncludePaths>
|
||||
<AdditionalIncludePath>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.39.33519\include</AdditionalIncludePath>
|
||||
<AdditionalIncludePath>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.39.33519\ATLMFC\include</AdditionalIncludePath>
|
||||
<AdditionalIncludePath>C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\VS\include</AdditionalIncludePath>
|
||||
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt</AdditionalIncludePath>
|
||||
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\um</AdditionalIncludePath>
|
||||
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\shared</AdditionalIncludePath>
|
||||
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\winrt</AdditionalIncludePath>
|
||||
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\cppwinrt</AdditionalIncludePath>
|
||||
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um</AdditionalIncludePath>
|
||||
</AdditionalIncludePaths>
|
||||
<Defines></Defines>
|
||||
<ConfigProperties></ConfigProperties>
|
||||
<Children></Children>
|
||||
</Workspace>
|
||||
</N10X>
|
@ -11,6 +11,7 @@ using namespace gen;
|
||||
#include "GasaGenCommon.cpp"
|
||||
#include "GasaGen_ue_parse_testing.cpp"
|
||||
#include "GasaGen_UGasaAttributeSet.cpp"
|
||||
#include "GasaGen_ChangeBPActionMenu.cpp"
|
||||
|
||||
int gen_main()
|
||||
{
|
||||
@ -59,6 +60,8 @@ int gen_main()
|
||||
StrC str_DECLARE_EVENT_ThreeParams = txt("DECLARE_EVENT_ThreeParams(");
|
||||
StrC str_USTRUCT = txt("USTRUCT(");
|
||||
StrC str_GENERATED_USTRUCT_BODY = txt("GENERATED_USTRUCT_BODY(");
|
||||
StrC str_SLATE_BEGIN_ARGS = txt("SLATE_BEGIN_ARGS(");
|
||||
StrC str_SLATE_END_ARGS = txt("SLATE_END_ARGS(");
|
||||
|
||||
PreprocessorDefines.append( get_cached_string(str_GENERATED_BODY));
|
||||
PreprocessorDefines.append( get_cached_string(str_GENERATED_UCLASS_BODY));
|
||||
@ -97,11 +100,14 @@ int gen_main()
|
||||
PreprocessorDefines.append( get_cached_string(str_DECLARE_EVENT_ThreeParams));
|
||||
PreprocessorDefines.append( get_cached_string(str_USTRUCT));
|
||||
PreprocessorDefines.append( get_cached_string(str_GENERATED_USTRUCT_BODY));
|
||||
PreprocessorDefines.append( get_cached_string(str_SLATE_BEGIN_ARGS));
|
||||
PreprocessorDefines.append( get_cached_string(str_SLATE_END_ARGS));
|
||||
|
||||
ue_parse_testing();
|
||||
// ue_parse_testing();
|
||||
|
||||
StrC str_gasa_api = txt("GASA_API");
|
||||
|
||||
gen_UGasaAttributeSet();
|
||||
swap_SBlueprintActionMenu_Construct();
|
||||
return 0;
|
||||
}
|
||||
|
273
Project/Source/GasaGen/GasaGen_ChangeBPActionMenu.cpp
Normal file
273
Project/Source/GasaGen/GasaGen_ChangeBPActionMenu.cpp
Normal file
@ -0,0 +1,273 @@
|
||||
constexpr StrC SBlueprintActionMenu_Construct_Replacement = txt(R"(
|
||||
void SBlueprintActionMenu::Construct( const FArguments& InArgs, TSharedPtr<FBlueprintEditor> InEditor )
|
||||
{
|
||||
bActionExecuted = false;
|
||||
|
||||
this->GraphObj = InArgs._GraphObj;
|
||||
this->DraggedFromPins = InArgs._DraggedFromPins;
|
||||
this->NewNodePosition = InArgs._NewNodePosition;
|
||||
this->OnClosedCallback = InArgs._OnClosedCallback;
|
||||
this->bAutoExpandActionMenu = InArgs._AutoExpandActionMenu;
|
||||
this->EditorPtr = InEditor;
|
||||
this->OnCloseReasonCallback = InArgs._OnCloseReason;
|
||||
|
||||
// Generate the context display; showing the user what they're picking something for
|
||||
//@TODO: Should probably be somewhere more schema-sensitive than the graph panel!
|
||||
FSlateColor TypeColor;
|
||||
FString TypeOfDisplay;
|
||||
const FSlateBrush* ContextIcon = nullptr;
|
||||
|
||||
if (DraggedFromPins.Num() == 1)
|
||||
{
|
||||
UEdGraphPin* OnePin = DraggedFromPins[0];
|
||||
|
||||
const UEdGraphSchema* Schema = OnePin->GetSchema();
|
||||
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
|
||||
|
||||
if (!Schema->IsA(UEdGraphSchema_K2::StaticClass()) || !K2Schema->IsExecPin(*OnePin))
|
||||
{
|
||||
// Get the type color and icon
|
||||
TypeColor = Schema->GetPinTypeColor(OnePin->PinType);
|
||||
ContextIcon = FAppStyle::GetBrush( OnePin->PinType.IsArray() ? TEXT("Graph.ArrayPin.Connected") : TEXT("Graph.Pin.Connected") );
|
||||
}
|
||||
}
|
||||
|
||||
FBlueprintActionContext MenuContext;
|
||||
ConstructActionContext(MenuContext);
|
||||
|
||||
TSharedPtr<SWidget> AddImportTargetContent = SNullWidget::NullWidget;
|
||||
if (GetDefault<UBlueprintEditorSettings>()->bEnableNamespaceImportingFeatures)
|
||||
{
|
||||
SAssignNew(AddImportTargetContent, SBox)
|
||||
.ToolTipText(LOCTEXT("ImportActionLabelTooltip", "Choose a namespace to import and load additional actions."))
|
||||
[
|
||||
SNew(SHorizontalBox)
|
||||
+SHorizontalBox::Slot()
|
||||
.AutoWidth()
|
||||
.VAlign(VAlign_Center)
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text(LOCTEXT("ImportActionButtonLabel", "Import Actions From:"))
|
||||
]
|
||||
+SHorizontalBox::Slot()
|
||||
.AutoWidth()
|
||||
.Padding(4.f, 0.f)
|
||||
[
|
||||
SNew(SBlueprintNamespaceEntry)
|
||||
.AllowTextEntry(false)
|
||||
.OnNamespaceSelected(this, &SBlueprintActionMenu::OnNamespaceSelectedForImport)
|
||||
.OnGetNamespacesToExclude(this, &SBlueprintActionMenu::OnGetNamespacesToExcludeFromImportMenu)
|
||||
.ExcludedNamespaceTooltipText(LOCTEXT("CannotSelectNamespaceForImport", "This namespace has already been imported by this Blueprint."))
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
TSharedPtr<SComboButton> TargetContextSubMenuButton;
|
||||
// @TODO: would be nice if we could use a checkbox style for this, and have a different state for open/closed
|
||||
SAssignNew(TargetContextSubMenuButton, SComboButton)
|
||||
.MenuPlacement(MenuPlacement_MenuRight)
|
||||
.HasDownArrow(false)
|
||||
.ButtonStyle(FAppStyle::Get(), "BlueprintEditor.ContextMenu.TargetsButton")
|
||||
.ContentPadding(FMargin(5))
|
||||
.MenuContent()
|
||||
[
|
||||
SAssignNew(ContextTargetSubMenu, SBlueprintContextTargetMenu, MenuContext)
|
||||
.OnTargetMaskChanged(this, &SBlueprintActionMenu::OnContextTargetsChanged)
|
||||
.CustomTargetContent()
|
||||
[
|
||||
AddImportTargetContent.ToSharedRef()
|
||||
]
|
||||
];
|
||||
|
||||
// Build the widget layout
|
||||
TSharedRef<SBox> ContentBox = SNew(SBox);
|
||||
{
|
||||
TSharedRef<SVerticalBox> VBox = SNew(SVerticalBox);
|
||||
{
|
||||
SVerticalBox::FSlot::FSlotArguments
|
||||
SearchIndicator = SVerticalBox::Slot();
|
||||
{
|
||||
TSharedRef<SHorizontalBox> HBox = SNew(SHorizontalBox);
|
||||
{
|
||||
SHorizontalBox::FSlot::FSlotArguments
|
||||
TypePill = SHorizontalBox::Slot();
|
||||
{
|
||||
TSharedRef<SImage> PillImage = SNew(SImage);
|
||||
{
|
||||
SImage::FArguments Args;
|
||||
Args.Visibility(this, & SBlueprintActionMenu::GetTypeImageVisibility);
|
||||
PillImage->SetColorAndOpacity(TypeColor);
|
||||
PillImage->SetImage(ContextIcon);
|
||||
PillImage->Construct(Args);
|
||||
}
|
||||
SHorizontalBox::FSlot* Slot; TypePill.Expose(Slot);
|
||||
TypePill.AutoWidth();
|
||||
TypePill.VAlign(VAlign_Center);
|
||||
TypePill.Padding( FMargin(0.f, 0.f, (ContextIcon != nullptr) ? 5.f : 0.f, 0.f));
|
||||
TypePill.AttachWidget(PillImage);
|
||||
}
|
||||
|
||||
SHorizontalBox::FSlot::FSlotArguments
|
||||
SearchContextDescription = SHorizontalBox::Slot();
|
||||
{
|
||||
TSharedRef<STextBlock> TextBlock = SNew(STextBlock);
|
||||
{
|
||||
STextBlock::FArguments Args;
|
||||
Args.Text(this, & SBlueprintActionMenu::GetSearchContextDesc);
|
||||
Args.Font(FAppStyle::GetFontStyle(FName("BlueprintEditor.ActionMenu.ContextDescriptionFont")));
|
||||
Args.ToolTip(IDocumentation::Get()->CreateToolTip(
|
||||
LOCTEXT("BlueprintActionMenuContextTextTooltip", "Describes the current context of the action list"),
|
||||
NULL,
|
||||
TEXT("Shared/Editors/BlueprintEditor"),
|
||||
TEXT("BlueprintActionMenuContextText")));
|
||||
Args.AutoWrapText(true);
|
||||
TextBlock->Construct(Args);
|
||||
}
|
||||
SearchContextDescription.FillWidth(1.f);
|
||||
SearchContextDescription.VAlign(VAlign_Center);
|
||||
SearchContextDescription.AttachWidget(TextBlock);
|
||||
}
|
||||
|
||||
SHorizontalBox::FSlot::FSlotArguments
|
||||
ContextToggle = SHorizontalBox::Slot();
|
||||
{
|
||||
TSharedRef<SCheckBox> CheckBox = SNew(SCheckBox);
|
||||
{
|
||||
SCheckBox::FArguments Args;
|
||||
Args.OnCheckStateChanged(this, & SBlueprintActionMenu::OnContextToggleChanged);
|
||||
Args.IsChecked(this, & SBlueprintActionMenu::ContextToggleIsChecked);
|
||||
Args.ToolTip(IDocumentation::Get()->CreateToolTip(
|
||||
LOCTEXT("BlueprintActionMenuContextToggleTooltip"
|
||||
, "Should the list be filtered to only actions that make sense in the current context?"),
|
||||
NULL,
|
||||
TEXT("Shared/Editors/BlueprintEditor"),
|
||||
TEXT("BlueprintActionMenuContextToggle")));
|
||||
Args.Content().SlotContent.Widget = SNew(STextBlock)
|
||||
.Text(LOCTEXT("BlueprintActionMenuContextToggle", "Context Sensitive"));
|
||||
CheckBox->Construct(Args);
|
||||
}
|
||||
ContextToggle.HAlign(HAlign_Right);
|
||||
ContextToggle.VAlign(VAlign_Center);
|
||||
ContextToggle.AutoWidth();
|
||||
ContextToggle.AttachWidget( CheckBox );
|
||||
}
|
||||
|
||||
SHorizontalBox::FSlot::FSlotArguments
|
||||
ContextButton = SHorizontalBox::Slot();
|
||||
{
|
||||
ContextButton.HAlign(HAlign_Right);
|
||||
ContextButton.VAlign(VAlign_Center);
|
||||
ContextButton.AutoWidth();
|
||||
ContextButton.Padding( FMargin( 3.f, 0.f, 0.f, 0.f ));
|
||||
ContextButton.AttachWidget( TargetContextSubMenuButton.ToSharedRef() );
|
||||
}
|
||||
|
||||
SHorizontalBox::FArguments Args = SHorizontalBox::FArguments();
|
||||
Args.operator+( TypePill );
|
||||
Args.operator+( SearchContextDescription );
|
||||
Args.operator+( ContextToggle );
|
||||
Args.operator+( ContextButton );
|
||||
HBox->Construct(Args);
|
||||
}
|
||||
|
||||
SearchIndicator.AutoHeight();
|
||||
SearchIndicator.Padding( FMargin(2, 2, 2, 5));
|
||||
SearchIndicator.AttachWidget(HBox);
|
||||
}
|
||||
|
||||
SVerticalBox::FSlot::FSlotArguments
|
||||
ActionList = SVerticalBox::Slot();
|
||||
{
|
||||
SAssignNew( GraphActionMenu, SGraphActionMenu);
|
||||
|
||||
SGraphActionMenu::FArguments Args;
|
||||
Args.OnActionSelected(this, &SBlueprintActionMenu::OnActionSelected);
|
||||
Args.OnCreateWidgetForAction(SGraphActionMenu::FOnCreateWidgetForAction::CreateSP(this, &SBlueprintActionMenu::OnCreateWidgetForAction));
|
||||
Args.OnGetActionList(this, &SBlueprintActionMenu::OnGetActionList);
|
||||
Args.OnCreateCustomRowExpander_Static(&CreateCustomBlueprintActionExpander);
|
||||
Args.DraggedFromPins(DraggedFromPins);
|
||||
Args.GraphObj(GraphObj);
|
||||
GraphActionMenu->Construct(Args);
|
||||
|
||||
ActionList.AttachWidget( GraphActionMenu.ToSharedRef() );
|
||||
}
|
||||
|
||||
SVerticalBox::FSlot::FSlotArguments
|
||||
ProgressBar = SVerticalBox::Slot();
|
||||
{
|
||||
TSharedRef<SBox> Box = SNew(SBox);
|
||||
{
|
||||
TSharedRef<SProgressBar> Bar = SNew(SProgressBar);
|
||||
{
|
||||
Bar->SetBorderPadding(FVector2D( 0, 0 ));
|
||||
Bar->SetPercent( TAttribute<TOptional<float>>::CreateLambda([this]()
|
||||
{
|
||||
return ContextMenuBuilder.IsValid() ? ContextMenuBuilder->GetPendingActionsProgress() : 0.0f;
|
||||
}));
|
||||
}
|
||||
Box->SetContent( Bar );
|
||||
Box->SetHeightOverride(2);
|
||||
Box->SetVisibility(TAttribute<EVisibility>().CreateLambda([this]()
|
||||
{
|
||||
return ContextMenuBuilder.IsValid() && ContextMenuBuilder->GetNumPendingActions() > 0 ? EVisibility::SelfHitTestInvisible : EVisibility::Collapsed;
|
||||
}));
|
||||
}
|
||||
ProgressBar.AutoHeight();
|
||||
ProgressBar.AttachWidget(Box);
|
||||
}
|
||||
|
||||
SVerticalBox::FArguments Args;
|
||||
Args.operator+( SearchIndicator );
|
||||
Args.operator+( ActionList );
|
||||
Args.operator+( ProgressBar );
|
||||
VBox->Construct( Args );
|
||||
}
|
||||
|
||||
ContentBox->SetMaxDesiredWidth(500.f);
|
||||
ContentBox->SetMaxDesiredHeight(650.f);
|
||||
ContentBox->SetContent( VBox );
|
||||
|
||||
SBorder::FArguments Args;
|
||||
Args.BorderImage(FAppStyle::GetBrush("Menu.Background"));
|
||||
Args.Padding(5.0f);
|
||||
Args.operator[](ContentBox);
|
||||
SBorder::Construct(Args);
|
||||
}
|
||||
})");
|
||||
|
||||
void swap_SBlueprintActionMenu_Construct()
|
||||
{
|
||||
#define path_SBlueprintActionMenuCpp \
|
||||
R"(C:\projects\Unreal\Surgo\UE\Engine\Source\Editor\Kismet\Private\SBlueprintActionMenu.cpp)"
|
||||
|
||||
FileContents content = file_read_contents( GlobalAllocator, true, path_SBlueprintActionMenuCpp );
|
||||
CodeBody parsed_SBlueprintActionMenu = parse_global_body( StrC { content.size, (char const*)content.data });
|
||||
|
||||
CodeFn signature_to_change = parse_function( code(
|
||||
void SBlueprintActionMenu::Construct( const FArguments& InArgs, TSharedPtr<FBlueprintEditor> InEditor ) {}
|
||||
));
|
||||
|
||||
CodeBody changed_SBlueprintActionMenu = def_body(ECode::Global_Body);
|
||||
for ( Code code : parsed_SBlueprintActionMenu )
|
||||
{
|
||||
switch ( code->Type )
|
||||
{
|
||||
using namespace ECode;
|
||||
case Function:
|
||||
CodeFn function_def = code.cast<CodeFn>();
|
||||
log_fmt("%S\n", function_def->Name);
|
||||
|
||||
if ( String::are_equal(function_def->Name, signature_to_change->Name)
|
||||
&& function_def->Params.is_equal(signature_to_change->Params))
|
||||
{
|
||||
code = parse_function( SBlueprintActionMenu_Construct_Replacement );
|
||||
}
|
||||
break;
|
||||
}
|
||||
changed_SBlueprintActionMenu.append(code);
|
||||
}
|
||||
|
||||
Builder SBlueprintActionMenu_Changed = Builder::open(path_SBlueprintActionMenuCpp);
|
||||
SBlueprintActionMenu_Changed.print(changed_SBlueprintActionMenu);
|
||||
SBlueprintActionMenu_Changed.write();
|
||||
}
|
@ -68,8 +68,6 @@ void gen_UGasaAttributeSet()
|
||||
));
|
||||
body.append( GetLifetimeOfReplicatedProps );
|
||||
body.append( def_pragma( txt("endregion UObject")));
|
||||
|
||||
String test = GetLifetimeOfReplicatedProps.to_string();
|
||||
}
|
||||
GasaAttributeSet = def_class( class_name, body
|
||||
, type_UAttributeSet, AccessSpec::Public
|
||||
@ -137,11 +135,11 @@ void gen_UGasaAttributeSet()
|
||||
)));
|
||||
}
|
||||
|
||||
GetLifetimeOfReplicatedProps = parse_function( token_fmt( "body", (StrC)(field_lifetimes.to_string()), stringize(
|
||||
GetLifetimeOfReplicatedProps = parse_function( token_fmt( "field_lifetimes", (StrC)(field_lifetimes.to_string()), stringize(
|
||||
void UGasaAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
<body>
|
||||
<field_lifetimes>
|
||||
}
|
||||
)));
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ void ue_parse_testing()
|
||||
{
|
||||
switch ( class_code->Type )
|
||||
{
|
||||
case CodeT::Variable:
|
||||
// case CodeT::Variable:
|
||||
case CodeT::Function:
|
||||
case CodeT::Function_Fwd:
|
||||
if ( class_code->Name )
|
||||
|
@ -1718,7 +1718,11 @@ String CodeDestructor::to_string()
|
||||
|
||||
void CodeDestructor::to_string_def( String& result )
|
||||
{
|
||||
if ( ast->Specs )
|
||||
if ( ast->Name )
|
||||
{
|
||||
result.append_fmt( "%S()", ast->Name );
|
||||
}
|
||||
else if ( ast->Specs )
|
||||
{
|
||||
if ( ast->Specs.has( ESpecifier::Virtual ) )
|
||||
result.append_fmt( "virtual ~%S()", ast->Parent->Name );
|
||||
@ -2434,7 +2438,7 @@ void CodeStruct::to_string_def( String& result )
|
||||
{
|
||||
char const* access_level = to_str( ast->ParentAccess );
|
||||
|
||||
result.append_fmt( "%S : %s %S", ast->Name, access_level, ast->ParentType );
|
||||
result.append_fmt( "%S : %s %S", ast->Name, access_level, ast->ParentType.to_string() );
|
||||
|
||||
CodeType interface = ast->ParentType->Next->cast< CodeType >();
|
||||
if ( interface )
|
||||
@ -7302,6 +7306,7 @@ namespace parser
|
||||
internal CodeFn parse_function_after_name( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType ret_type, Token name );
|
||||
internal Code parse_function_body();
|
||||
internal Code parse_global_nspace();
|
||||
internal Code parse_global_nspace_constructor_destructor( CodeSpecifiers specifiers );
|
||||
internal Token parse_identifier( bool* possible_member_function = nullptr );
|
||||
internal CodeInclude parse_include();
|
||||
internal CodeOperator parse_operator_after_ret_type( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType ret_type );
|
||||
@ -7340,115 +7345,6 @@ namespace parser
|
||||
|
||||
constexpr bool strip_formatting_dont_preserve_newlines = false;
|
||||
|
||||
internal inline
|
||||
bool is_constructor_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.
|
||||
|
||||
TODO(Ed): We could fix this by attempting to parse a type, but we would have to have a way to have it soft fail and rollback.
|
||||
*/
|
||||
TokArray tokens = Context.Tokens;
|
||||
|
||||
s32 idx = tokens.Idx;
|
||||
Token nav = tokens[ idx ];
|
||||
for ( ; idx < tokens.Arr.num(); idx++, nav = tokens[ idx ] )
|
||||
{
|
||||
if ( nav.Text[0] == '<' )
|
||||
{
|
||||
// Skip templated expressions as they mey have expressions with the () operators
|
||||
s32 capture_level = 0;
|
||||
s32 template_level = 0;
|
||||
for ( ; idx < tokens.Arr.num(); idx++, nav = tokens[idx] )
|
||||
{
|
||||
if (nav.Text[ 0 ] == '<')
|
||||
++ template_level;
|
||||
|
||||
if (nav.Text[ 0 ] == '>')
|
||||
-- template_level;
|
||||
if (nav.Type == TokType::Operator && nav.Text[1] == '>')
|
||||
-- template_level;
|
||||
|
||||
if ( nav.Type == ETokType::Capture_Start)
|
||||
{
|
||||
if (template_level != 0 )
|
||||
++ capture_level;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if ( template_level != 0 && nav.Type == ETokType::Capture_End)
|
||||
-- capture_level;
|
||||
}
|
||||
}
|
||||
|
||||
if ( nav.Type == TokType::Capture_Start )
|
||||
break;
|
||||
}
|
||||
|
||||
-- idx;
|
||||
Token tok_right = tokens[idx];
|
||||
Token tok_left = NullToken;
|
||||
|
||||
if (tok_right.Type != TokType::Identifier)
|
||||
{
|
||||
// We're not dealing with a constructor if there is no identifier right before the opening of a parameter's scope.
|
||||
return false;
|
||||
}
|
||||
|
||||
-- idx;
|
||||
tok_left = tokens[idx];
|
||||
// <Attributes> <Specifiers> ... <Identifier>
|
||||
|
||||
if ( tok_left.Type != TokType::Access_StaticSymbol )
|
||||
return false;
|
||||
|
||||
-- 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> (
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This function was an attempt at stripping formatting from any c++ code.
|
||||
It has edge case failures that prevent it from being used in function bodies.
|
||||
@ -9012,11 +8908,11 @@ namespace parser
|
||||
case TokType::Type_double :
|
||||
case TokType::Type_int :
|
||||
{
|
||||
Code constructor_destructor = parse_global_nspace_constructor_destructor( specifiers );
|
||||
// Possible constructor implemented at global file scope.
|
||||
if (is_constructor_definition())
|
||||
if ( constructor_destructor )
|
||||
{
|
||||
member = parse_constructor( specifiers );
|
||||
// <Attributes> <Specifiers> <Name> :: <Name> <Type> () { ... }
|
||||
member = constructor_destructor;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -9074,6 +8970,134 @@ namespace parser
|
||||
return result;
|
||||
}
|
||||
|
||||
internal inline
|
||||
Code parse_global_nspace_constructor_destructor( CodeSpecifiers specifiers )
|
||||
{
|
||||
Code result = { nullptr };
|
||||
|
||||
/*
|
||||
To check if a definition is for a constructor we can go straight to the opening parenthesis for its parameters
|
||||
From There we work backwards to see if we come across two identifiers with the same name between an member access
|
||||
:: operator, there can be template parameters on the left of the :: so we ignore those.
|
||||
Whats important is that its back to back.
|
||||
|
||||
This has multiple possible faults. What we parse using this method may not filter out if something has a "return type"
|
||||
This is bad since technically you could have a namespace nested into another namespace with the same name.
|
||||
If this awful pattern is done the only way to distiguish with this coarse parse is to know there is no return type defined.
|
||||
|
||||
TODO(Ed): We could fix this by attempting to parse a type, but we would have to have a way to have it soft fail and rollback.
|
||||
*/
|
||||
TokArray tokens = Context.Tokens;
|
||||
|
||||
s32 idx = tokens.Idx;
|
||||
Token nav = tokens[ idx ];
|
||||
for ( ; idx < tokens.Arr.num(); idx++, nav = tokens[ idx ] )
|
||||
{
|
||||
if ( nav.Text[0] == '<' )
|
||||
{
|
||||
// Skip templated expressions as they mey have expressions with the () operators
|
||||
s32 capture_level = 0;
|
||||
s32 template_level = 0;
|
||||
for ( ; idx < tokens.Arr.num(); idx++, nav = tokens[idx] )
|
||||
{
|
||||
if (nav.Text[ 0 ] == '<')
|
||||
++ template_level;
|
||||
|
||||
if (nav.Text[ 0 ] == '>')
|
||||
-- template_level;
|
||||
if (nav.Type == TokType::Operator && nav.Text[1] == '>')
|
||||
-- template_level;
|
||||
|
||||
if ( nav.Type == ETokType::Capture_Start)
|
||||
{
|
||||
if (template_level != 0 )
|
||||
++ capture_level;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if ( template_level != 0 && nav.Type == ETokType::Capture_End)
|
||||
-- capture_level;
|
||||
}
|
||||
}
|
||||
|
||||
if ( nav.Type == TokType::Capture_Start )
|
||||
break;
|
||||
}
|
||||
|
||||
-- idx;
|
||||
Token tok_right = tokens[idx];
|
||||
Token tok_left = NullToken;
|
||||
|
||||
if (tok_right.Type != TokType::Identifier)
|
||||
{
|
||||
// We're not dealing with a constructor if there is no identifier right before the opening of a parameter's scope.
|
||||
return result;
|
||||
}
|
||||
|
||||
-- idx;
|
||||
tok_left = tokens[idx];
|
||||
// <Attributes> <Specifiers> ... <Identifier>
|
||||
|
||||
bool possible_destructor = false;
|
||||
if ( tok_left.Type == TokType::Operator && tok_left.Text[0] == '~')
|
||||
{
|
||||
possible_destructor = true;
|
||||
-- idx;
|
||||
tok_left = tokens[idx];
|
||||
}
|
||||
|
||||
if ( tok_left.Type != TokType::Access_StaticSymbol )
|
||||
return result;
|
||||
|
||||
-- idx;
|
||||
tok_left = tokens[idx];
|
||||
// <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
|
||||
if (possible_destructor)
|
||||
{
|
||||
// <Name> :: ~<Name> (
|
||||
result = parse_destructor( specifiers );
|
||||
}
|
||||
else {
|
||||
// <Name> :: <Name> (
|
||||
result = parse_constructor( specifiers );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO(Ed): I want to eventually change the identifier to its own AST type.
|
||||
// This would allow distinction of the qualifier for a symbol <qualifier>::<nested symboL>
|
||||
// This would also allow
|
||||
@ -9114,6 +9138,21 @@ namespace parser
|
||||
}
|
||||
}
|
||||
|
||||
if ( currtok.Type == TokType::Operator && currtok.Text[0] == '~' )
|
||||
{
|
||||
bool is_destructor = str_compare( Context.Scope->Prev->ProcName, "parse_destructor" ) == 0;
|
||||
if (is_destructor)
|
||||
{
|
||||
name.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )name.Text;
|
||||
Context.pop();
|
||||
return name;
|
||||
}
|
||||
|
||||
log_failure( "Error, had a ~ operator after %S but not a destructor\n%s", ETokType::to_str( prevtok.Type ), Context.to_string() );
|
||||
Context.pop();
|
||||
return { nullptr, 0, TokType::Invalid };
|
||||
}
|
||||
|
||||
if ( currtok.Type != TokType::Identifier )
|
||||
{
|
||||
log_failure( "Error, expected static symbol identifier, not %s\n%s", ETokType::to_str( currtok.Type ), Context.to_string() );
|
||||
@ -10332,7 +10371,7 @@ namespace parser
|
||||
eat( currtok.Type );
|
||||
}
|
||||
|
||||
initializer_list_tok.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )initializer_list_tok.Text;
|
||||
initializer_list_tok.Length = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )initializer_list_tok.Text;
|
||||
// <Name> ( <Parameters> ) : <InitializerList>
|
||||
|
||||
initializer_list = untyped_str( initializer_list_tok );
|
||||
@ -10393,6 +10432,9 @@ namespace parser
|
||||
{
|
||||
push_scope();
|
||||
|
||||
bool has_context = Context.Scope && Context.Scope->Prev;
|
||||
bool is_in_global_nspace = has_context && str_compare( Context.Scope->Prev->ProcName, "parse_global_nspace" ) == 0;
|
||||
|
||||
if ( check( TokType::Spec_Virtual ) )
|
||||
{
|
||||
if ( specifiers )
|
||||
@ -10403,6 +10445,8 @@ namespace parser
|
||||
}
|
||||
// <Virtual Specifier>
|
||||
|
||||
Token prefix_identifier = parse_identifier();
|
||||
|
||||
if ( left && currtok.Text[ 0 ] == '~' )
|
||||
eat( TokType::Operator );
|
||||
else
|
||||
@ -10467,6 +10511,12 @@ namespace parser
|
||||
|
||||
CodeDestructor result = ( CodeDestructor )make_code();
|
||||
|
||||
if ( prefix_identifier )
|
||||
{
|
||||
prefix_identifier.Length += 1 + identifier.Length;
|
||||
result->Name = get_cached_string( prefix_identifier );
|
||||
}
|
||||
|
||||
if ( specifiers )
|
||||
result->Specs = specifiers;
|
||||
|
||||
@ -11256,12 +11306,16 @@ namespace parser
|
||||
bool is_in_global_nspace = has_context && str_compare( Context.Scope->Prev->ProcName, "parse_global_nspace" ) == 0;
|
||||
|
||||
// Possible constructor implemented at global file scope.
|
||||
if (is_in_global_nspace && is_constructor_definition())
|
||||
if (is_in_global_nspace)
|
||||
{
|
||||
definition = parse_constructor( specifiers );
|
||||
Code constructor_destructor = parse_global_nspace_constructor_destructor( specifiers );
|
||||
if ( constructor_destructor )
|
||||
{
|
||||
definition = constructor_destructor;
|
||||
// <Attributes> <Specifiers> <Name> :: <Name> <Type> () { ... }
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Possible user Defined operator casts
|
||||
if (is_in_global_nspace)
|
||||
|
@ -2070,7 +2070,7 @@ struct AST_Destructor
|
||||
Code Next;
|
||||
parser::Token* Tok;
|
||||
Code Parent;
|
||||
char _PAD_NAME_[ sizeof( StringCached ) ];
|
||||
StringCached Name;
|
||||
CodeT Type;
|
||||
char _PAD_UNUSED_[ sizeof( ModuleFlag ) + sizeof( u32 ) ];
|
||||
};
|
||||
|
@ -151,17 +151,17 @@ SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpacesBeforeTrailingComments: 4
|
||||
|
||||
SpaceInEmptyBlock: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInAngles: true
|
||||
SpacesInCStyleCastParentheses: true
|
||||
SpacesInConditionalStatement: true
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: 20
|
||||
SpacesInParentheses: true
|
||||
SpacesInSquareBrackets: true
|
||||
SpacesInSquareBrackets: false
|
||||
|
||||
Standard: c++17
|
||||
|
||||
|
@ -105,8 +105,12 @@ function run-gengasa
|
||||
|
||||
$path_AbilitySystem = join-path $path_gasa 'AbilitySystem'
|
||||
$include = @(
|
||||
'GasaAttributeSet.h', 'GasaAttributeSet.cpp', 'LETS_SEE.h'
|
||||
'GasaAttributeSet.h', 'GasaAttributeSet.cpp'
|
||||
)
|
||||
format-cpp $path_AbilitySystem $include $null
|
||||
|
||||
$path_KismetPrivate = 'C:\projects\Unreal\Surgo\UE\Engine\Source\Editor\Kismet\Private\'
|
||||
$include = @( 'SBlueprintActionMenu.cpp' )
|
||||
format-cpp $path_KismetPrivate $include $null
|
||||
}
|
||||
run-gengasa
|
||||
|
Loading…
Reference in New Issue
Block a user