From 52025a6574c6b06024de56c92e5e3783687f6320 Mon Sep 17 00:00:00 2001 From: Ivan Kniazkov Date: Thu, 30 May 2024 12:26:27 +0300 Subject: [PATCH] Draft node extended --- .../org/cqfn/astranaut/core/DraftNode.java | 42 ++++++++++++++++--- .../cqfn/astranaut/core/DraftNodeTest.java | 34 +++++++++++++++ 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/cqfn/astranaut/core/DraftNode.java b/src/main/java/org/cqfn/astranaut/core/DraftNode.java index c3ccba3..3d3cea9 100644 --- a/src/main/java/org/cqfn/astranaut/core/DraftNode.java +++ b/src/main/java/org/cqfn/astranaut/core/DraftNode.java @@ -27,9 +27,12 @@ import java.text.StringCharacterIterator; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.Set; /** * Draft node for wrapping the results of third-party parsers @@ -121,16 +124,35 @@ public String toString() { */ @SuppressWarnings("PMD.ProhibitPublicStaticMethods") public static Node createByDescription(final String description) { + return DraftNode.createByDescription(description, null); + } + + /** + * Creates a tree from draft nodes based on description. + * Description format: A(B,C(...),...) where 'A' is the type name + * (it consists only of letters) followed by child nodes (in the same format) in parentheses + * separated by commas. + * @param description Description + * @param nodes Collection in which to place the nodes to be created, sorted by type name + * @return Root node of the tree created by description + */ + @SuppressWarnings("PMD.ProhibitPublicStaticMethods") + public static Node createByDescription( + final String description, + final Map> nodes) { final CharacterIterator iterator = new StringCharacterIterator(description); - return DraftNode.createByDescription(iterator); + return DraftNode.createByDescription(iterator, nodes); } /** * Creates a tree based on its description (recursive method). * @param iterator Iterator by description characters + * @param nodes Collection in which to place the nodes to be created, sorted by type name * @return Node of the tree with its children, created by description */ - private static Node createByDescription(final CharacterIterator iterator) { + private static Node createByDescription( + final CharacterIterator iterator, + final Map> nodes) { char symbol = iterator.current(); final Node result; final StringBuilder name = new StringBuilder(); @@ -146,9 +168,14 @@ private static Node createByDescription(final CharacterIterator iterator) { symbol = iterator.current(); } if (symbol == '(') { - builder.setChildrenList(DraftNode.parseChildrenList(iterator)); + builder.setChildrenList(DraftNode.parseChildrenList(iterator, nodes)); } result = builder.createNode(); + if (nodes != null) { + final Set set = + nodes.computeIfAbsent(result.getTypeName(), k -> new HashSet<>()); + set.add(result); + } } else { result = null; } @@ -181,15 +208,18 @@ private static String parseData(final CharacterIterator iterator) { /** * Parses children list from description. * @param iterator Iterator by description characters + * @param nodes Collection in which to place the nodes to be created, sorted by type name * @return Children list, created by description */ - private static List parseChildrenList(final CharacterIterator iterator) { + private static List parseChildrenList( + final CharacterIterator iterator, + final Map> nodes) { assert iterator.current() == '('; final List children = new LinkedList<>(); char next; do { iterator.next(); - final Node child = DraftNode.createByDescription(iterator); + final Node child = DraftNode.createByDescription(iterator, nodes); if (child != null) { children.add(child); } @@ -213,7 +243,7 @@ private static class TypeImpl implements Type { /** * Constructor. - * @param name The type name + * @param name The type name` */ TypeImpl(final String name) { this.name = name; diff --git a/src/test/java/org/cqfn/astranaut/core/DraftNodeTest.java b/src/test/java/org/cqfn/astranaut/core/DraftNodeTest.java index 84e067e..f3d5124 100644 --- a/src/test/java/org/cqfn/astranaut/core/DraftNodeTest.java +++ b/src/test/java/org/cqfn/astranaut/core/DraftNodeTest.java @@ -24,7 +24,11 @@ package org.cqfn.astranaut.core; import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -76,6 +80,36 @@ void constructorTest() { Assertions.assertEquals(serialized, ctor.createNode().toString()); } + /** + * Testing {@link DraftNode#createByDescription(String, Map)} method. + */ + @Test + void testExtendedDescriptorProcessor() { + final Map> nodes = new TreeMap<>(); + final Node root = DraftNode.createByDescription("X(A,A,B(C,D))", nodes); + Assertions.assertSame( + root, + nodes.computeIfAbsent( + "X", + s -> Collections.singleton(EmptyTree.INSTANCE) + ).iterator().next() + ); + Assertions.assertEquals( + 2, + nodes.computeIfAbsent( + "A", + s -> Collections.singleton(EmptyTree.INSTANCE) + ).size() + ); + Assertions.assertEquals( + 2, + nodes.computeIfAbsent( + "B", + s -> Collections.singleton(EmptyTree.INSTANCE) + ).iterator().next().getChildCount() + ); + } + /** * Testing {@link DraftNode#createByDescription(String)} and * {@link DraftNode#toString()} methods (testing of one case).