diff --git a/src/main/java/org/cqfn/astranaut/codegen/java/MatcherClassFiller.java b/src/main/java/org/cqfn/astranaut/codegen/java/MatcherClassFiller.java index dcfda3f5..7de02314 100644 --- a/src/main/java/org/cqfn/astranaut/codegen/java/MatcherClassFiller.java +++ b/src/main/java/org/cqfn/astranaut/codegen/java/MatcherClassFiller.java @@ -499,6 +499,33 @@ private String formatHoleExtractor(final Hole hole, final int index) { ) ); result = String.join("\n", code); + } else if (hole.getAttribute() == HoleAttribute.TYPED) { + this.alist = true; + final String capacity; + if (index == 0) { + capacity = "count"; + } else { + capacity = String.format("count - %d", index); + } + final List code = Arrays.asList( + "final int count = node.getChildCount();", + String.format("final List list = new ArrayList<>(%s);", capacity), + String.format( + "for (int index = %d; index < count; index = index + 1) {", + index + ), + "final Node child = node.getChild(index);", + String.format("if (\"%s\".equals(child.getTypeName())) {", hole.getType()), + "list.add(child);", + "}", + "}", + String.format( + "children.put(%s.%s, list);\n", + this.klass.getName(), + destination + ) + ); + result = String.join("\n", code); } else { this.collections = true; final String srclbl = this.children.getLabel(); diff --git a/src/main/java/org/cqfn/astranaut/interpreter/Matcher.java b/src/main/java/org/cqfn/astranaut/interpreter/Matcher.java index d64adf79..09b70ffb 100644 --- a/src/main/java/org/cqfn/astranaut/interpreter/Matcher.java +++ b/src/main/java/org/cqfn/astranaut/interpreter/Matcher.java @@ -172,10 +172,14 @@ private static List checkAndExtractChildrenFromHole( case TYPED: final int number = node.getChildCount(); list = new ArrayList<>(number - index); - for (int position = index; position < number; position += 1) { - final Node child = node.getChild(position); - if (hole.getType().equals(child.getTypeName())) { - list.add(child); + int position = index; + Node child = node.getChild(position); + final String type = hole.getType(); + while (type.equals(child.getTypeName()) && position < number) { + list.add(child); + position += 1; + if (position != number) { + child = node.getChild(position); } } break; diff --git a/src/test/java/org/cqfn/astranaut/codegen/java/MatcherGeneratorTest.java b/src/test/java/org/cqfn/astranaut/codegen/java/MatcherGeneratorTest.java index 39998507..d7031c05 100644 --- a/src/test/java/org/cqfn/astranaut/codegen/java/MatcherGeneratorTest.java +++ b/src/test/java/org/cqfn/astranaut/codegen/java/MatcherGeneratorTest.java @@ -43,6 +43,7 @@ * * @since 0.1.5 */ +@SuppressWarnings("PMD.TooManyMethods") class MatcherGeneratorTest { /** * The folder with test resources. @@ -130,10 +131,22 @@ void testLargeNumberOfChildNodes() { Assertions.assertTrue(result > 0); } + /** + * Test case: extract unknown number of children of the particular type. + */ + @Test + void testUnknownNumberOfChildNodesWithSameType() { + final int result = this.testing( + "AAA(BBB, CCC#1, #2)", + "matcher_generator_extract_particular_type.txt" + ); + Assertions.assertTrue(result > 0); + } + /** * Performs a test. * @param code Source code of descriptor - * @param filename The name of file that contains the expected result + * @param filename The name of file that contaAins the expected result * @return Expected generated classes number */ private int testing(final String code, final String filename) { diff --git a/src/test/java/org/cqfn/astranaut/interpreter/InterpreterTest.java b/src/test/java/org/cqfn/astranaut/interpreter/InterpreterTest.java index ed344908..36c3c564 100644 --- a/src/test/java/org/cqfn/astranaut/interpreter/InterpreterTest.java +++ b/src/test/java/org/cqfn/astranaut/interpreter/InterpreterTest.java @@ -83,6 +83,16 @@ void typedHoleTest(@TempDir final Path temp) { Assertions.assertTrue(result); } + /** + * Testing holes with a node type, more complex case. + * @param temp A temporary directory + */ + @Test + void typedHoleComplexTest(@TempDir final Path temp) { + final boolean result = this.test("test_4", temp); + Assertions.assertTrue(result); + } + /** * Testing running interpreter without a destination specified. */ diff --git a/src/test/resources/codegen/java/matcher_generator_extract_particular_type.txt b/src/test/resources/codegen/java/matcher_generator_extract_particular_type.txt new file mode 100644 index 00000000..e16a8786 --- /dev/null +++ b/src/test/resources/codegen/java/matcher_generator_extract_particular_type.txt @@ -0,0 +1,161 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2022 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.uast; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import org.cqfn.astranaut.core.Matcher; +import org.cqfn.astranaut.core.Node; + +/** + * Checks if the node matches some structure, and extracts the data and children. + * + * @since 1.0 + */ +public final class Matcher0 implements Matcher { + /** + * The instance. + */ + public static final Matcher INSTANCE = new Matcher0(); + + /** + * Expected node type. + */ + private static final String EXPECTED_TYPE = "AAA"; + + /** + * The number of the first hole. + */ + private static final int FIRST_HOLE_ID = 1; + + /** + * The number of the second hole. + */ + private static final int SECOND_HOLE_ID = 2; + + /** + * The index of the first child. + */ + private static final int FIRST_CHILD_ID = 2; + + /** + * Constructor. + */ + private Matcher0() { + } + + @Override + public boolean match(final Node node, + final Map> children, + final Map data) { + final boolean result = node.belongsToGroup(Matcher0.EXPECTED_TYPE) + && Matcher1.INSTANCE.match(node.getChild(0), children, data); + if (result) { + final int count = node.getChildCount(); + final List list = new ArrayList<>(count - 1); + for (int index = 1; index < count; index = index + 1) { + final Node child = node.getChild(index); + if ("CCC".equals(child.getTypeName())) { + list.add(child); + } + } + children.put(Matcher0.FIRST_HOLE_ID, list); + children.put( + Matcher0.SECOND_HOLE_ID, + Collections.singletonList(node.getChild(Matcher0.FIRST_CHILD_ID)) + ); + } + return result; + } +} + +/* + * The MIT License (MIT) + * + * Copyright (c) 2022 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.uast; + +import java.util.List; +import java.util.Map; +import org.cqfn.astranaut.core.Matcher; +import org.cqfn.astranaut.core.Node; + +/** + * Checks if the node matches some structure, and extracts the data and children. + * + * @since 1.0 + */ +public final class Matcher1 implements Matcher { + /** + * The instance. + */ + public static final Matcher INSTANCE = new Matcher1(); + + /** + * Expected node type. + */ + private static final String EXPECTED_TYPE = "BBB"; + + /** + * Expected number of child nodes. + */ + private static final int EXPECTED_COUNT = 0; + + /** + * Constructor. + */ + private Matcher1() { + } + + @Override + public boolean match(final Node node, + final Map> children, + final Map data) { + return node.belongsToGroup(Matcher1.EXPECTED_TYPE) + && node.getChildCount() == Matcher1.EXPECTED_COUNT; + } +} diff --git a/src/test/resources/interpreter/test_4_result.json b/src/test/resources/interpreter/test_4_result.json new file mode 100644 index 00000000..0debce44 --- /dev/null +++ b/src/test/resources/interpreter/test_4_result.json @@ -0,0 +1,40 @@ +{ + "root": { + "type": "F", + "children": [ + { + "type": "BB", + "children": [ + { + "type": "B", + "data": "1" + }, + { + "type": "B", + "data": "2" + } + ] + }, + { + "type": "B", + "data": "0" + }, + { + "type": "C" + }, + { + "type": "DD", + "children": [ + { + "type": "D", + "data": "1" + }, + { + "type": "D", + "data": "2" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/src/test/resources/interpreter/test_4_rules.dsl b/src/test/resources/interpreter/test_4_rules.dsl new file mode 100644 index 00000000..db634f42 --- /dev/null +++ b/src/test/resources/interpreter/test_4_rules.dsl @@ -0,0 +1 @@ +A(B#1, C, B<#2>, D#3) -> F(BB(#1), B<#2>, C, DD(#3)); diff --git a/src/test/resources/interpreter/test_4_source_tree.json b/src/test/resources/interpreter/test_4_source_tree.json new file mode 100644 index 00000000..9571eabd --- /dev/null +++ b/src/test/resources/interpreter/test_4_source_tree.json @@ -0,0 +1,30 @@ +{ + "root" : { + "type" : "A", + "children": [ + { + "type": "B", + "data": "1" + }, + { + "type": "B", + "data": "2" + }, + { + "type": "C" + }, + { + "type": "B", + "data": "0" + }, + { + "type": "D", + "data": "1" + }, + { + "type": "D", + "data": "2" + } + ] + } +} \ No newline at end of file