diff --git a/GASATHON.10x b/GASATHON.10x
new file mode 100644
index 0000000..2bfdc56
--- /dev/null
+++ b/GASATHON.10x
@@ -0,0 +1,46 @@
+
+
+
+ *.*
+ *.obj,*.lib,*.pch,*.dll,*.pdb,.vs,Debug,Release,x64,obj,*.user,Intermediate
+ true
+ true
+ true
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+ Debug
+ Release
+
+
+ x64
+
+
+ C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.39.33519\include
+ C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.39.33519\ATLMFC\include
+ C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\VS\include
+ C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt
+ C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\um
+ C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\shared
+ C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\winrt
+ C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\cppwinrt
+ C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um
+
+
+
+
+
+
diff --git a/Project/Source/GasaGen/GasaGen.cpp b/Project/Source/GasaGen/GasaGen.cpp
index f63ce16..5853b66 100644
--- a/Project/Source/GasaGen/GasaGen.cpp
+++ b/Project/Source/GasaGen/GasaGen.cpp
@@ -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;
}
diff --git a/Project/Source/GasaGen/GasaGen_ChangeBPActionMenu.cpp b/Project/Source/GasaGen/GasaGen_ChangeBPActionMenu.cpp
new file mode 100644
index 0000000..43ebf2c
--- /dev/null
+++ b/Project/Source/GasaGen/GasaGen_ChangeBPActionMenu.cpp
@@ -0,0 +1,273 @@
+constexpr StrC SBlueprintActionMenu_Construct_Replacement = txt(R"(
+void SBlueprintActionMenu::Construct( const FArguments& InArgs, TSharedPtr 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();
+
+ 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 AddImportTargetContent = SNullWidget::NullWidget;
+ if (GetDefault()->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 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 ContentBox = SNew(SBox);
+ {
+ TSharedRef VBox = SNew(SVerticalBox);
+ {
+ SVerticalBox::FSlot::FSlotArguments
+ SearchIndicator = SVerticalBox::Slot();
+ {
+ TSharedRef HBox = SNew(SHorizontalBox);
+ {
+ SHorizontalBox::FSlot::FSlotArguments
+ TypePill = SHorizontalBox::Slot();
+ {
+ TSharedRef 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 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 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 Box = SNew(SBox);
+ {
+ TSharedRef Bar = SNew(SProgressBar);
+ {
+ Bar->SetBorderPadding(FVector2D( 0, 0 ));
+ Bar->SetPercent( TAttribute>::CreateLambda([this]()
+ {
+ return ContextMenuBuilder.IsValid() ? ContextMenuBuilder->GetPendingActionsProgress() : 0.0f;
+ }));
+ }
+ Box->SetContent( Bar );
+ Box->SetHeightOverride(2);
+ Box->SetVisibility(TAttribute().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 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();
+ 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();
+}
\ No newline at end of file
diff --git a/Project/Source/GasaGen/GasaGen_UGasaAttributeSet.cpp b/Project/Source/GasaGen/GasaGen_UGasaAttributeSet.cpp
index 5126e71..4111e69 100644
--- a/Project/Source/GasaGen/GasaGen_UGasaAttributeSet.cpp
+++ b/Project/Source/GasaGen/GasaGen_UGasaAttributeSet.cpp
@@ -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& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
-
+
}
)));
}
diff --git a/Project/Source/GasaGen/GasaGen_ue_parse_testing.cpp b/Project/Source/GasaGen/GasaGen_ue_parse_testing.cpp
index f024e4e..2b39e62 100644
--- a/Project/Source/GasaGen/GasaGen_ue_parse_testing.cpp
+++ b/Project/Source/GasaGen/GasaGen_ue_parse_testing.cpp
@@ -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 )
diff --git a/Project/Source/GasaGen/gen.cpp b/Project/Source/GasaGen/gen.cpp
index 6c3f5db..cca08df 100644
--- a/Project/Source/GasaGen/gen.cpp
+++ b/Project/Source/GasaGen/gen.cpp
@@ -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];
- // ...
-
- if ( tok_left.Type != TokType::Access_StaticSymbol )
- return false;
-
- -- idx;
- tok_left = tokens[idx];
- // ... ::
-
- // We search toward the left until we find the next valid identifier
- s32 capture_level = 0;
- s32 template_level = 0;
- while ( idx != tokens.Idx )
- {
- if (tok_left.Text[ 0 ] == '<')
- ++ template_level;
-
- if (tok_left.Text[ 0 ] == '>')
- -- template_level;
- if (tok_left.Type == TokType::Operator && tok_left.Text[1] == '>')
- -- template_level;
-
- if ( template_level != 0 && tok_left.Type == ETokType::Capture_Start)
- ++ capture_level;
-
- if ( template_level != 0 && tok_left.Type == ETokType::Capture_End)
- -- capture_level;
-
- if ( capture_level == 0 && template_level == 0 && tok_left.Type == TokType::Identifier )
- break;
-
- -- idx;
- tok_left = tokens[idx];
- }
-
- bool is_same = str_compare( tok_right.Text, tok_left.Text, tok_right.Length ) == 0;
- if (tok_left.Type == TokType::Identifier && is_same)
- {
- // We have found the pattern we desired
- // :: (
- 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 );
- // :: () { ... }
+ 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];
+ // ...
+
+ bool possible_destructor = false;
+ if ( tok_left.Type == TokType::Operator && tok_left.Text[0] == '~')
+ {
+ possible_destructor = true;
+ -- idx;
+ tok_left = tokens[idx];
+ }
+
+ if ( tok_left.Type != TokType::Access_StaticSymbol )
+ return result;
+
+ -- idx;
+ tok_left = tokens[idx];
+ // ... ::
+
+ // We search toward the left until we find the next valid identifier
+ s32 capture_level = 0;
+ s32 template_level = 0;
+ while ( idx != tokens.Idx )
+ {
+ if (tok_left.Text[ 0 ] == '<')
+ ++ template_level;
+
+ if (tok_left.Text[ 0 ] == '>')
+ -- template_level;
+ if (tok_left.Type == TokType::Operator && tok_left.Text[1] == '>')
+ -- template_level;
+
+ if ( template_level != 0 && tok_left.Type == ETokType::Capture_Start)
+ ++ capture_level;
+
+ if ( template_level != 0 && tok_left.Type == ETokType::Capture_End)
+ -- capture_level;
+
+ if ( capture_level == 0 && template_level == 0 && tok_left.Type == TokType::Identifier )
+ break;
+
+ -- idx;
+ tok_left = tokens[idx];
+ }
+
+ bool is_same = str_compare( tok_right.Text, tok_left.Text, tok_right.Length ) == 0;
+ if (tok_left.Type == TokType::Identifier && is_same)
+ {
+ // We have found the pattern we desired
+ if (possible_destructor)
+ {
+ // :: ~ (
+ result = parse_destructor( specifiers );
+ }
+ else {
+ // :: (
+ result = parse_constructor( specifiers );
+ }
+ }
+
+ return result;
+ }
+
// TODO(Ed): I want to eventually change the identifier to its own AST type.
// This would allow distinction of the qualifier for a 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;
// ( ) :
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
}
//
+ 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,11 +11306,15 @@ 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 );
- // :: () { ... }
- break;
+ Code constructor_destructor = parse_global_nspace_constructor_destructor( specifiers );
+ if ( constructor_destructor )
+ {
+ definition = constructor_destructor;
+ // :: () { ... }
+ break;
+ }
}
// Possible user Defined operator casts
diff --git a/Project/Source/GasaGen/gen.hpp b/Project/Source/GasaGen/gen.hpp
index 8613334..95085b1 100644
--- a/Project/Source/GasaGen/gen.hpp
+++ b/Project/Source/GasaGen/gen.hpp
@@ -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 ) ];
};
diff --git a/scripts/.clang-format b/scripts/.clang-format
index 06805ad..eeda36b 100644
--- a/scripts/.clang-format
+++ b/scripts/.clang-format
@@ -151,17 +151,17 @@ SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpacesBeforeTrailingComments: 4
-SpaceInEmptyBlock: true
+SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
-SpacesInAngles: true
-SpacesInCStyleCastParentheses: true
-SpacesInConditionalStatement: true
-SpacesInContainerLiterals: true
+SpacesInAngles: false
+SpacesInCStyleCastParentheses: false
+SpacesInConditionalStatement: false
+SpacesInContainerLiterals: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: 20
SpacesInParentheses: true
-SpacesInSquareBrackets: true
+SpacesInSquareBrackets: false
Standard: c++17
diff --git a/scripts/gen_pass_gasa.ps1 b/scripts/gen_pass_gasa.ps1
index 62ded28..1293420 100644
--- a/scripts/gen_pass_gasa.ps1
+++ b/scripts/gen_pass_gasa.ps1
@@ -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