diff --git a/src/main/java/org/cqfn/astranaut/core/algorithms/DeepTraversal.java b/src/main/java/org/cqfn/astranaut/core/algorithms/DeepTraversal.java
new file mode 100644
index 0000000..f24d99f
--- /dev/null
+++ b/src/main/java/org/cqfn/astranaut/core/algorithms/DeepTraversal.java
@@ -0,0 +1,128 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 Ivan Kniazkov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.cqfn.astranaut.core.algorithms;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import org.cqfn.astranaut.core.Node;
+
+/**
+ * Performs a deep traversal of the syntax tree.
+ *
+ * @since 1.1.5
+ */
+public class DeepTraversal {
+ /**
+ * The root node of the tree being traversed.
+ */
+ private final Node root;
+
+ /**
+ * Constructor.
+ * @param root The root node of the tree being traversed
+ */
+ public DeepTraversal(final Node root) {
+ this.root = root;
+ }
+
+ /**
+ * Processes nodes starting from the root. Processes a node first.
+ * If the stopping criterion is not reached, recursively processes all children of it,
+ * starting from the first one. Once a node is found that satisfies the criterion,
+ * stops traversal.
+ * And yes, you can use this algorithm not only to find nodes, but also just to traverse
+ * the tree in the specific order.
+ * @param visitor Visitor that processes nodes
+ * @return Found node (optional)
+ */
+ public Optional findFirst(final Visitor visitor) {
+ return Optional.ofNullable(DeepTraversal.findFirst(this.root, visitor));
+ }
+
+ /**
+ * Processes nodes starting from the root.
+ * If a node matches the criterion, adds it to the set and does not check
+ * the children of this node, otherwise it does.
+ * @param visitor Visitor that processes nodes
+ * @return List of found nodes (can be empty, but not {@code null})
+ */
+ public List findAll(final Visitor visitor) {
+ final List list = new ArrayList<>(0);
+ DeepTraversal.findAll(this.root, visitor, list);
+ return list;
+ }
+
+ /**
+ * Recursive method that implements the "Find first starting from the root" algorithm.
+ * @param node Current node to be processed
+ * @param visitor Visitor that processes nodes
+ * @return Found node or {@code null} if no node is found
+ */
+ private static Node findFirst(final Node node, final Visitor visitor) {
+ Node result = null;
+ final boolean stop = visitor.process(node);
+ if (stop) {
+ result = node;
+ } else {
+ final int count = node.getChildCount();
+ for (int index = 0; index < count && result == null; index = index + 1) {
+ result = DeepTraversal.findFirst(node.getChild(index), visitor);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Recursive method that implements the "Find all starting from the root" algorithm.
+ * @param node Current node to be processed
+ * @param visitor Visitor that processes nodes
+ * @param list List of found nodes
+ */
+ private static void findAll(final Node node, final Visitor visitor, final List list) {
+ final boolean found = visitor.process(node);
+ if (found) {
+ list.add(node);
+ } else {
+ final int count = node.getChildCount();
+ for (int index = 0; index < count; index = index + 1) {
+ DeepTraversal.findAll(node.getChild(index), visitor, list);
+ }
+ }
+ }
+
+ /**
+ * Payload interface for the traversal algorithm.
+ *
+ * @since 1.1.5
+ */
+ public interface Visitor {
+ /**
+ * Processes a node.
+ * @param node Node
+ * @return Whether to stop traversal after node processing
+ */
+ boolean process(Node node);
+ }
+}
diff --git a/src/test/java/org/cqfn/astranaut/core/algorithms/DeepTraversalTest.java b/src/test/java/org/cqfn/astranaut/core/algorithms/DeepTraversalTest.java
new file mode 100644
index 0000000..3b76c48
--- /dev/null
+++ b/src/test/java/org/cqfn/astranaut/core/algorithms/DeepTraversalTest.java
@@ -0,0 +1,73 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 Ivan Kniazkov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.cqfn.astranaut.core.algorithms;
+
+import java.util.List;
+import java.util.Optional;
+import org.cqfn.astranaut.core.DraftNode;
+import org.cqfn.astranaut.core.Node;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Testing {@link DeepTraversal} class.
+ *
+ * @since 1.1.5
+ */
+class DeepTraversalTest {
+ @Test
+ void testFindFirst() {
+ final Node root = DraftNode.createByDescription("A(B,C,D(E<\"eee\">,F<\"fff\">)))");
+ final DeepTraversal traversal = new DeepTraversal(root);
+ final Optional node = traversal.findFirst(node1 -> !node1.getData().isEmpty());
+ Assertions.assertTrue(node.isPresent());
+ Assertions.assertEquals("E", node.get().getTypeName());
+ }
+
+ @Test
+ void testNotFoundFirst() {
+ final Node root = DraftNode.createByDescription("A(B,C,D)");
+ final DeepTraversal traversal = new DeepTraversal(root);
+ final Optional node = traversal.findFirst(node1 -> !node1.getData().isEmpty());
+ Assertions.assertFalse(node.isPresent());
+ }
+
+ @Test
+ void testFindAll() {
+ final Node root = DraftNode.createByDescription("A(B,C<\"ccc\">,D(E<\"eee\">)))");
+ final DeepTraversal traversal = new DeepTraversal(root);
+ final List list = traversal.findAll(node1 -> !node1.getData().isEmpty());
+ Assertions.assertNotNull(list);
+ Assertions.assertEquals(2, list.size());
+ }
+
+ @Test
+ void testFindNothing() {
+ final Node root = DraftNode.createByDescription("A(X,Y,Z)");
+ final DeepTraversal traversal = new DeepTraversal(root);
+ final List list = traversal.findAll(node1 -> !node1.getData().isEmpty());
+ Assertions.assertNotNull(list);
+ Assertions.assertTrue(list.isEmpty());
+ }
+}