diff --git a/CMake/LLVM.cmake b/CMake/LLVM.cmake index 9366cb75..36f3a032 100644 --- a/CMake/LLVM.cmake +++ b/CMake/LLVM.cmake @@ -31,10 +31,10 @@ message(STATUS "LLVM_INCLUDE_DIRS: ${LLVM_INCLUDE_DIRS}") message(STATUS "LLVM_DEFINITIONS: ${LLVM_DEFINITIONS_LIST}") -add_library(LLVM INTERFACE) -target_include_directories(LLVM INTERFACE ${LLVM_INCLUDE_DIRS}) +add_library(RiftLLVM INTERFACE) +target_include_directories(RiftLLVM INTERFACE ${LLVM_INCLUDE_DIRS}) llvm_map_components_to_libnames(llvm_libs core x86asmparser x86codegen) -target_link_libraries(LLVM INTERFACE ${LLVM_AVAILABLE_LIBS}) -target_compile_definitions(LLVM INTERFACE ${LLVM_DEFINITIONS_LIST} -DNOMINMAX) +target_link_libraries(RiftLLVM INTERFACE ${LLVM_AVAILABLE_LIBS}) +target_compile_definitions(RiftLLVM INTERFACE ${LLVM_DEFINITIONS_LIST} -DNOMINMAX) # rift_target_disable_all_warnings(LLVM INTERFACE) diff --git a/Libs/Backends/LLVM/CMakeLists.txt b/Libs/Backends/LLVM/CMakeLists.txt index 7461ad15..d8749cbc 100644 --- a/Libs/Backends/LLVM/CMakeLists.txt +++ b/Libs/Backends/LLVM/CMakeLists.txt @@ -12,7 +12,7 @@ rift_target_shared_output_directory(RiftBackendLLVM) target_link_libraries(RiftBackendLLVM PUBLIC Rift::Rift) -target_link_libraries(RiftBackendLLVM PRIVATE LLVM) +target_link_libraries(RiftBackendLLVM PRIVATE RiftLLVM) install(TARGETS RiftBackendLLVM diff --git a/Libs/Editor/Include/Utils/FunctionGraph.h b/Libs/Editor/Include/Utils/FunctionGraph.h index 480c492f..1065184b 100644 --- a/Libs/Editor/Include/Utils/FunctionGraph.h +++ b/Libs/Editor/Include/Utils/FunctionGraph.h @@ -32,6 +32,7 @@ namespace Rift::Graph float GetSpaceHeight(u32 height) const; v2 GetContentPadding() const; + v2 GetGridPosition(v2 screenPosition) const; }; inline Settings settings{}; @@ -46,16 +47,13 @@ namespace Rift::Graph void Init(); void Shutdown(); - void PushNodeStyle(); void PopNodeStyle(); void PushInnerNodeStyle(); void PopInnerNodeStyle(); - void DrawContextMenu(AST::Tree& ast); void DrawTypeGraph(AST::Tree& ast, AST::Id typeId, CTypeEditor& typeEditor); - v2 GetGridPosition(v2 screenPosition); void SetNodePosition(AST::Id id, v2 position); v2 GetNodePosition(AST::Id id); diff --git a/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h b/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h new file mode 100644 index 00000000..4467c231 --- /dev/null +++ b/Libs/Editor/Include/Utils/FunctionGraphContextMenu.h @@ -0,0 +1,11 @@ +// Copyright 2015-2022 Piperift - All rights reserved +#pragma once + +#include +#include + + +namespace Rift::Graph +{ + void DrawContextMenu(AST::Tree& ast, AST::Id typeId, AST::Id hoveredNodeId); +} // namespace Rift::Graph diff --git a/Libs/Editor/Include/Utils/Nodes.h b/Libs/Editor/Include/Utils/Nodes.h index ce678072..fe75bdaf 100644 --- a/Libs/Editor/Include/Utils/Nodes.h +++ b/Libs/Editor/Include/Utils/Nodes.h @@ -439,15 +439,16 @@ namespace Rift::Nodes // Use the following functions to query a change of state for an existing link, or new link. // Call these after EndNodeEditor(). - // Did the user start dragging a new link from a pin? - bool IsLinkStarted(Id* outputPinId); + bool IsDraggingLink(); + TPair GetDraggedOriginPin(); // Did the user drop the dragged link before attaching it to a pin? // There are two different kinds of situations to consider when handling this event: // 1) a link which is created at a pin and then dropped // 2) an existing link which is detached from a pin and then dropped // Use the including_detached_links flag to control whether this function triggers when the // user detaches a link and drops it. - bool IsLinkDropped(Id* outputPinId = nullptr, bool includingDetachedLinks = true); + bool IsLinkDropped( + Id* outputId = nullptr, Id* inputId = nullptr, bool includingDetachedLinks = true); // Did the user finish creating a new link? bool IsLinkCreated(Id& outputPinId, Id& inputPinId, bool* createdFromSnap = nullptr); bool IsLinkCreated(AST::Id& outputNodeId, Id& outputPinId, AST::Id& inputNodeId, Id& inputPinId, diff --git a/Libs/Editor/Include/Utils/NodesInternal.h b/Libs/Editor/Include/Utils/NodesInternal.h index a3bd9361..9288c09f 100644 --- a/Libs/Editor/Include/Utils/NodesInternal.h +++ b/Libs/Editor/Include/Utils/NodesInternal.h @@ -122,7 +122,6 @@ namespace Rift::Nodes T& Get(AST::Id id) { - Check(Contains(id)); return *GetByIndex(AST::GetIndex(id)); } @@ -186,6 +185,7 @@ namespace Rift::Nodes private: T* GetByIndex(u32 index) { + Check(data.IsValidIndex(index)); return data.Data() + index; } }; diff --git a/Libs/Editor/Src/Utils/FunctionGraph.cpp b/Libs/Editor/Src/Utils/FunctionGraph.cpp index 57728ae5..b81d3ace 100644 --- a/Libs/Editor/Src/Utils/FunctionGraph.cpp +++ b/Libs/Editor/Src/Utils/FunctionGraph.cpp @@ -5,8 +5,8 @@ #include "Components/CTypeEditor.h" #include "DockSpaceLayout.h" #include "Utils/EditorStyle.h" +#include "Utils/FunctionGraphContextMenu.h" #include "Utils/FunctionUtils.h" -#include "Utils/TypeUtils.h" #include #include @@ -26,9 +26,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -71,6 +71,11 @@ namespace Rift::Graph return {0.f, settings.verticalMargin + settings.verticalPadding}; } + v2 Settings::GetGridPosition(v2 screenPosition) const + { + return Nodes::ScreenToGridPosition(screenPosition) * GetInvGridSize(); + } + void BeginNode(TAccessRef> access, AST::Id id) { currentNodeTransform = &access.GetOrAdd(id); @@ -465,223 +470,6 @@ namespace Rift::Graph { ImGui::PopStyleVar(2); } - void DrawNodeContextMenu(AST::Tree& ast, AST::Id typeId, TSpan nodeIds) - { - Check(!nodeIds.IsEmpty()); - - AST::Id firstNodeId = nodeIds[0]; - - if (nodeIds.Size() == 1 && ast.Has(firstNodeId)) - { - if (UI::MenuItem("Add return node")) - { - AST::Id newId = Functions::AddReturn({ast, typeId}); - if (!IsNone(newId)) - { - v2 position = ast.Get(firstNodeId).position; - ast.Add(newId, position + v2{10.f, 0.f}); - - AST::Statements::TryConnect(ast, firstNodeId, newId); - } - } - UI::Separator(); - } - if (UI::MenuItem("Delete")) - { - Functions::RemoveNodes(ast, nodeIds); - } - } - - void DrawGraphContextMenu(AST::Tree& ast, AST::Id typeId) - { - static ImGuiTextFilter filter; - if (UI::IsWindowAppearing()) - { - UI::SetKeyboardFocusHere(); - } - filter.Draw("##Filter"); - const v2 clickPos = UI::GetMousePosOnOpeningCurrentPopup(); - const v2 gridPos = GetGridPosition(clickPos).Floor(); - - if (filter.IsActive() || UI::TreeNode("Flow")) - { - if (filter.PassFilter("Return") && UI::MenuItem("Return")) - { - AST::Id newId = Functions::AddReturn({ast, typeId}); - if (!IsNone(newId)) - { - ast.Add(newId, gridPos); - } - } - if (filter.PassFilter("If") && UI::MenuItem("If")) - { - AST::Id newId = Functions::AddIf({ast, typeId}); - if (!IsNone(newId)) - { - ast.Add(newId, gridPos); - } - } - - if (!filter.IsActive()) - { - UI::TreePop(); - } - } - - if (filter.IsActive() || UI::TreeNode("Operators")) - { - static String name; - // Unary operators - for (auto type : Refl::GetEnumValues()) - { - StringView shortName = Functions::GetUnaryOperatorName(type); - StringView longName = Functions::GetUnaryOperatorLongName(type); - name.clear(); - Strings::FormatTo(name, "{} ({})", shortName, longName); - if (filter.PassFilter(name.data(), name.data() + name.size()) - && UI::MenuItem(name.data())) - { - AST::Id newId = Functions::AddUnaryOperator({ast, typeId}, type); - if (!IsNone(newId)) - { - ast.Add(newId, gridPos); - } - } - } - // Binary operators - for (auto type : Refl::GetEnumValues()) - { - StringView shortName = Functions::GetBinaryOperatorName(type); - StringView longName = Functions::GetBinaryOperatorLongName(type); - name.clear(); - Strings::FormatTo(name, "{} ({})", shortName, longName); - if (filter.PassFilter(name.data(), name.data() + name.size()) - && UI::MenuItem(name.data())) - { - AST::Id newId = Functions::AddBinaryOperator({ast, typeId}, type); - if (!IsNone(newId)) - { - ast.Add(newId, gridPos); - } - } - } - - if (!filter.IsActive()) - { - UI::TreePop(); - } - } - - if (filter.IsActive() || UI::TreeNode("Constructors")) - { - String makeStr{}; - auto& typeList = ast.GetStatic(); - auto types = ast.Filter(); - for (const auto& it : typeList.typesByName) - { - if (auto* type = types.TryGet(it.second)) - { - makeStr.clear(); - Strings::FormatTo(makeStr, "Make {}", type->name); - if (filter.PassFilter(makeStr.c_str(), makeStr.c_str() + makeStr.size())) - { - if (UI::MenuItem(makeStr.c_str())) - { - AST::Id newId = Functions::AddLiteral({ast, typeId}, it.second); - if (!IsNone(newId)) - { - ast.Add(newId, gridPos); - } - } - } - } - } - - if (!filter.IsActive()) - { - UI::TreePop(); - } - } - - if (filter.IsActive() || UI::TreeNode("Variables")) - { - auto variables = ast.Filter(); - auto identifiers = ast.Filter(); - for (AST::Id variableId : variables) - { - if (auto* iden = identifiers.TryGet(variableId)) - { - const String& name = iden->name.ToString(); - if (filter.PassFilter(name.c_str(), name.c_str() + name.size())) - { - if (UI::MenuItem(name.c_str())) - { - AST::Id newId = - Functions::AddDeclarationReference({ast, typeId}, variableId); - if (!IsNone(newId)) - { - ast.Add(newId, gridPos); - } - } - } - } - } - - if (!filter.IsActive()) - { - UI::TreePop(); - } - } - - if (filter.IsActive() || UI::TreeNode("Functions")) - { - auto functions = ast.Filter(); - auto identifiers = ast.Filter(); - for (AST::Id functionId : functions) - { - if (auto* iden = identifiers.TryGet(functionId)) - { - const String& name = iden->name.ToString(); - if (filter.PassFilter(name.c_str(), name.c_str() + name.size())) - { - if (UI::MenuItem(name.c_str())) - { - AST::Id newId = Functions::AddCall({ast, typeId}, functionId); - if (!IsNone(newId)) - { - ast.Add(newId, gridPos); - } - } - } - } - } - - if (!filter.IsActive()) - { - ImGui::TreePop(); - } - } - } - - void DrawContextMenu(AST::Tree& ast, AST::Id typeId, AST::Id hoveredNodeId) - { - if (ImGui::BeginPopup("GraphContextMenu")) - { - if (IsNone(hoveredNodeId)) - { - DrawGraphContextMenu(ast, typeId); - } - else if (Nodes::IsNodeSelected(hoveredNodeId)) - { - DrawNodeContextMenu(ast, typeId, Nodes::GetSelectedNodes()); - } - else - { - DrawNodeContextMenu(ast, typeId, hoveredNodeId); - } - ImGui::EndPopup(); - } - } void DrawFunctionDecls(AST::Tree& ast, const TArray& functionDecls) { @@ -1065,15 +853,15 @@ namespace Rift::Graph // Links DrawStatementLinks(ast, *children); DrawExpressionLinks(ast, *children); - - if (UI::IsKeyReleased(GLFW_KEY_DELETE)) - { - Functions::RemoveNodes(ast, Nodes::GetSelectedNodes()); - } } Nodes::DrawMiniMap(0.2f, Nodes::MiniMapCorner::TopRight); PopNodeStyle(); + + if (UI::IsKeyReleased(GLFW_KEY_DELETE)) + { + Functions::RemoveNodes(ast, Nodes::GetSelectedNodes()); + } Nodes::EndNodeEditor(); Nodes::Id outputPin; @@ -1102,12 +890,6 @@ namespace Rift::Graph } } - - v2 GetGridPosition(v2 screenPosition) - { - return Nodes::ScreenToGridPosition(screenPosition) * settings.GetInvGridSize(); - } - void SetNodePosition(AST::Id id, v2 position) { position *= settings.GetGridSize(); diff --git a/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp new file mode 100644 index 00000000..0d3af62c --- /dev/null +++ b/Libs/Editor/Src/Utils/FunctionGraphContextMenu.cpp @@ -0,0 +1,254 @@ +// Copyright 2015-2022 Piperift - All rights reserved + +#include "Utils/FunctionGraphContextMenu.h" + +#include "Utils/FunctionGraph.h" +#include "Utils/FunctionUtils.h" +#include "Utils/TypeUtils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace Rift::Graph +{ + void SetPositionAndConnect(AST::Tree& ast, AST::Id id, v2 position) + { + if (!IsNone(id)) + { + ast.Add(id, position); + + // TODO: Improve nodes input to handle this correctly + TPair linkPin = Nodes::GetDraggedOriginPin(); + const AST::Id linkPinId = AST::Id(linkPin.first); + switch (linkPin.second) + { + case Nodes::PinType::Output: + AST::Statements::TryConnect(ast, linkPinId, id); + AST::Expressions::TryConnect(ast, linkPinId, id); + break; + case Nodes::PinType::Input: + AST::Statements::TryConnect(ast, id, linkPinId); + AST::Expressions::TryConnect(ast, id, linkPinId); + break; + default: break; + } + } + } + + bool ContextTreeNode(StringView name, const ImGuiTextFilter& filter) + { + return filter.IsActive() || UI::TreeNode(name.data()); + } + void ContextTreePop(const ImGuiTextFilter& filter) + { + if (!filter.IsActive()) + { + UI::TreePop(); + } + } + + bool ContextItem(StringView name, const ImGuiTextFilter& filter) + { + if (filter.PassFilter(name.data(), name.data() + name.size())) + { + // Return true also if Enter is pressed + if (UI::MenuItem(name.data()) + || (UI::IsItemFocused() && UI::IsKeyPressedMap(ImGuiKey_Enter))) + { + UI::CloseCurrentPopup(); + return true; + } + } + return false; + } + + void DrawNodeContextMenu(AST::Tree& ast, AST::Id typeId, TSpan nodeIds) + { + Check(!nodeIds.IsEmpty()); + + AST::Id firstNodeId = nodeIds[0]; + + if (nodeIds.Size() == 1 && ast.Has(firstNodeId)) + { + if (UI::MenuItem("Add return node")) + { + AST::Id newId = Functions::AddReturn({ast, typeId}); + if (!IsNone(newId)) + { + v2 position = ast.Get(firstNodeId).position; + ast.Add(newId, position + v2{10.f, 0.f}); + + AST::Statements::TryConnect(ast, firstNodeId, newId); + } + } + UI::Separator(); + } + if (UI::MenuItem("Delete")) + { + Functions::RemoveNodes(ast, nodeIds); + } + } + + void DrawGraphContextMenu(AST::Tree& ast, AST::Id typeId) + { + static ImGuiTextFilter filter; + if (UI::IsWindowAppearing()) + { + UI::SetKeyboardFocusHere(); + filter.Clear(); + } + filter.Draw("##Filter"); + const v2 clickPos = UI::GetMousePosOnOpeningCurrentPopup(); + const v2 gridPos = settings.GetGridPosition(clickPos).Floor(); + + if (ContextTreeNode("Flow", filter)) + { + if (ContextItem("Return", filter)) + { + AST::Id newId = Functions::AddReturn({ast, typeId}); + SetPositionAndConnect(ast, newId, gridPos); + } + if (ContextItem("If", filter)) + { + AST::Id newId = Functions::AddIf({ast, typeId}); + SetPositionAndConnect(ast, newId, gridPos); + } + ContextTreePop(filter); + } + + if (ContextTreeNode("Constructors", filter)) + { + String makeStr{}; + auto& typeList = ast.GetStatic(); + auto types = ast.Filter(); + for (const auto& it : typeList.typesByName) + { + if (auto* type = types.TryGet(it.second)) + { + makeStr.clear(); + Strings::FormatTo(makeStr, "Make {}", type->name); + if (ContextItem(makeStr, filter)) + { + AST::Id newId = Functions::AddLiteral({ast, typeId}, it.second); + SetPositionAndConnect(ast, newId, gridPos); + } + } + } + ContextTreePop(filter); + } + + if (ContextTreeNode("Functions", filter)) + { + static String label; + TAccess access{ast}; + for (AST::Id functionId : AST::ListAll(access)) + { + Name name = access.Get(functionId).name; + label.clear(); + AST::Id typeId = AST::Hierarchy::GetParent(access, functionId); + if (!IsNone(typeId) && access.Has(typeId)) + { + Strings::FormatTo( + label, "{} ({})", name, access.Get(typeId).name); + } + else + { + Strings::FormatTo(label, "{}", name); + } + if (ContextItem(label, filter)) + { + AST::Id newId = Functions::AddCall({ast, typeId}, functionId); + SetPositionAndConnect(ast, newId, gridPos); + } + } + ContextTreePop(filter); + } + + if (ContextTreeNode("Variables", filter)) + { + static String label; + TAccess access{ast}; + for (AST::Id variableId : AST::ListAll(access)) + { + Name name = access.Get(variableId).name; + label.clear(); + AST::Id typeId = AST::Hierarchy::GetParent(access, variableId); + if (!IsNone(typeId) && access.Has(typeId)) + { + Strings::FormatTo( + label, "{} ({})", name, access.Get(typeId).name); + } + else + { + Strings::FormatTo(label, "{}", name); + } + if (ContextItem(label, filter)) + { + AST::Id newId = Functions::AddDeclarationReference({ast, typeId}, variableId); + SetPositionAndConnect(ast, newId, gridPos); + } + } + ContextTreePop(filter); + } + + if (ContextTreeNode("Operators", filter)) + { + static String name; + // Unary operators + for (auto type : Refl::GetEnumValues()) + { + name.clear(); + StringView shortName = Functions::GetUnaryOperatorName(type); + StringView longName = Functions::GetUnaryOperatorLongName(type); + Strings::FormatTo(name, "{} ({})", shortName, longName); + if (ContextItem(name, filter)) + { + AST::Id newId = Functions::AddUnaryOperator({ast, typeId}, type); + SetPositionAndConnect(ast, newId, gridPos); + } + } + // Binary operators + for (auto type : Refl::GetEnumValues()) + { + name.clear(); + StringView shortName = Functions::GetBinaryOperatorName(type); + StringView longName = Functions::GetBinaryOperatorLongName(type); + Strings::FormatTo(name, "{} ({})", shortName, longName); + if (ContextItem(name, filter)) + { + AST::Id newId = Functions::AddBinaryOperator({ast, typeId}, type); + SetPositionAndConnect(ast, newId, gridPos); + } + } + ContextTreePop(filter); + } + } + + void DrawContextMenu(AST::Tree& ast, AST::Id typeId, AST::Id hoveredNodeId) + { + if (ImGui::BeginPopup("GraphContextMenu")) + { + if (IsNone(hoveredNodeId)) + { + DrawGraphContextMenu(ast, typeId); + } + else if (Nodes::IsNodeSelected(hoveredNodeId)) + { + DrawNodeContextMenu(ast, typeId, Nodes::GetSelectedNodes()); + } + else + { + DrawNodeContextMenu(ast, typeId, hoveredNodeId); + } + ImGui::EndPopup(); + } + } +} // namespace Rift::Graph diff --git a/Libs/Editor/Src/Utils/Nodes.cpp b/Libs/Editor/Src/Utils/Nodes.cpp index 5b0d2d5c..058c96c4 100644 --- a/Libs/Editor/Src/Utils/Nodes.cpp +++ b/Libs/Editor/Src/Utils/Nodes.cpp @@ -2552,27 +2552,28 @@ namespace Rift::Nodes return true; } - bool IsLinkStarted(Id* outputId, Id* inputId) + bool IsDraggingLink() { - // Call this function after EndNodeEditor()! - assert(gNodes->currentScope != Scope::None); - assert(outputId != nullptr); - if ((gNodes->UIState & UIState_LinkStarted) != 0) + return (gNodes->UIState & UIState_LinkStarted) != 0; + } + TPair GetDraggedOriginPin() + { + if (IsDraggingLink()) { const EditorContext& editor = GetEditorContext(); - const i32 outputIdx = editor.clickInteraction.linkCreation.outputIdx; - if (outputId && outputIdx != NO_INDEX) + + const i32 outputIdx = editor.clickInteraction.linkCreation.outputIdx; + if (outputIdx != NO_INDEX) { - *outputId = editor.GetPinData({outputIdx, PinType::Output}).id; + return {editor.GetPinData({outputIdx, PinType::Output}).id, PinType::Output}; } const i32 inputIdx = editor.clickInteraction.linkCreation.inputIdx; - if (inputId && inputIdx != NO_INDEX) + if (inputIdx != NO_INDEX) { - *inputId = editor.GetPinData({inputIdx, PinType::Input}).id; + return {editor.GetPinData({inputIdx, PinType::Input}).id, PinType::Input}; } - return true; } - return false; + return {0, PinType::None}; } bool IsLinkDropped(Id* outputId, Id* inputId, bool includingDetachedLinks) diff --git a/Libs/Framework/Include/AST/Types.h b/Libs/Framework/Include/AST/Types.h index 13f5ab62..0414a863 100644 --- a/Libs/Framework/Include/AST/Types.h +++ b/Libs/Framework/Include/AST/Types.h @@ -126,5 +126,5 @@ namespace Rift::AST constexpr bool IsNone(Rift::AST::Id id) { - return id == Rift::AST::NoId; + return Rift::AST::GetVersion(id) == Rift::AST::GetVersion(Rift::AST::NoId); } diff --git a/Libs/Framework/Src/AST/Filtering.cpp b/Libs/Framework/Src/AST/Filtering.cpp index 13f97c32..9a892873 100644 --- a/Libs/Framework/Src/AST/Filtering.cpp +++ b/Libs/Framework/Src/AST/Filtering.cpp @@ -185,8 +185,17 @@ namespace Rift::AST const Pool* iterablePool = pools[smallestIdx]; pools.RemoveAtSwap(smallestIdx); - ids.Empty(); - ids.Append(iterablePool->begin(), iterablePool->end()); + ids.Empty(false); + ids.Reserve(iterablePool->Size()); + for (AST::Id id : *iterablePool) + { + if (!IsNone(id)) [[likely]] + { + ids.Add(id); + } + } + // Faster but doesnt exclude invalid ids. TODO: Improve PoolSet + // ids.Append(iterablePool->begin(), iterablePool->end()); for (const Pool* pool : pools) { diff --git a/Libs/Framework/Src/AST/Utils/Statements.cpp b/Libs/Framework/Src/AST/Utils/Statements.cpp index c4047ffc..804223aa 100644 --- a/Libs/Framework/Src/AST/Utils/Statements.cpp +++ b/Libs/Framework/Src/AST/Utils/Statements.cpp @@ -40,7 +40,6 @@ namespace Rift::AST::Statements else { outputNode = Hierarchy::GetParent(ast, outputPin); - Log::Error("{}", outputNode); if (IsNone(outputNode)) { return false; diff --git a/Project/Inventory.rf b/Project/Inventory.rf index a355a3de..5f22de58 100644 --- a/Project/Inventory.rf +++ b/Project/Inventory.rf @@ -1,6 +1,6 @@ { "type": "Class", - "count": 9, + "count": 11, "roots": [ 0 ], @@ -12,13 +12,18 @@ "3": 0, "4": 0, "5": 0, - "6": 2, - "7": 2, - "8": 2 + "6": 0, + "7": 0, + "8": 2, + "9": 2, + "10": 2 }, "CDeclClass": { "0": {} }, + "CDeclVariable": { + "7": {} + }, "CDeclFunction": { "1": {}, "3": {} @@ -34,13 +39,16 @@ } }, "CExprInput": { - "6": { + "8": { "linkOutputPin": -1 } }, - "CExprType": { + "CStmtReturn": { "6": {} }, + "CExprType": { + "8": {} + }, "CGraphTransform": { "1": { "position": { @@ -71,6 +79,12 @@ "x": 4.0, "y": 0.0 } + }, + "6": { + "position": { + "x": 18.0, + "y": 7.0 + } } }, "CIdentifier": { @@ -79,6 +93,9 @@ }, "3": { "name": "Remove" + }, + "7": { + "name": "items" } }, "CParent": { @@ -87,32 +104,35 @@ 2, 3, 4, - 5 + 5, + 6, + 7 ], "1": [], "2": [ - 6, - 7, - 8 + 8, + 9, + 10 ], "3": [], "4": [], - "5": [] + "5": [], + "7": [] }, "CStmtIf": { "2": {} }, "CStmtOutput": { "1": 5, - "3": -1, + "3": 6, "4": -1, "5": 2 }, "CStmtOutputs": { "2": { "linkPins": [ - 7, - 8 + 9, + 10 ], "linkInputNodes": [ 4, @@ -123,7 +143,8 @@ "CStmtInput": { "2": 5, "4": 2, - "5": 1 + "5": 1, + "6": 3 } } } \ No newline at end of file diff --git a/Tests/AST/Filtering.spec.cpp b/Tests/AST/Filtering.spec.cpp index e39fa841..ff33f59b 100644 --- a/Tests/AST/Filtering.spec.cpp +++ b/Tests/AST/Filtering.spec.cpp @@ -40,15 +40,21 @@ go_bandit([]() { AST::Id id1; AST::Id id2; AST::Id id3; + AST::Id id4; + AST::Id id5; describe("AST.Filtering", [&]() { before_each([&]() { ast = {}; id1 = ast.Create(); id2 = ast.Create(); id3 = ast.Create(); + id4 = ast.Create(); + id5 = ast.Create(); ast.Add(id1); ast.Add(id2); ast.Add(id3); + ast.Add(id4); + ast.Add(id5); }); describe("ListAny/ListAll", [&]() { @@ -77,6 +83,17 @@ go_bandit([]() { AssertThat(type2Ids.Contains(id2), Is().True()); AssertThat(type2Ids.Contains(id3), Is().True()); }); + + it("Doesn't list removed ids", [&]() { + TAccess access{ast}; + ast.Destroy(id2); // Remove first in the pool + ast.Destroy(id3); // Remove last in the pool + ast.Destroy(id4); // Remove last in the pool + + TArray ids = AST::ListAll(access); + AssertThat(ids.Contains(AST::NoId), Is().False()); + AssertThat(ids.Size(), Equals(1)); + }); }); describe("RemoveIf", [&]() {