From 5bc7c379f64ecfc3903ad9ccfcdb8ec4a83ef13c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20L=C3=BCpges?= Date: Tue, 24 Sep 2024 10:27:12 +0200 Subject: [PATCH] Fix Pretty Printer handling of Constant Groups --- .../PrettyPrinterGenerationVisitor.java | 10 ++- .../de/monticore/TestPrettyPrinters.mc4 | 17 +++- .../prettyprint/TestPrettyPrinterTest.java | 79 ++++++++++++++++--- 3 files changed, 94 insertions(+), 12 deletions(-) diff --git a/monticore-generator/src/main/java/de/monticore/codegen/prettyprint/PrettyPrinterGenerationVisitor.java b/monticore-generator/src/main/java/de/monticore/codegen/prettyprint/PrettyPrinterGenerationVisitor.java index 978f5e5052..39b4964b3f 100644 --- a/monticore-generator/src/main/java/de/monticore/codegen/prettyprint/PrettyPrinterGenerationVisitor.java +++ b/monticore-generator/src/main/java/de/monticore/codegen/prettyprint/PrettyPrinterGenerationVisitor.java @@ -34,6 +34,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; +import java.util.stream.Collectors; // Note: We can't use symbol-table information for multiplicities due to GrammarTransformer#removeNonTerminalSeparators, etc public class PrettyPrinterGenerationVisitor implements GrammarVisitor2 { @@ -482,7 +483,9 @@ public void visit(ASTConstantGroup node) { String humanName = node.isPresentUsageName() ? node.getUsageName() : node.getName(); String getter = getPlainGetterSymbol(humanName, Multiplicity.STANDARD); - boolean onlyOneConstant = node.getConstantList().size() == 1; + // The detection process of weather a constant groups AST attribute is an int or boolean + // must be able to handle u:[c:"a" | c:"b"], (op:["*"]|op:["/"]) and ASTRule shenanigans + boolean onlyOneConstant = !TransformationHelper.isConstGroupIterated(node.getSymbol()); if (onlyOneConstant) { // catch (op:["*"]|op:["/"]) and ASTRule shenanigans String nodeAttrName = node.isPresentUsageName() ? node.getUsageName() : node.getName(); @@ -501,6 +504,11 @@ public void visit(ASTConstantGroup node) { this.failureMessage = "Unable to find good Constant name for " + getter + " and value " + constant.getHumanName(); } + if (onlyOneConstant) { + // in case of u:[c:"a" | c:"b"], limit the size of the used constants to 1 + constants = constants.stream().limit(1).collect(Collectors.toSet()); + } + PPGuardComponent component = PPGuardComponent.forCG(getter, constants); AltData altData; diff --git a/monticore-test/01.experiments/prettyPrinters/src/main/grammars/de/monticore/TestPrettyPrinters.mc4 b/monticore-test/01.experiments/prettyPrinters/src/main/grammars/de/monticore/TestPrettyPrinters.mc4 index ae1161fbbb..311fc06dd1 100644 --- a/monticore-test/01.experiments/prettyPrinters/src/main/grammars/de/monticore/TestPrettyPrinters.mc4 +++ b/monticore-test/01.experiments/prettyPrinters/src/main/grammars/de/monticore/TestPrettyPrinters.mc4 @@ -38,9 +38,13 @@ grammar TestPrettyPrinters extends de.monticore.literals.MCCommonLiterals { CPCGSingle = ["cg1"] ; CPCGSingleU1 = [u:"cg1"] ; CPCGSingleU2 = u:["cg1"] ; + CPCGSingleU3 = cg:[ a:"cg1" | a:"cg2"] ; // Note: Only the first constant is generated for the parser + CPCGSingleU4 = cg:["a" | a:"cg1" | a:"cg2"] ; // Note: Only the first constant is generated CPCGMulti1 = cg:["cg1" | "cg2"] ; CPCGMulti2 = cg:[u:"cg1" | v:"cg2"] ; + CPCGMulti3 = cg:[a:"cg1" | a:"cg2" | b: "b"] ; + CPCGMulti4 = (op:["*"] | op:["/"]); // special constand handling MultiCGPlus = (["a"]| ["b"] | ["c"])+ D?; MultiCGStar = (["a"] | ["b"] | ["c"])* D?; @@ -55,6 +59,18 @@ grammar TestPrettyPrinters extends de.monticore.literals.MCCommonLiterals { // Duplicate NonTerminal usagenames DuplicateUsageName = Name ("=" value:Name |"=" value:String)? ; + DuplicateUsageName2 = a:Name a:Name; + DuplicateUsageName3 = a:Name (a:Name)*; + + // Duplicate Token-NonTerminal usagenames + token MyToken = "MYTOKEN"; + DuplicateTokenUsageName = MyToken ("=" value:MyToken |"+=" value:MyToken)? ; + DuplicateTokenUsageName2 = a:MyToken a:MyToken; + DuplicateTokenUsageName3 = a:MyToken (a:MyToken)*; + + // Duplicate Terminal with usagenames + DuplicateTermUsageName2 = a:"a" a:"a"; + DuplicateTermUsageName3 = a:"a" (a:"a")*; CPAstList = (A | B | C)*; // Unsupported astrule CPAstList = a:A max=1; // Unsupported @@ -64,7 +80,6 @@ grammar TestPrettyPrinters extends de.monticore.literals.MCCommonLiterals { CPCGSup = complete:["(c)"]; CPCGUnsupName = ending:[".dot"|".jpg"]; // Unsupported due to constants name - CPCGUnsuppDup = (op:["*"]|op:["/"]); // Unsupported CPListInDList = B (B A*)*; CPListInPList = B (B+ A*)*; diff --git a/monticore-test/01.experiments/prettyPrinters/src/test/java/de/monticore/prettyprint/TestPrettyPrinterTest.java b/monticore-test/01.experiments/prettyPrinters/src/test/java/de/monticore/prettyprint/TestPrettyPrinterTest.java index d2ad5b6e03..0e30b1b921 100644 --- a/monticore-test/01.experiments/prettyPrinters/src/test/java/de/monticore/prettyprint/TestPrettyPrinterTest.java +++ b/monticore-test/01.experiments/prettyPrinters/src/test/java/de/monticore/prettyprint/TestPrettyPrinterTest.java @@ -201,6 +201,19 @@ public void testCPCGSingleU2() throws IOException { testPP("cg1", TestPrettyPrintersMill.parser()::parse_StringCPCGSingleU2); } + @Test + public void testCPCGSingleU3() throws IOException { + testPP("cg1", TestPrettyPrintersMill.parser()::parse_StringCPCGSingleU3); +// testPP("cg2", TestPrettyPrintersMill.parser()::parse_StringCPCGSingleU3); // Note: Only the first constant is generated for the parser + } + + @Test + public void testCPCGSingleU4() throws IOException { + testPP("a", TestPrettyPrintersMill.parser()::parse_StringCPCGSingleU4); +// testPP("cg1", TestPrettyPrintersMill.parser()::parse_StringCPCGSingleU4); // Note: Only the first constant is generated for the parser +// testPP("cg2", TestPrettyPrintersMill.parser()::parse_StringCPCGSingleU4); // Note: Only the first constant is generated for the parser + } + @Test public void testCPCGMulti1() throws IOException { testPP("cg1", TestPrettyPrintersMill.parser()::parse_StringCPCGMulti1); @@ -213,6 +226,19 @@ public void testCPCGMulti2() throws IOException { testPP("cg2", TestPrettyPrintersMill.parser()::parse_StringCPCGMulti2); } + @Test + public void testCPCGMulti3() throws IOException { + testPP("cg1", TestPrettyPrintersMill.parser()::parse_StringCPCGMulti3); + testPP("cg2", TestPrettyPrintersMill.parser()::parse_StringCPCGMulti3); + testPP("b", TestPrettyPrintersMill.parser()::parse_StringCPCGMulti3); + } + + @Test + public void testCPCGMulti4() throws IOException { + testPP("*", TestPrettyPrintersMill.parser()::parse_StringCPCGMulti4); + testPP("/", TestPrettyPrintersMill.parser()::parse_StringCPCGMulti4); + } + @Test public void testCGs() throws IOException { for (String input : Arrays.asList("a", "b", "c", @@ -261,6 +287,49 @@ public void testDuplicateUsageName() throws IOException { testPP("n1 = s1\n", TestPrettyPrintersMill.parser()::parse_StringDuplicateUsageName); } + @Test + public void testDuplicateUsageName2() throws IOException { + testPP("n1 n2", TestPrettyPrintersMill.parser()::parse_StringDuplicateUsageName2); + } + + @Test + public void testDuplicateUsageName3() throws IOException { + testPP("n1", TestPrettyPrintersMill.parser()::parse_StringDuplicateUsageName3); + testPP("n1 n2", TestPrettyPrintersMill.parser()::parse_StringDuplicateUsageName3); + testPP("n1 n2 n3", TestPrettyPrintersMill.parser()::parse_StringDuplicateUsageName3); + } + + @Test + public void testDuplicateTokenUsageName() throws IOException { + testPP("MYTOKEN", TestPrettyPrintersMill.parser()::parse_StringDuplicateTokenUsageName); + testPP("MYTOKEN = MYTOKEN", TestPrettyPrintersMill.parser()::parse_StringDuplicateTokenUsageName); + testPP("MYTOKEN += MYTOKEN", TestPrettyPrintersMill.parser()::parse_StringDuplicateTokenUsageName); + } + + @Test + public void testDuplicateTokenUsageName2() throws IOException { + testPP("MYTOKEN MYTOKEN", TestPrettyPrintersMill.parser()::parse_StringDuplicateTokenUsageName2); + } + + @Test + public void testDuplicateTokenUsageName3() throws IOException { + testPP("MYTOKEN", TestPrettyPrintersMill.parser()::parse_StringDuplicateTokenUsageName3); + testPP("MYTOKEN MYTOKEN", TestPrettyPrintersMill.parser()::parse_StringDuplicateTokenUsageName3); + testPP("MYTOKEN MYTOKEN MYTOKEN", TestPrettyPrintersMill.parser()::parse_StringDuplicateTokenUsageName3); + } + + @Test + public void testDuplicateTermUsageName2() throws IOException { + testPP("a a", TestPrettyPrintersMill.parser()::parse_StringDuplicateTermUsageName2); + } + + @Test + public void testDuplicateTermUsageName3() throws IOException { + testPP("a", TestPrettyPrintersMill.parser()::parse_StringDuplicateTermUsageName3); + testPP("a a", TestPrettyPrintersMill.parser()::parse_StringDuplicateTermUsageName3); + testPP("a a a", TestPrettyPrintersMill.parser()::parse_StringDuplicateTermUsageName3); + } + @Test @Ignore public void testCPAstList() throws IOException { @@ -292,16 +361,6 @@ public void testCPCGUnsupName() throws IOException { } } - @Test - public void testCPCGUnsuppDup() throws IOException { - try { - testPP("*", TestPrettyPrintersMill.parser()::parse_StringCPCGUnsuppDup); - Assert.fail(); - } catch (IllegalStateException expected) { - Assert.assertEquals("Unable to handle ConstantGroup with size of 1, but multiple elements named op present", expected.getMessage()); - } - } - @Test public void testCPListInDList() throws IOException { testPP("B", TestPrettyPrintersMill.parser()::parse_StringCPListInDList);