From 863aa25186e3ffedf47d73ba05b9a9eaa66582d3 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Wed, 19 Aug 2026 20:53:35 +0200 Subject: [PATCH] XML: keep HTML void element support from changing how malformed XML recovers The `element` rule was left-factored when void element support was added in #7906, so strict XML and HTML-like sources began sharing one shape. The shape of the rule, not just which alternative matches, determines the resynchronization sets ANTLR's error recovery uses, so the change altered recovery for XML too -- despite the void element predicate itself being gated on `htmlMode`. `XMLLexer` ends a `STRING` at the first embedded quote, because an attribute value may contain neither `"` nor `<`. An attribute whose value carries an unescaped quote -- common in embedded expressions such as Azure API Management policies -- therefore re-lexes the rest of the value as further attributes. Under the new shape those recovered into an `attribute` with a synthesized `=`, which the printer cannot distinguish from a real one and wrote back into the value: - list += "AAA,"; + list += "AAA=,"; One level of nesting deeper the same input instead abandoned the rule with a null `EQUALS`, and `visitAttribute` threw a `NullPointerException`. Give strict XML back the two plain alternatives it had before void element support existed, gated by `isHtmlMode()`, and reject attributes and elements that error recovery left incomplete or invented so such input falls back to a `ParseError` preserving the original text, as #7555 established for other malformed input. The C# grammar sources are left as they are, matching #7906, which also did not regenerate them. --- rewrite-xml/src/main/antlr/XMLParser.g4 | 10 +- .../xml/internal/XmlParserVisitor.java | 31 + .../xml/internal/grammar/XMLParser.interp | 2 +- .../xml/internal/grammar/XMLParser.java | 557 +++++++++++------- .../xml/internal/grammar/XMLParserBase.java | 10 + .../org/openrewrite/xml/XmlParserTest.java | 62 ++ 6 files changed, 447 insertions(+), 225 deletions(-) diff --git a/rewrite-xml/src/main/antlr/XMLParser.g4 b/rewrite-xml/src/main/antlr/XMLParser.g4 index 2477fc33025..69fb3fa50eb 100755 --- a/rewrite-xml/src/main/antlr/XMLParser.g4 +++ b/rewrite-xml/src/main/antlr/XMLParser.g4 @@ -81,8 +81,16 @@ content : (element | reference | processinginstruction | CDATA | COMMENT | jspscriptlet | jspexpression | jspdeclaration | jspcomment | chardata) ; +// Strict XML and HTML-like sources get separate alternatives rather than one shared, left-factored shape. +// The shape of this rule determines the resynchronization sets ANTLR's error recovery uses, so folding the +// two together would let HTML void element support change how malformed *XML* recovers -- e.g. an attribute +// whose value contains an unescaped quote could recover with a synthesized '=' that the printer then emits +// into the source. Keeping the strict-XML alternatives exactly as they were before void element support +// existed is what makes "HTML support does not affect XML parsing" true of recovery and not just of matching. element - : OPEN name=Name attribute* + : {!isHtmlMode()}? OPEN name=Name attribute* CLOSE content* OPEN '/' Name CLOSE + | {!isHtmlMode()}? OPEN name=Name attribute* '/>' + | {isHtmlMode()}? OPEN name=Name attribute* ( '/>' | CLOSE ( {isVoidElement($name.text)}? voidClose // HTML void element, e.g.
with no closing tag diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/internal/XmlParserVisitor.java b/rewrite-xml/src/main/java/org/openrewrite/xml/internal/XmlParserVisitor.java index c8d8fe323a7..38959066d2a 100755 --- a/rewrite-xml/src/main/java/org/openrewrite/xml/internal/XmlParserVisitor.java +++ b/rewrite-xml/src/main/java/org/openrewrite/xml/internal/XmlParserVisitor.java @@ -328,6 +328,9 @@ public Xml visitJspcomment(XMLParser.JspcommentContext ctx) { @Override public Xml.Tag visitElement(XMLParser.ElementContext ctx) { + if (ctx != null && ctx.Name(0) == null) { + throw malformed(ctx.getStart(), "an element is missing its name"); + } return convert(ctx, (c, prefix) -> { String name = convert(ctx.Name(0), (n, p) -> n.getText()); @@ -389,6 +392,7 @@ public Xml.Tag visitElement(XMLParser.ElementContext ctx) { @Override public Xml.Attribute visitAttribute(XMLParser.AttributeContext ctx) { + requireWellFormed(ctx); return convert(ctx, (c, prefix) -> { Xml.Ident key = convert(c.Name(), (t, p) -> new Xml.Ident(randomId(), p, Markers.EMPTY, t.getText())); @@ -407,6 +411,33 @@ public Xml.Attribute visitAttribute(XMLParser.AttributeContext ctx) { }); } + /** + * An attribute is only reachable here with a part missing, or with a part ANTLR invented, when error recovery + * built it out of tokens that were never an attribute in the source. Reading such a context yields a tree that no + * longer represents the source: a synthesized {@code =} is indistinguishable from a real one once built, and the + * printer then emits it back into the attribute value. + */ + private void requireWellFormed(XMLParser.@Nullable AttributeContext ctx) { + if (ctx != null && (ctx.Name() == null || ctx.STRING() == null || isSynthesized(ctx.EQUALS()))) { + throw malformed(ctx.getStart(), "an attribute value contains an unescaped '\"' or '<'"); + } + } + + private static boolean isSynthesized(@Nullable TerminalNode node) { + return node == null || node.getSymbol().getTokenIndex() < 0; + } + + /** + * Rejects input that is not well-formed XML, so the caller falls back to a + * {@link org.openrewrite.tree.ParseError} that preserves the original text rather than building an LST out of + * whatever ANTLR error recovery happened to leave behind. + */ + private IllegalStateException malformed(Token start, String detail) { + return new IllegalStateException(String.format( + "%s is not well-formed XML: %s at line %d:%d.", + path, detail, start.getLine(), start.getCharPositionInLine())); + } + @Override public Xml.DocTypeDecl visitDoctypedecl(XMLParser.DoctypedeclContext ctx) { return convert(ctx, (c, prefix) -> { diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/internal/grammar/XMLParser.interp b/rewrite-xml/src/main/java/org/openrewrite/xml/internal/grammar/XMLParser.interp index 3ed6ca925b9..06db096714e 100755 --- a/rewrite-xml/src/main/java/org/openrewrite/xml/internal/grammar/XMLParser.interp +++ b/rewrite-xml/src/main/java/org/openrewrite/xml/internal/grammar/XMLParser.interp @@ -113,4 +113,4 @@ chardata atn: -[4, 1, 42, 212, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 1, 0, 3, 0, 44, 8, 0, 1, 0, 1, 0, 3, 0, 48, 8, 0, 1, 1, 3, 1, 51, 8, 1, 1, 1, 5, 1, 54, 8, 1, 10, 1, 12, 1, 57, 9, 1, 1, 1, 5, 1, 60, 8, 1, 10, 1, 12, 1, 63, 9, 1, 1, 2, 1, 2, 5, 2, 67, 8, 2, 10, 2, 12, 2, 70, 9, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 79, 8, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 5, 4, 86, 8, 4, 10, 4, 12, 4, 89, 9, 4, 1, 4, 1, 4, 1, 4, 1, 4, 3, 4, 95, 8, 4, 1, 4, 1, 4, 1, 5, 1, 5, 5, 5, 101, 8, 5, 10, 5, 12, 5, 104, 9, 5, 1, 6, 1, 6, 5, 6, 108, 8, 6, 10, 6, 12, 6, 111, 9, 6, 1, 6, 5, 6, 114, 8, 6, 10, 6, 12, 6, 117, 9, 6, 1, 6, 5, 6, 120, 8, 6, 10, 6, 12, 6, 123, 9, 6, 1, 6, 1, 6, 1, 6, 3, 6, 128, 8, 6, 1, 7, 1, 7, 1, 8, 3, 8, 133, 8, 8, 1, 9, 1, 9, 5, 9, 137, 8, 9, 10, 9, 12, 9, 140, 9, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 154, 8, 10, 1, 11, 1, 11, 1, 11, 5, 11, 159, 8, 11, 10, 11, 12, 11, 162, 9, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 169, 8, 11, 10, 11, 12, 11, 172, 9, 11, 1, 11, 1, 11, 1, 11, 1, 11, 3, 11, 178, 8, 11, 3, 11, 180, 8, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 188, 8, 13, 10, 13, 12, 13, 191, 9, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 0, 0, 21, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 0, 3, 1, 0, 28, 29, 1, 0, 5, 6, 3, 0, 7, 7, 9, 9, 18, 18, 225, 0, 43, 1, 0, 0, 0, 2, 50, 1, 0, 0, 0, 4, 64, 1, 0, 0, 0, 6, 78, 1, 0, 0, 0, 8, 80, 1, 0, 0, 0, 10, 102, 1, 0, 0, 0, 12, 127, 1, 0, 0, 0, 14, 129, 1, 0, 0, 0, 16, 132, 1, 0, 0, 0, 18, 134, 1, 0, 0, 0, 20, 153, 1, 0, 0, 0, 22, 155, 1, 0, 0, 0, 24, 181, 1, 0, 0, 0, 26, 183, 1, 0, 0, 0, 28, 195, 1, 0, 0, 0, 30, 197, 1, 0, 0, 0, 32, 199, 1, 0, 0, 0, 34, 201, 1, 0, 0, 0, 36, 203, 1, 0, 0, 0, 38, 205, 1, 0, 0, 0, 40, 209, 1, 0, 0, 0, 42, 44, 5, 8, 0, 0, 43, 42, 1, 0, 0, 0, 43, 44, 1, 0, 0, 0, 44, 45, 1, 0, 0, 0, 45, 47, 3, 2, 1, 0, 46, 48, 3, 22, 11, 0, 47, 46, 1, 0, 0, 0, 47, 48, 1, 0, 0, 0, 48, 1, 1, 0, 0, 0, 49, 51, 3, 4, 2, 0, 50, 49, 1, 0, 0, 0, 50, 51, 1, 0, 0, 0, 51, 55, 1, 0, 0, 0, 52, 54, 3, 6, 3, 0, 53, 52, 1, 0, 0, 0, 54, 57, 1, 0, 0, 0, 55, 53, 1, 0, 0, 0, 55, 56, 1, 0, 0, 0, 56, 61, 1, 0, 0, 0, 57, 55, 1, 0, 0, 0, 58, 60, 3, 26, 13, 0, 59, 58, 1, 0, 0, 0, 60, 63, 1, 0, 0, 0, 61, 59, 1, 0, 0, 0, 61, 62, 1, 0, 0, 0, 62, 3, 1, 0, 0, 0, 63, 61, 1, 0, 0, 0, 64, 68, 5, 10, 0, 0, 65, 67, 3, 38, 19, 0, 66, 65, 1, 0, 0, 0, 67, 70, 1, 0, 0, 0, 68, 66, 1, 0, 0, 0, 68, 69, 1, 0, 0, 0, 69, 71, 1, 0, 0, 0, 70, 68, 1, 0, 0, 0, 71, 72, 5, 34, 0, 0, 72, 5, 1, 0, 0, 0, 73, 79, 5, 2, 0, 0, 74, 79, 3, 8, 4, 0, 75, 79, 3, 18, 9, 0, 76, 79, 3, 32, 16, 0, 77, 79, 3, 34, 17, 0, 78, 73, 1, 0, 0, 0, 78, 74, 1, 0, 0, 0, 78, 75, 1, 0, 0, 0, 78, 76, 1, 0, 0, 0, 78, 77, 1, 0, 0, 0, 79, 7, 1, 0, 0, 0, 80, 81, 5, 13, 0, 0, 81, 82, 5, 22, 0, 0, 82, 83, 5, 42, 0, 0, 83, 87, 3, 16, 8, 0, 84, 86, 5, 41, 0, 0, 85, 84, 1, 0, 0, 0, 86, 89, 1, 0, 0, 0, 87, 85, 1, 0, 0, 0, 87, 88, 1, 0, 0, 0, 88, 94, 1, 0, 0, 0, 89, 87, 1, 0, 0, 0, 90, 91, 5, 20, 0, 0, 91, 92, 3, 10, 5, 0, 92, 93, 5, 23, 0, 0, 93, 95, 1, 0, 0, 0, 94, 90, 1, 0, 0, 0, 94, 95, 1, 0, 0, 0, 95, 96, 1, 0, 0, 0, 96, 97, 5, 19, 0, 0, 97, 9, 1, 0, 0, 0, 98, 101, 3, 12, 6, 0, 99, 101, 3, 14, 7, 0, 100, 98, 1, 0, 0, 0, 100, 99, 1, 0, 0, 0, 101, 104, 1, 0, 0, 0, 102, 100, 1, 0, 0, 0, 102, 103, 1, 0, 0, 0, 103, 11, 1, 0, 0, 0, 104, 102, 1, 0, 0, 0, 105, 109, 5, 24, 0, 0, 106, 108, 7, 0, 0, 0, 107, 106, 1, 0, 0, 0, 108, 111, 1, 0, 0, 0, 109, 107, 1, 0, 0, 0, 109, 110, 1, 0, 0, 0, 110, 115, 1, 0, 0, 0, 111, 109, 1, 0, 0, 0, 112, 114, 5, 30, 0, 0, 113, 112, 1, 0, 0, 0, 114, 117, 1, 0, 0, 0, 115, 113, 1, 0, 0, 0, 115, 116, 1, 0, 0, 0, 116, 121, 1, 0, 0, 0, 117, 115, 1, 0, 0, 0, 118, 120, 7, 0, 0, 0, 119, 118, 1, 0, 0, 0, 120, 123, 1, 0, 0, 0, 121, 119, 1, 0, 0, 0, 121, 122, 1, 0, 0, 0, 122, 124, 1, 0, 0, 0, 123, 121, 1, 0, 0, 0, 124, 128, 5, 26, 0, 0, 125, 128, 3, 18, 9, 0, 126, 128, 5, 2, 0, 0, 127, 105, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 127, 126, 1, 0, 0, 0, 128, 13, 1, 0, 0, 0, 129, 130, 5, 4, 0, 0, 130, 15, 1, 0, 0, 0, 131, 133, 5, 42, 0, 0, 132, 131, 1, 0, 0, 0, 132, 133, 1, 0, 0, 0, 133, 17, 1, 0, 0, 0, 134, 138, 5, 12, 0, 0, 135, 137, 5, 32, 0, 0, 136, 135, 1, 0, 0, 0, 137, 140, 1, 0, 0, 0, 138, 136, 1, 0, 0, 0, 138, 139, 1, 0, 0, 0, 139, 141, 1, 0, 0, 0, 140, 138, 1, 0, 0, 0, 141, 142, 5, 34, 0, 0, 142, 19, 1, 0, 0, 0, 143, 154, 3, 22, 11, 0, 144, 154, 3, 36, 18, 0, 145, 154, 3, 18, 9, 0, 146, 154, 5, 3, 0, 0, 147, 154, 5, 2, 0, 0, 148, 154, 3, 28, 14, 0, 149, 154, 3, 30, 15, 0, 150, 154, 3, 32, 16, 0, 151, 154, 3, 34, 17, 0, 152, 154, 3, 40, 20, 0, 153, 143, 1, 0, 0, 0, 153, 144, 1, 0, 0, 0, 153, 145, 1, 0, 0, 0, 153, 146, 1, 0, 0, 0, 153, 147, 1, 0, 0, 0, 153, 148, 1, 0, 0, 0, 153, 149, 1, 0, 0, 0, 153, 150, 1, 0, 0, 0, 153, 151, 1, 0, 0, 0, 153, 152, 1, 0, 0, 0, 154, 21, 1, 0, 0, 0, 155, 156, 5, 11, 0, 0, 156, 160, 5, 42, 0, 0, 157, 159, 3, 38, 19, 0, 158, 157, 1, 0, 0, 0, 159, 162, 1, 0, 0, 0, 160, 158, 1, 0, 0, 0, 160, 161, 1, 0, 0, 0, 161, 179, 1, 0, 0, 0, 162, 160, 1, 0, 0, 0, 163, 180, 5, 35, 0, 0, 164, 177, 5, 33, 0, 0, 165, 166, 4, 11, 0, 1, 166, 178, 3, 24, 12, 0, 167, 169, 3, 20, 10, 0, 168, 167, 1, 0, 0, 0, 169, 172, 1, 0, 0, 0, 170, 168, 1, 0, 0, 0, 170, 171, 1, 0, 0, 0, 171, 173, 1, 0, 0, 0, 172, 170, 1, 0, 0, 0, 173, 174, 5, 11, 0, 0, 174, 175, 5, 39, 0, 0, 175, 176, 5, 42, 0, 0, 176, 178, 5, 33, 0, 0, 177, 165, 1, 0, 0, 0, 177, 170, 1, 0, 0, 0, 178, 180, 1, 0, 0, 0, 179, 163, 1, 0, 0, 0, 179, 164, 1, 0, 0, 0, 180, 23, 1, 0, 0, 0, 181, 182, 1, 0, 0, 0, 182, 25, 1, 0, 0, 0, 183, 184, 5, 11, 0, 0, 184, 185, 5, 37, 0, 0, 185, 189, 5, 42, 0, 0, 186, 188, 3, 38, 19, 0, 187, 186, 1, 0, 0, 0, 188, 191, 1, 0, 0, 0, 189, 187, 1, 0, 0, 0, 189, 190, 1, 0, 0, 0, 190, 192, 1, 0, 0, 0, 191, 189, 1, 0, 0, 0, 192, 193, 5, 38, 0, 0, 193, 194, 5, 33, 0, 0, 194, 27, 1, 0, 0, 0, 195, 196, 5, 17, 0, 0, 196, 29, 1, 0, 0, 0, 197, 198, 5, 16, 0, 0, 198, 31, 1, 0, 0, 0, 199, 200, 5, 15, 0, 0, 200, 33, 1, 0, 0, 0, 201, 202, 5, 14, 0, 0, 202, 35, 1, 0, 0, 0, 203, 204, 7, 1, 0, 0, 204, 37, 1, 0, 0, 0, 205, 206, 5, 42, 0, 0, 206, 207, 5, 40, 0, 0, 207, 208, 5, 41, 0, 0, 208, 39, 1, 0, 0, 0, 209, 210, 7, 2, 0, 0, 210, 41, 1, 0, 0, 0, 23, 43, 47, 50, 55, 61, 68, 78, 87, 94, 100, 102, 109, 115, 121, 127, 132, 138, 153, 160, 170, 177, 179, 189] \ No newline at end of file +[4, 1, 42, 245, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 1, 0, 3, 0, 44, 8, 0, 1, 0, 1, 0, 3, 0, 48, 8, 0, 1, 1, 3, 1, 51, 8, 1, 1, 1, 5, 1, 54, 8, 1, 10, 1, 12, 1, 57, 9, 1, 1, 1, 5, 1, 60, 8, 1, 10, 1, 12, 1, 63, 9, 1, 1, 2, 1, 2, 5, 2, 67, 8, 2, 10, 2, 12, 2, 70, 9, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 79, 8, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 5, 4, 86, 8, 4, 10, 4, 12, 4, 89, 9, 4, 1, 4, 1, 4, 1, 4, 1, 4, 3, 4, 95, 8, 4, 1, 4, 1, 4, 1, 5, 1, 5, 5, 5, 101, 8, 5, 10, 5, 12, 5, 104, 9, 5, 1, 6, 1, 6, 5, 6, 108, 8, 6, 10, 6, 12, 6, 111, 9, 6, 1, 6, 5, 6, 114, 8, 6, 10, 6, 12, 6, 117, 9, 6, 1, 6, 5, 6, 120, 8, 6, 10, 6, 12, 6, 123, 9, 6, 1, 6, 1, 6, 1, 6, 3, 6, 128, 8, 6, 1, 7, 1, 7, 1, 8, 3, 8, 133, 8, 8, 1, 9, 1, 9, 5, 9, 137, 8, 9, 10, 9, 12, 9, 140, 9, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 154, 8, 10, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 160, 8, 11, 10, 11, 12, 11, 163, 9, 11, 1, 11, 1, 11, 5, 11, 167, 8, 11, 10, 11, 12, 11, 170, 9, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 180, 8, 11, 10, 11, 12, 11, 183, 9, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 190, 8, 11, 10, 11, 12, 11, 193, 9, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 200, 8, 11, 10, 11, 12, 11, 203, 9, 11, 1, 11, 1, 11, 1, 11, 1, 11, 3, 11, 209, 8, 11, 3, 11, 211, 8, 11, 3, 11, 213, 8, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 221, 8, 13, 10, 13, 12, 13, 224, 9, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 0, 0, 21, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 0, 3, 1, 0, 28, 29, 1, 0, 5, 6, 3, 0, 7, 7, 9, 9, 18, 18, 263, 0, 43, 1, 0, 0, 0, 2, 50, 1, 0, 0, 0, 4, 64, 1, 0, 0, 0, 6, 78, 1, 0, 0, 0, 8, 80, 1, 0, 0, 0, 10, 102, 1, 0, 0, 0, 12, 127, 1, 0, 0, 0, 14, 129, 1, 0, 0, 0, 16, 132, 1, 0, 0, 0, 18, 134, 1, 0, 0, 0, 20, 153, 1, 0, 0, 0, 22, 212, 1, 0, 0, 0, 24, 214, 1, 0, 0, 0, 26, 216, 1, 0, 0, 0, 28, 228, 1, 0, 0, 0, 30, 230, 1, 0, 0, 0, 32, 232, 1, 0, 0, 0, 34, 234, 1, 0, 0, 0, 36, 236, 1, 0, 0, 0, 38, 238, 1, 0, 0, 0, 40, 242, 1, 0, 0, 0, 42, 44, 5, 8, 0, 0, 43, 42, 1, 0, 0, 0, 43, 44, 1, 0, 0, 0, 44, 45, 1, 0, 0, 0, 45, 47, 3, 2, 1, 0, 46, 48, 3, 22, 11, 0, 47, 46, 1, 0, 0, 0, 47, 48, 1, 0, 0, 0, 48, 1, 1, 0, 0, 0, 49, 51, 3, 4, 2, 0, 50, 49, 1, 0, 0, 0, 50, 51, 1, 0, 0, 0, 51, 55, 1, 0, 0, 0, 52, 54, 3, 6, 3, 0, 53, 52, 1, 0, 0, 0, 54, 57, 1, 0, 0, 0, 55, 53, 1, 0, 0, 0, 55, 56, 1, 0, 0, 0, 56, 61, 1, 0, 0, 0, 57, 55, 1, 0, 0, 0, 58, 60, 3, 26, 13, 0, 59, 58, 1, 0, 0, 0, 60, 63, 1, 0, 0, 0, 61, 59, 1, 0, 0, 0, 61, 62, 1, 0, 0, 0, 62, 3, 1, 0, 0, 0, 63, 61, 1, 0, 0, 0, 64, 68, 5, 10, 0, 0, 65, 67, 3, 38, 19, 0, 66, 65, 1, 0, 0, 0, 67, 70, 1, 0, 0, 0, 68, 66, 1, 0, 0, 0, 68, 69, 1, 0, 0, 0, 69, 71, 1, 0, 0, 0, 70, 68, 1, 0, 0, 0, 71, 72, 5, 34, 0, 0, 72, 5, 1, 0, 0, 0, 73, 79, 5, 2, 0, 0, 74, 79, 3, 8, 4, 0, 75, 79, 3, 18, 9, 0, 76, 79, 3, 32, 16, 0, 77, 79, 3, 34, 17, 0, 78, 73, 1, 0, 0, 0, 78, 74, 1, 0, 0, 0, 78, 75, 1, 0, 0, 0, 78, 76, 1, 0, 0, 0, 78, 77, 1, 0, 0, 0, 79, 7, 1, 0, 0, 0, 80, 81, 5, 13, 0, 0, 81, 82, 5, 22, 0, 0, 82, 83, 5, 42, 0, 0, 83, 87, 3, 16, 8, 0, 84, 86, 5, 41, 0, 0, 85, 84, 1, 0, 0, 0, 86, 89, 1, 0, 0, 0, 87, 85, 1, 0, 0, 0, 87, 88, 1, 0, 0, 0, 88, 94, 1, 0, 0, 0, 89, 87, 1, 0, 0, 0, 90, 91, 5, 20, 0, 0, 91, 92, 3, 10, 5, 0, 92, 93, 5, 23, 0, 0, 93, 95, 1, 0, 0, 0, 94, 90, 1, 0, 0, 0, 94, 95, 1, 0, 0, 0, 95, 96, 1, 0, 0, 0, 96, 97, 5, 19, 0, 0, 97, 9, 1, 0, 0, 0, 98, 101, 3, 12, 6, 0, 99, 101, 3, 14, 7, 0, 100, 98, 1, 0, 0, 0, 100, 99, 1, 0, 0, 0, 101, 104, 1, 0, 0, 0, 102, 100, 1, 0, 0, 0, 102, 103, 1, 0, 0, 0, 103, 11, 1, 0, 0, 0, 104, 102, 1, 0, 0, 0, 105, 109, 5, 24, 0, 0, 106, 108, 7, 0, 0, 0, 107, 106, 1, 0, 0, 0, 108, 111, 1, 0, 0, 0, 109, 107, 1, 0, 0, 0, 109, 110, 1, 0, 0, 0, 110, 115, 1, 0, 0, 0, 111, 109, 1, 0, 0, 0, 112, 114, 5, 30, 0, 0, 113, 112, 1, 0, 0, 0, 114, 117, 1, 0, 0, 0, 115, 113, 1, 0, 0, 0, 115, 116, 1, 0, 0, 0, 116, 121, 1, 0, 0, 0, 117, 115, 1, 0, 0, 0, 118, 120, 7, 0, 0, 0, 119, 118, 1, 0, 0, 0, 120, 123, 1, 0, 0, 0, 121, 119, 1, 0, 0, 0, 121, 122, 1, 0, 0, 0, 122, 124, 1, 0, 0, 0, 123, 121, 1, 0, 0, 0, 124, 128, 5, 26, 0, 0, 125, 128, 3, 18, 9, 0, 126, 128, 5, 2, 0, 0, 127, 105, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 127, 126, 1, 0, 0, 0, 128, 13, 1, 0, 0, 0, 129, 130, 5, 4, 0, 0, 130, 15, 1, 0, 0, 0, 131, 133, 5, 42, 0, 0, 132, 131, 1, 0, 0, 0, 132, 133, 1, 0, 0, 0, 133, 17, 1, 0, 0, 0, 134, 138, 5, 12, 0, 0, 135, 137, 5, 32, 0, 0, 136, 135, 1, 0, 0, 0, 137, 140, 1, 0, 0, 0, 138, 136, 1, 0, 0, 0, 138, 139, 1, 0, 0, 0, 139, 141, 1, 0, 0, 0, 140, 138, 1, 0, 0, 0, 141, 142, 5, 34, 0, 0, 142, 19, 1, 0, 0, 0, 143, 154, 3, 22, 11, 0, 144, 154, 3, 36, 18, 0, 145, 154, 3, 18, 9, 0, 146, 154, 5, 3, 0, 0, 147, 154, 5, 2, 0, 0, 148, 154, 3, 28, 14, 0, 149, 154, 3, 30, 15, 0, 150, 154, 3, 32, 16, 0, 151, 154, 3, 34, 17, 0, 152, 154, 3, 40, 20, 0, 153, 143, 1, 0, 0, 0, 153, 144, 1, 0, 0, 0, 153, 145, 1, 0, 0, 0, 153, 146, 1, 0, 0, 0, 153, 147, 1, 0, 0, 0, 153, 148, 1, 0, 0, 0, 153, 149, 1, 0, 0, 0, 153, 150, 1, 0, 0, 0, 153, 151, 1, 0, 0, 0, 153, 152, 1, 0, 0, 0, 154, 21, 1, 0, 0, 0, 155, 156, 4, 11, 0, 0, 156, 157, 5, 11, 0, 0, 157, 161, 5, 42, 0, 0, 158, 160, 3, 38, 19, 0, 159, 158, 1, 0, 0, 0, 160, 163, 1, 0, 0, 0, 161, 159, 1, 0, 0, 0, 161, 162, 1, 0, 0, 0, 162, 164, 1, 0, 0, 0, 163, 161, 1, 0, 0, 0, 164, 168, 5, 33, 0, 0, 165, 167, 3, 20, 10, 0, 166, 165, 1, 0, 0, 0, 167, 170, 1, 0, 0, 0, 168, 166, 1, 0, 0, 0, 168, 169, 1, 0, 0, 0, 169, 171, 1, 0, 0, 0, 170, 168, 1, 0, 0, 0, 171, 172, 5, 11, 0, 0, 172, 173, 5, 39, 0, 0, 173, 174, 5, 42, 0, 0, 174, 213, 5, 33, 0, 0, 175, 176, 4, 11, 1, 0, 176, 177, 5, 11, 0, 0, 177, 181, 5, 42, 0, 0, 178, 180, 3, 38, 19, 0, 179, 178, 1, 0, 0, 0, 180, 183, 1, 0, 0, 0, 181, 179, 1, 0, 0, 0, 181, 182, 1, 0, 0, 0, 182, 184, 1, 0, 0, 0, 183, 181, 1, 0, 0, 0, 184, 213, 5, 35, 0, 0, 185, 186, 4, 11, 2, 0, 186, 187, 5, 11, 0, 0, 187, 191, 5, 42, 0, 0, 188, 190, 3, 38, 19, 0, 189, 188, 1, 0, 0, 0, 190, 193, 1, 0, 0, 0, 191, 189, 1, 0, 0, 0, 191, 192, 1, 0, 0, 0, 192, 210, 1, 0, 0, 0, 193, 191, 1, 0, 0, 0, 194, 211, 5, 35, 0, 0, 195, 208, 5, 33, 0, 0, 196, 197, 4, 11, 3, 1, 197, 209, 3, 24, 12, 0, 198, 200, 3, 20, 10, 0, 199, 198, 1, 0, 0, 0, 200, 203, 1, 0, 0, 0, 201, 199, 1, 0, 0, 0, 201, 202, 1, 0, 0, 0, 202, 204, 1, 0, 0, 0, 203, 201, 1, 0, 0, 0, 204, 205, 5, 11, 0, 0, 205, 206, 5, 39, 0, 0, 206, 207, 5, 42, 0, 0, 207, 209, 5, 33, 0, 0, 208, 196, 1, 0, 0, 0, 208, 201, 1, 0, 0, 0, 209, 211, 1, 0, 0, 0, 210, 194, 1, 0, 0, 0, 210, 195, 1, 0, 0, 0, 211, 213, 1, 0, 0, 0, 212, 155, 1, 0, 0, 0, 212, 175, 1, 0, 0, 0, 212, 185, 1, 0, 0, 0, 213, 23, 1, 0, 0, 0, 214, 215, 1, 0, 0, 0, 215, 25, 1, 0, 0, 0, 216, 217, 5, 11, 0, 0, 217, 218, 5, 37, 0, 0, 218, 222, 5, 42, 0, 0, 219, 221, 3, 38, 19, 0, 220, 219, 1, 0, 0, 0, 221, 224, 1, 0, 0, 0, 222, 220, 1, 0, 0, 0, 222, 223, 1, 0, 0, 0, 223, 225, 1, 0, 0, 0, 224, 222, 1, 0, 0, 0, 225, 226, 5, 38, 0, 0, 226, 227, 5, 33, 0, 0, 227, 27, 1, 0, 0, 0, 228, 229, 5, 17, 0, 0, 229, 29, 1, 0, 0, 0, 230, 231, 5, 16, 0, 0, 231, 31, 1, 0, 0, 0, 232, 233, 5, 15, 0, 0, 233, 33, 1, 0, 0, 0, 234, 235, 5, 14, 0, 0, 235, 35, 1, 0, 0, 0, 236, 237, 7, 1, 0, 0, 237, 37, 1, 0, 0, 0, 238, 239, 5, 42, 0, 0, 239, 240, 5, 40, 0, 0, 240, 241, 5, 41, 0, 0, 241, 39, 1, 0, 0, 0, 242, 243, 7, 2, 0, 0, 243, 41, 1, 0, 0, 0, 27, 43, 47, 50, 55, 61, 68, 78, 87, 94, 100, 102, 109, 115, 121, 127, 132, 138, 153, 161, 168, 181, 191, 201, 208, 210, 212, 222] \ No newline at end of file diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/internal/grammar/XMLParser.java b/rewrite-xml/src/main/java/org/openrewrite/xml/internal/grammar/XMLParser.java index 24caab5856a..d3b1bc99b38 100644 --- a/rewrite-xml/src/main/java/org/openrewrite/xml/internal/grammar/XMLParser.java +++ b/rewrite-xml/src/main/java/org/openrewrite/xml/internal/grammar/XMLParser.java @@ -160,32 +160,31 @@ public T accept(ParseTreeVisitor visitor) { public final DocumentContext document() throws RecognitionException { DocumentContext _localctx = new DocumentContext(_ctx, getState()); enterRule(_localctx, 0, RULE_document); - int _la; try { enterOuterAlt(_localctx, 1); { setState(43); _errHandler.sync(this); - _la = _input.LA(1); - if (_la==UTF_ENCODING_BOM) { + switch ( getInterpreter().adaptivePredict(_input,0,_ctx) ) { + case 1: { setState(42); match(UTF_ENCODING_BOM); } + break; } - setState(45); prolog(); setState(47); _errHandler.sync(this); - _la = _input.LA(1); - if (_la==OPEN) { + switch ( getInterpreter().adaptivePredict(_input,1,_ctx) ) { + case 1: { setState(46); element(); } + break; } - } } catch (RecognitionException re) { @@ -238,34 +237,35 @@ public T accept(ParseTreeVisitor visitor) { public final PrologContext prolog() throws RecognitionException { PrologContext _localctx = new PrologContext(_ctx, getState()); enterRule(_localctx, 2, RULE_prolog); - int _la; try { int _alt; enterOuterAlt(_localctx, 1); { setState(50); _errHandler.sync(this); - _la = _input.LA(1); - if (_la==SPECIAL_OPEN_XML) { + switch ( getInterpreter().adaptivePredict(_input,2,_ctx) ) { + case 1: { setState(49); xmldecl(); } + break; } - setState(55); _errHandler.sync(this); - _la = _input.LA(1); - while ((((_la) & ~0x3f) == 0 && ((1L << _la) & 61444L) != 0)) { - { - { - setState(52); - misc(); - } + _alt = getInterpreter().adaptivePredict(_input,3,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(52); + misc(); + } + } } setState(57); _errHandler.sync(this); - _la = _input.LA(1); + _alt = getInterpreter().adaptivePredict(_input,3,_ctx); } setState(61); _errHandler.sync(this); @@ -993,72 +993,67 @@ public final ContentContext content() throws RecognitionException { { setState(153); _errHandler.sync(this); - switch (_input.LA(1)) { - case OPEN: + switch ( getInterpreter().adaptivePredict(_input,17,_ctx) ) { + case 1: { setState(143); element(); } break; - case EntityRef: - case CharRef: + case 2: { setState(144); reference(); } break; - case SPECIAL_OPEN: + case 3: { setState(145); processinginstruction(); } break; - case CDATA: + case 4: { setState(146); match(CDATA); } break; - case COMMENT: + case 5: { setState(147); match(COMMENT); } break; - case JSP_SCRIPTLET: + case 6: { setState(148); jspscriptlet(); } break; - case JSP_EXPRESSION: + case 7: { setState(149); jspexpression(); } break; - case JSP_DECLARATION: + case 8: { setState(150); jspdeclaration(); } break; - case JSP_COMMENT: + case 9: { setState(151); jspcomment(); } break; - case SEA_WS: - case QUESTION_MARK: - case TEXT: + case 10: { setState(152); chardata(); } break; - default: - throw new NoViableAltException(this); } } } @@ -1080,31 +1075,31 @@ public static class ElementContext extends ParserRuleContext { public TerminalNode OPEN(int i) { return getToken(XMLParser.OPEN, i); } - public List Name() { return getTokens(XMLParser.Name); } - public TerminalNode Name(int i) { - return getToken(XMLParser.Name, i); - } - public TerminalNode SLASH_CLOSE() { return getToken(XMLParser.SLASH_CLOSE, 0); } public List CLOSE() { return getTokens(XMLParser.CLOSE); } public TerminalNode CLOSE(int i) { return getToken(XMLParser.CLOSE, i); } + public TerminalNode SLASH() { return getToken(XMLParser.SLASH, 0); } + public List Name() { return getTokens(XMLParser.Name); } + public TerminalNode Name(int i) { + return getToken(XMLParser.Name, i); + } public List attribute() { return getRuleContexts(AttributeContext.class); } public AttributeContext attribute(int i) { return getRuleContext(AttributeContext.class,i); } - public VoidCloseContext voidClose() { - return getRuleContext(VoidCloseContext.class,0); - } - public TerminalNode SLASH() { return getToken(XMLParser.SLASH, 0); } public List content() { return getRuleContexts(ContentContext.class); } public ContentContext content(int i) { return getRuleContext(ContentContext.class,i); } + public TerminalNode SLASH_CLOSE() { return getToken(XMLParser.SLASH_CLOSE, 0); } + public VoidCloseContext voidClose() { + return getRuleContext(VoidCloseContext.class,0); + } public ElementContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @@ -1130,84 +1125,170 @@ public final ElementContext element() throws RecognitionException { int _la; try { int _alt; - enterOuterAlt(_localctx, 1); - { - setState(155); - match(OPEN); - setState(156); - ((ElementContext)_localctx).name = match(Name); - setState(160); + setState(212); _errHandler.sync(this); - _la = _input.LA(1); - while (_la==Name) { - { + switch ( getInterpreter().adaptivePredict(_input,25,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); { + setState(155); + if (!(!isHtmlMode())) throw new FailedPredicateException(this, "!isHtmlMode()"); + setState(156); + match(OPEN); setState(157); - attribute(); + ((ElementContext)_localctx).name = match(Name); + setState(161); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==Name) { + { + { + setState(158); + attribute(); + } + } + setState(163); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(164); + match(CLOSE); + setState(168); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,19,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(165); + content(); + } + } + } + setState(170); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,19,_ctx); } + setState(171); + match(OPEN); + setState(172); + match(SLASH); + setState(173); + match(Name); + setState(174); + match(CLOSE); } - setState(162); + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(175); + if (!(!isHtmlMode())) throw new FailedPredicateException(this, "!isHtmlMode()"); + setState(176); + match(OPEN); + setState(177); + ((ElementContext)_localctx).name = match(Name); + setState(181); _errHandler.sync(this); _la = _input.LA(1); - } - setState(179); - _errHandler.sync(this); - switch (_input.LA(1)) { - case SLASH_CLOSE: - { - setState(163); + while (_la==Name) { + { + { + setState(178); + attribute(); + } + } + setState(183); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(184); match(SLASH_CLOSE); } break; - case CLOSE: + case 3: + enterOuterAlt(_localctx, 3); { - setState(164); - match(CLOSE); - setState(177); + setState(185); + if (!(isHtmlMode())) throw new FailedPredicateException(this, "isHtmlMode()"); + setState(186); + match(OPEN); + setState(187); + ((ElementContext)_localctx).name = match(Name); + setState(191); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==Name) { + { + { + setState(188); + attribute(); + } + } + setState(193); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(210); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,20,_ctx) ) { - case 1: + switch (_input.LA(1)) { + case SLASH_CLOSE: { - setState(165); - if (!(isVoidElement((((ElementContext)_localctx).name!=null?((ElementContext)_localctx).name.getText():null)))) throw new FailedPredicateException(this, "isVoidElement($name.text)"); - setState(166); - voidClose(); + setState(194); + match(SLASH_CLOSE); } break; - case 2: + case CLOSE: { - setState(170); + setState(195); + match(CLOSE); + setState(208); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,19,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { - if ( _alt==1 ) { - { - { - setState(167); - content(); - } - } + switch ( getInterpreter().adaptivePredict(_input,23,_ctx) ) { + case 1: + { + setState(196); + if (!(isVoidElement((((ElementContext)_localctx).name!=null?((ElementContext)_localctx).name.getText():null)))) throw new FailedPredicateException(this, "isVoidElement($name.text)"); + setState(197); + voidClose(); } - setState(172); + break; + case 2: + { + setState(201); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,19,_ctx); + _alt = getInterpreter().adaptivePredict(_input,22,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(198); + content(); + } + } + } + setState(203); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,22,_ctx); + } + setState(204); + match(OPEN); + setState(205); + match(SLASH); + setState(206); + match(Name); + setState(207); + match(CLOSE); + } + break; } - setState(173); - match(OPEN); - setState(174); - match(SLASH); - setState(175); - match(Name); - setState(176); - match(CLOSE); } break; + default: + throw new NoViableAltException(this); } } break; - default: - throw new NoViableAltException(this); - } } } catch (RecognitionException re) { @@ -1300,29 +1381,29 @@ public final JspdirectiveContext jspdirective() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(183); + setState(216); match(OPEN); - setState(184); + setState(217); match(DIRECTIVE_OPEN); - setState(185); + setState(218); match(Name); - setState(189); + setState(222); _errHandler.sync(this); _la = _input.LA(1); while (_la==Name) { { { - setState(186); + setState(219); attribute(); } } - setState(191); + setState(224); _errHandler.sync(this); _la = _input.LA(1); } - setState(192); + setState(225); match(DIRECTIVE_CLOSE); - setState(193); + setState(226); match(CLOSE); } } @@ -1365,7 +1446,7 @@ public final JspscriptletContext jspscriptlet() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(195); + setState(228); match(JSP_SCRIPTLET); } } @@ -1408,7 +1489,7 @@ public final JspexpressionContext jspexpression() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(197); + setState(230); match(JSP_EXPRESSION); } } @@ -1451,7 +1532,7 @@ public final JspdeclarationContext jspdeclaration() throws RecognitionException try { enterOuterAlt(_localctx, 1); { - setState(199); + setState(232); match(JSP_DECLARATION); } } @@ -1494,7 +1575,7 @@ public final JspcommentContext jspcomment() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(201); + setState(234); match(JSP_COMMENT); } } @@ -1539,7 +1620,7 @@ public final ReferenceContext reference() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(203); + setState(236); _la = _input.LA(1); if ( !(_la==EntityRef || _la==CharRef) ) { _errHandler.recoverInline(this); @@ -1592,11 +1673,11 @@ public final AttributeContext attribute() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(205); + setState(238); match(Name); - setState(206); + setState(239); match(EQUALS); - setState(207); + setState(240); match(STRING); } } @@ -1642,7 +1723,7 @@ public final ChardataContext chardata() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(209); + setState(242); _la = _input.LA(1); if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 262784L) != 0)) ) { _errHandler.recoverInline(this); @@ -1675,13 +1756,19 @@ public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { private boolean element_sempred(ElementContext _localctx, int predIndex) { switch (predIndex) { case 0: + return !isHtmlMode(); + case 1: + return !isHtmlMode(); + case 2: + return isHtmlMode(); + case 3: return isVoidElement((((ElementContext)_localctx).name!=null?((ElementContext)_localctx).name.getText():null)); } return true; } public static final String _serializedATN = - "\u0004\u0001*\u00d4\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ + "\u0004\u0001*\u00f5\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ "\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b\u0007\u000b\u0002"+ @@ -1704,114 +1791,138 @@ private boolean element_sempred(ElementContext _localctx, int predIndex) { "\b\u0003\b\u0085\b\b\u0001\t\u0001\t\u0005\t\u0089\b\t\n\t\f\t\u008c\t"+ "\t\u0001\t\u0001\t\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001"+ "\n\u0001\n\u0001\n\u0001\n\u0003\n\u009a\b\n\u0001\u000b\u0001\u000b\u0001"+ - "\u000b\u0005\u000b\u009f\b\u000b\n\u000b\f\u000b\u00a2\t\u000b\u0001\u000b"+ - "\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0005\u000b\u00a9\b\u000b"+ - "\n\u000b\f\u000b\u00ac\t\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001"+ - "\u000b\u0003\u000b\u00b2\b\u000b\u0003\u000b\u00b4\b\u000b\u0001\f\u0001"+ - "\f\u0001\r\u0001\r\u0001\r\u0001\r\u0005\r\u00bc\b\r\n\r\f\r\u00bf\t\r"+ - "\u0001\r\u0001\r\u0001\r\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f"+ - "\u0001\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0012\u0001\u0012"+ - "\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0014\u0001\u0014"+ - "\u0001\u0014\u0000\u0000\u0015\u0000\u0002\u0004\u0006\b\n\f\u000e\u0010"+ - "\u0012\u0014\u0016\u0018\u001a\u001c\u001e \"$&(\u0000\u0003\u0001\u0000"+ - "\u001c\u001d\u0001\u0000\u0005\u0006\u0003\u0000\u0007\u0007\t\t\u0012"+ - "\u0012\u00e1\u0000+\u0001\u0000\u0000\u0000\u00022\u0001\u0000\u0000\u0000"+ - "\u0004@\u0001\u0000\u0000\u0000\u0006N\u0001\u0000\u0000\u0000\bP\u0001"+ - "\u0000\u0000\u0000\nf\u0001\u0000\u0000\u0000\f\u007f\u0001\u0000\u0000"+ - "\u0000\u000e\u0081\u0001\u0000\u0000\u0000\u0010\u0084\u0001\u0000\u0000"+ - "\u0000\u0012\u0086\u0001\u0000\u0000\u0000\u0014\u0099\u0001\u0000\u0000"+ - "\u0000\u0016\u009b\u0001\u0000\u0000\u0000\u0018\u00b5\u0001\u0000\u0000"+ - "\u0000\u001a\u00b7\u0001\u0000\u0000\u0000\u001c\u00c3\u0001\u0000\u0000"+ - "\u0000\u001e\u00c5\u0001\u0000\u0000\u0000 \u00c7\u0001\u0000\u0000\u0000"+ - "\"\u00c9\u0001\u0000\u0000\u0000$\u00cb\u0001\u0000\u0000\u0000&\u00cd"+ - "\u0001\u0000\u0000\u0000(\u00d1\u0001\u0000\u0000\u0000*,\u0005\b\u0000"+ - "\u0000+*\u0001\u0000\u0000\u0000+,\u0001\u0000\u0000\u0000,-\u0001\u0000"+ - "\u0000\u0000-/\u0003\u0002\u0001\u0000.0\u0003\u0016\u000b\u0000/.\u0001"+ - "\u0000\u0000\u0000/0\u0001\u0000\u0000\u00000\u0001\u0001\u0000\u0000"+ - "\u000013\u0003\u0004\u0002\u000021\u0001\u0000\u0000\u000023\u0001\u0000"+ - "\u0000\u000037\u0001\u0000\u0000\u000046\u0003\u0006\u0003\u000054\u0001"+ - "\u0000\u0000\u000069\u0001\u0000\u0000\u000075\u0001\u0000\u0000\u0000"+ - "78\u0001\u0000\u0000\u00008=\u0001\u0000\u0000\u000097\u0001\u0000\u0000"+ - "\u0000:<\u0003\u001a\r\u0000;:\u0001\u0000\u0000\u0000\u0001\u0000\u0000\u0000>\u0003\u0001"+ - "\u0000\u0000\u0000?=\u0001\u0000\u0000\u0000@D\u0005\n\u0000\u0000AC\u0003"+ - "&\u0013\u0000BA\u0001\u0000\u0000\u0000CF\u0001\u0000\u0000\u0000DB\u0001"+ - "\u0000\u0000\u0000DE\u0001\u0000\u0000\u0000EG\u0001\u0000\u0000\u0000"+ - "FD\u0001\u0000\u0000\u0000GH\u0005\"\u0000\u0000H\u0005\u0001\u0000\u0000"+ - "\u0000IO\u0005\u0002\u0000\u0000JO\u0003\b\u0004\u0000KO\u0003\u0012\t"+ - "\u0000LO\u0003 \u0010\u0000MO\u0003\"\u0011\u0000NI\u0001\u0000\u0000"+ - "\u0000NJ\u0001\u0000\u0000\u0000NK\u0001\u0000\u0000\u0000NL\u0001\u0000"+ - "\u0000\u0000NM\u0001\u0000\u0000\u0000O\u0007\u0001\u0000\u0000\u0000"+ - "PQ\u0005\r\u0000\u0000QR\u0005\u0016\u0000\u0000RS\u0005*\u0000\u0000"+ - "SW\u0003\u0010\b\u0000TV\u0005)\u0000\u0000UT\u0001\u0000\u0000\u0000"+ - "VY\u0001\u0000\u0000\u0000WU\u0001\u0000\u0000\u0000WX\u0001\u0000\u0000"+ - "\u0000X^\u0001\u0000\u0000\u0000YW\u0001\u0000\u0000\u0000Z[\u0005\u0014"+ - "\u0000\u0000[\\\u0003\n\u0005\u0000\\]\u0005\u0017\u0000\u0000]_\u0001"+ - "\u0000\u0000\u0000^Z\u0001\u0000\u0000\u0000^_\u0001\u0000\u0000\u0000"+ - "_`\u0001\u0000\u0000\u0000`a\u0005\u0013\u0000\u0000a\t\u0001\u0000\u0000"+ - "\u0000be\u0003\f\u0006\u0000ce\u0003\u000e\u0007\u0000db\u0001\u0000\u0000"+ - "\u0000dc\u0001\u0000\u0000\u0000eh\u0001\u0000\u0000\u0000fd\u0001\u0000"+ - "\u0000\u0000fg\u0001\u0000\u0000\u0000g\u000b\u0001\u0000\u0000\u0000"+ - "hf\u0001\u0000\u0000\u0000im\u0005\u0018\u0000\u0000jl\u0007\u0000\u0000"+ - "\u0000kj\u0001\u0000\u0000\u0000lo\u0001\u0000\u0000\u0000mk\u0001\u0000"+ - "\u0000\u0000mn\u0001\u0000\u0000\u0000ns\u0001\u0000\u0000\u0000om\u0001"+ - "\u0000\u0000\u0000pr\u0005\u001e\u0000\u0000qp\u0001\u0000\u0000\u0000"+ - "ru\u0001\u0000\u0000\u0000sq\u0001\u0000\u0000\u0000st\u0001\u0000\u0000"+ - "\u0000ty\u0001\u0000\u0000\u0000us\u0001\u0000\u0000\u0000vx\u0007\u0000"+ - "\u0000\u0000wv\u0001\u0000\u0000\u0000x{\u0001\u0000\u0000\u0000yw\u0001"+ - "\u0000\u0000\u0000yz\u0001\u0000\u0000\u0000z|\u0001\u0000\u0000\u0000"+ - "{y\u0001\u0000\u0000\u0000|\u0080\u0005\u001a\u0000\u0000}\u0080\u0003"+ - "\u0012\t\u0000~\u0080\u0005\u0002\u0000\u0000\u007fi\u0001\u0000\u0000"+ - "\u0000\u007f}\u0001\u0000\u0000\u0000\u007f~\u0001\u0000\u0000\u0000\u0080"+ - "\r\u0001\u0000\u0000\u0000\u0081\u0082\u0005\u0004\u0000\u0000\u0082\u000f"+ - "\u0001\u0000\u0000\u0000\u0083\u0085\u0005*\u0000\u0000\u0084\u0083\u0001"+ - "\u0000\u0000\u0000\u0084\u0085\u0001\u0000\u0000\u0000\u0085\u0011\u0001"+ - "\u0000\u0000\u0000\u0086\u008a\u0005\f\u0000\u0000\u0087\u0089\u0005 "+ - "\u0000\u0000\u0088\u0087\u0001\u0000\u0000\u0000\u0089\u008c\u0001\u0000"+ - "\u0000\u0000\u008a\u0088\u0001\u0000\u0000\u0000\u008a\u008b\u0001\u0000"+ - "\u0000\u0000\u008b\u008d\u0001\u0000\u0000\u0000\u008c\u008a\u0001\u0000"+ - "\u0000\u0000\u008d\u008e\u0005\"\u0000\u0000\u008e\u0013\u0001\u0000\u0000"+ - "\u0000\u008f\u009a\u0003\u0016\u000b\u0000\u0090\u009a\u0003$\u0012\u0000"+ - "\u0091\u009a\u0003\u0012\t\u0000\u0092\u009a\u0005\u0003\u0000\u0000\u0093"+ - "\u009a\u0005\u0002\u0000\u0000\u0094\u009a\u0003\u001c\u000e\u0000\u0095"+ - "\u009a\u0003\u001e\u000f\u0000\u0096\u009a\u0003 \u0010\u0000\u0097\u009a"+ - "\u0003\"\u0011\u0000\u0098\u009a\u0003(\u0014\u0000\u0099\u008f\u0001"+ - "\u0000\u0000\u0000\u0099\u0090\u0001\u0000\u0000\u0000\u0099\u0091\u0001"+ - "\u0000\u0000\u0000\u0099\u0092\u0001\u0000\u0000\u0000\u0099\u0093\u0001"+ - "\u0000\u0000\u0000\u0099\u0094\u0001\u0000\u0000\u0000\u0099\u0095\u0001"+ - "\u0000\u0000\u0000\u0099\u0096\u0001\u0000\u0000\u0000\u0099\u0097\u0001"+ - "\u0000\u0000\u0000\u0099\u0098\u0001\u0000\u0000\u0000\u009a\u0015\u0001"+ - "\u0000\u0000\u0000\u009b\u009c\u0005\u000b\u0000\u0000\u009c\u00a0\u0005"+ - "*\u0000\u0000\u009d\u009f\u0003&\u0013\u0000\u009e\u009d\u0001\u0000\u0000"+ - "\u0000\u009f\u00a2\u0001\u0000\u0000\u0000\u00a0\u009e\u0001\u0000\u0000"+ - "\u0000\u00a0\u00a1\u0001\u0000\u0000\u0000\u00a1\u00b3\u0001\u0000\u0000"+ - "\u0000\u00a2\u00a0\u0001\u0000\u0000\u0000\u00a3\u00b4\u0005#\u0000\u0000"+ - "\u00a4\u00b1\u0005!\u0000\u0000\u00a5\u00a6\u0004\u000b\u0000\u0001\u00a6"+ - "\u00b2\u0003\u0018\f\u0000\u00a7\u00a9\u0003\u0014\n\u0000\u00a8\u00a7"+ - "\u0001\u0000\u0000\u0000\u00a9\u00ac\u0001\u0000\u0000\u0000\u00aa\u00a8"+ - "\u0001\u0000\u0000\u0000\u00aa\u00ab\u0001\u0000\u0000\u0000\u00ab\u00ad"+ - "\u0001\u0000\u0000\u0000\u00ac\u00aa\u0001\u0000\u0000\u0000\u00ad\u00ae"+ - "\u0005\u000b\u0000\u0000\u00ae\u00af\u0005\'\u0000\u0000\u00af\u00b0\u0005"+ - "*\u0000\u0000\u00b0\u00b2\u0005!\u0000\u0000\u00b1\u00a5\u0001\u0000\u0000"+ - "\u0000\u00b1\u00aa\u0001\u0000\u0000\u0000\u00b2\u00b4\u0001\u0000\u0000"+ - "\u0000\u00b3\u00a3\u0001\u0000\u0000\u0000\u00b3\u00a4\u0001\u0000\u0000"+ - "\u0000\u00b4\u0017\u0001\u0000\u0000\u0000\u00b5\u00b6\u0001\u0000\u0000"+ - "\u0000\u00b6\u0019\u0001\u0000\u0000\u0000\u00b7\u00b8\u0005\u000b\u0000"+ - "\u0000\u00b8\u00b9\u0005%\u0000\u0000\u00b9\u00bd\u0005*\u0000\u0000\u00ba"+ - "\u00bc\u0003&\u0013\u0000\u00bb\u00ba\u0001\u0000\u0000\u0000\u00bc\u00bf"+ - "\u0001\u0000\u0000\u0000\u00bd\u00bb\u0001\u0000\u0000\u0000\u00bd\u00be"+ - "\u0001\u0000\u0000\u0000\u00be\u00c0\u0001\u0000\u0000\u0000\u00bf\u00bd"+ - "\u0001\u0000\u0000\u0000\u00c0\u00c1\u0005&\u0000\u0000\u00c1\u00c2\u0005"+ - "!\u0000\u0000\u00c2\u001b\u0001\u0000\u0000\u0000\u00c3\u00c4\u0005\u0011"+ - "\u0000\u0000\u00c4\u001d\u0001\u0000\u0000\u0000\u00c5\u00c6\u0005\u0010"+ - "\u0000\u0000\u00c6\u001f\u0001\u0000\u0000\u0000\u00c7\u00c8\u0005\u000f"+ - "\u0000\u0000\u00c8!\u0001\u0000\u0000\u0000\u00c9\u00ca\u0005\u000e\u0000"+ - "\u0000\u00ca#\u0001\u0000\u0000\u0000\u00cb\u00cc\u0007\u0001\u0000\u0000"+ - "\u00cc%\u0001\u0000\u0000\u0000\u00cd\u00ce\u0005*\u0000\u0000\u00ce\u00cf"+ - "\u0005(\u0000\u0000\u00cf\u00d0\u0005)\u0000\u0000\u00d0\'\u0001\u0000"+ - "\u0000\u0000\u00d1\u00d2\u0007\u0002\u0000\u0000\u00d2)\u0001\u0000\u0000"+ - "\u0000\u0017+/27=DNW^dfmsy\u007f\u0084\u008a\u0099\u00a0\u00aa\u00b1\u00b3"+ - "\u00bd"; + "\u000b\u0001\u000b\u0005\u000b\u00a0\b\u000b\n\u000b\f\u000b\u00a3\t\u000b"+ + "\u0001\u000b\u0001\u000b\u0005\u000b\u00a7\b\u000b\n\u000b\f\u000b\u00aa"+ + "\t\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001"+ + "\u000b\u0001\u000b\u0001\u000b\u0005\u000b\u00b4\b\u000b\n\u000b\f\u000b"+ + "\u00b7\t\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b"+ + "\u0005\u000b\u00be\b\u000b\n\u000b\f\u000b\u00c1\t\u000b\u0001\u000b\u0001"+ + "\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0005\u000b\u00c8\b\u000b\n"+ + "\u000b\f\u000b\u00cb\t\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001"+ + "\u000b\u0003\u000b\u00d1\b\u000b\u0003\u000b\u00d3\b\u000b\u0003\u000b"+ + "\u00d5\b\u000b\u0001\f\u0001\f\u0001\r\u0001\r\u0001\r\u0001\r\u0005\r"+ + "\u00dd\b\r\n\r\f\r\u00e0\t\r\u0001\r\u0001\r\u0001\r\u0001\u000e\u0001"+ + "\u000e\u0001\u000f\u0001\u000f\u0001\u0010\u0001\u0010\u0001\u0011\u0001"+ + "\u0011\u0001\u0012\u0001\u0012\u0001\u0013\u0001\u0013\u0001\u0013\u0001"+ + "\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0000\u0000\u0015\u0000\u0002"+ + "\u0004\u0006\b\n\f\u000e\u0010\u0012\u0014\u0016\u0018\u001a\u001c\u001e"+ + " \"$&(\u0000\u0003\u0001\u0000\u001c\u001d\u0001\u0000\u0005\u0006\u0003"+ + "\u0000\u0007\u0007\t\t\u0012\u0012\u0107\u0000+\u0001\u0000\u0000\u0000"+ + "\u00022\u0001\u0000\u0000\u0000\u0004@\u0001\u0000\u0000\u0000\u0006N"+ + "\u0001\u0000\u0000\u0000\bP\u0001\u0000\u0000\u0000\nf\u0001\u0000\u0000"+ + "\u0000\f\u007f\u0001\u0000\u0000\u0000\u000e\u0081\u0001\u0000\u0000\u0000"+ + "\u0010\u0084\u0001\u0000\u0000\u0000\u0012\u0086\u0001\u0000\u0000\u0000"+ + "\u0014\u0099\u0001\u0000\u0000\u0000\u0016\u00d4\u0001\u0000\u0000\u0000"+ + "\u0018\u00d6\u0001\u0000\u0000\u0000\u001a\u00d8\u0001\u0000\u0000\u0000"+ + "\u001c\u00e4\u0001\u0000\u0000\u0000\u001e\u00e6\u0001\u0000\u0000\u0000"+ + " \u00e8\u0001\u0000\u0000\u0000\"\u00ea\u0001\u0000\u0000\u0000$\u00ec"+ + "\u0001\u0000\u0000\u0000&\u00ee\u0001\u0000\u0000\u0000(\u00f2\u0001\u0000"+ + "\u0000\u0000*,\u0005\b\u0000\u0000+*\u0001\u0000\u0000\u0000+,\u0001\u0000"+ + "\u0000\u0000,-\u0001\u0000\u0000\u0000-/\u0003\u0002\u0001\u0000.0\u0003"+ + "\u0016\u000b\u0000/.\u0001\u0000\u0000\u0000/0\u0001\u0000\u0000\u0000"+ + "0\u0001\u0001\u0000\u0000\u000013\u0003\u0004\u0002\u000021\u0001\u0000"+ + "\u0000\u000023\u0001\u0000\u0000\u000037\u0001\u0000\u0000\u000046\u0003"+ + "\u0006\u0003\u000054\u0001\u0000\u0000\u000069\u0001\u0000\u0000\u0000"+ + "75\u0001\u0000\u0000\u000078\u0001\u0000\u0000\u00008=\u0001\u0000\u0000"+ + "\u000097\u0001\u0000\u0000\u0000:<\u0003\u001a\r\u0000;:\u0001\u0000\u0000"+ + "\u0000\u0001\u0000"+ + "\u0000\u0000>\u0003\u0001\u0000\u0000\u0000?=\u0001\u0000\u0000\u0000"+ + "@D\u0005\n\u0000\u0000AC\u0003&\u0013\u0000BA\u0001\u0000\u0000\u0000"+ + "CF\u0001\u0000\u0000\u0000DB\u0001\u0000\u0000\u0000DE\u0001\u0000\u0000"+ + "\u0000EG\u0001\u0000\u0000\u0000FD\u0001\u0000\u0000\u0000GH\u0005\"\u0000"+ + "\u0000H\u0005\u0001\u0000\u0000\u0000IO\u0005\u0002\u0000\u0000JO\u0003"+ + "\b\u0004\u0000KO\u0003\u0012\t\u0000LO\u0003 \u0010\u0000MO\u0003\"\u0011"+ + "\u0000NI\u0001\u0000\u0000\u0000NJ\u0001\u0000\u0000\u0000NK\u0001\u0000"+ + "\u0000\u0000NL\u0001\u0000\u0000\u0000NM\u0001\u0000\u0000\u0000O\u0007"+ + "\u0001\u0000\u0000\u0000PQ\u0005\r\u0000\u0000QR\u0005\u0016\u0000\u0000"+ + "RS\u0005*\u0000\u0000SW\u0003\u0010\b\u0000TV\u0005)\u0000\u0000UT\u0001"+ + "\u0000\u0000\u0000VY\u0001\u0000\u0000\u0000WU\u0001\u0000\u0000\u0000"+ + "WX\u0001\u0000\u0000\u0000X^\u0001\u0000\u0000\u0000YW\u0001\u0000\u0000"+ + "\u0000Z[\u0005\u0014\u0000\u0000[\\\u0003\n\u0005\u0000\\]\u0005\u0017"+ + "\u0000\u0000]_\u0001\u0000\u0000\u0000^Z\u0001\u0000\u0000\u0000^_\u0001"+ + "\u0000\u0000\u0000_`\u0001\u0000\u0000\u0000`a\u0005\u0013\u0000\u0000"+ + "a\t\u0001\u0000\u0000\u0000be\u0003\f\u0006\u0000ce\u0003\u000e\u0007"+ + "\u0000db\u0001\u0000\u0000\u0000dc\u0001\u0000\u0000\u0000eh\u0001\u0000"+ + "\u0000\u0000fd\u0001\u0000\u0000\u0000fg\u0001\u0000\u0000\u0000g\u000b"+ + "\u0001\u0000\u0000\u0000hf\u0001\u0000\u0000\u0000im\u0005\u0018\u0000"+ + "\u0000jl\u0007\u0000\u0000\u0000kj\u0001\u0000\u0000\u0000lo\u0001\u0000"+ + "\u0000\u0000mk\u0001\u0000\u0000\u0000mn\u0001\u0000\u0000\u0000ns\u0001"+ + "\u0000\u0000\u0000om\u0001\u0000\u0000\u0000pr\u0005\u001e\u0000\u0000"+ + "qp\u0001\u0000\u0000\u0000ru\u0001\u0000\u0000\u0000sq\u0001\u0000\u0000"+ + "\u0000st\u0001\u0000\u0000\u0000ty\u0001\u0000\u0000\u0000us\u0001\u0000"+ + "\u0000\u0000vx\u0007\u0000\u0000\u0000wv\u0001\u0000\u0000\u0000x{\u0001"+ + "\u0000\u0000\u0000yw\u0001\u0000\u0000\u0000yz\u0001\u0000\u0000\u0000"+ + "z|\u0001\u0000\u0000\u0000{y\u0001\u0000\u0000\u0000|\u0080\u0005\u001a"+ + "\u0000\u0000}\u0080\u0003\u0012\t\u0000~\u0080\u0005\u0002\u0000\u0000"+ + "\u007fi\u0001\u0000\u0000\u0000\u007f}\u0001\u0000\u0000\u0000\u007f~"+ + "\u0001\u0000\u0000\u0000\u0080\r\u0001\u0000\u0000\u0000\u0081\u0082\u0005"+ + "\u0004\u0000\u0000\u0082\u000f\u0001\u0000\u0000\u0000\u0083\u0085\u0005"+ + "*\u0000\u0000\u0084\u0083\u0001\u0000\u0000\u0000\u0084\u0085\u0001\u0000"+ + "\u0000\u0000\u0085\u0011\u0001\u0000\u0000\u0000\u0086\u008a\u0005\f\u0000"+ + "\u0000\u0087\u0089\u0005 \u0000\u0000\u0088\u0087\u0001\u0000\u0000\u0000"+ + "\u0089\u008c\u0001\u0000\u0000\u0000\u008a\u0088\u0001\u0000\u0000\u0000"+ + "\u008a\u008b\u0001\u0000\u0000\u0000\u008b\u008d\u0001\u0000\u0000\u0000"+ + "\u008c\u008a\u0001\u0000\u0000\u0000\u008d\u008e\u0005\"\u0000\u0000\u008e"+ + "\u0013\u0001\u0000\u0000\u0000\u008f\u009a\u0003\u0016\u000b\u0000\u0090"+ + "\u009a\u0003$\u0012\u0000\u0091\u009a\u0003\u0012\t\u0000\u0092\u009a"+ + "\u0005\u0003\u0000\u0000\u0093\u009a\u0005\u0002\u0000\u0000\u0094\u009a"+ + "\u0003\u001c\u000e\u0000\u0095\u009a\u0003\u001e\u000f\u0000\u0096\u009a"+ + "\u0003 \u0010\u0000\u0097\u009a\u0003\"\u0011\u0000\u0098\u009a\u0003"+ + "(\u0014\u0000\u0099\u008f\u0001\u0000\u0000\u0000\u0099\u0090\u0001\u0000"+ + "\u0000\u0000\u0099\u0091\u0001\u0000\u0000\u0000\u0099\u0092\u0001\u0000"+ + "\u0000\u0000\u0099\u0093\u0001\u0000\u0000\u0000\u0099\u0094\u0001\u0000"+ + "\u0000\u0000\u0099\u0095\u0001\u0000\u0000\u0000\u0099\u0096\u0001\u0000"+ + "\u0000\u0000\u0099\u0097\u0001\u0000\u0000\u0000\u0099\u0098\u0001\u0000"+ + "\u0000\u0000\u009a\u0015\u0001\u0000\u0000\u0000\u009b\u009c\u0004\u000b"+ + "\u0000\u0000\u009c\u009d\u0005\u000b\u0000\u0000\u009d\u00a1\u0005*\u0000"+ + "\u0000\u009e\u00a0\u0003&\u0013\u0000\u009f\u009e\u0001\u0000\u0000\u0000"+ + "\u00a0\u00a3\u0001\u0000\u0000\u0000\u00a1\u009f\u0001\u0000\u0000\u0000"+ + "\u00a1\u00a2\u0001\u0000\u0000\u0000\u00a2\u00a4\u0001\u0000\u0000\u0000"+ + "\u00a3\u00a1\u0001\u0000\u0000\u0000\u00a4\u00a8\u0005!\u0000\u0000\u00a5"+ + "\u00a7\u0003\u0014\n\u0000\u00a6\u00a5\u0001\u0000\u0000\u0000\u00a7\u00aa"+ + "\u0001\u0000\u0000\u0000\u00a8\u00a6\u0001\u0000\u0000\u0000\u00a8\u00a9"+ + "\u0001\u0000\u0000\u0000\u00a9\u00ab\u0001\u0000\u0000\u0000\u00aa\u00a8"+ + "\u0001\u0000\u0000\u0000\u00ab\u00ac\u0005\u000b\u0000\u0000\u00ac\u00ad"+ + "\u0005\'\u0000\u0000\u00ad\u00ae\u0005*\u0000\u0000\u00ae\u00d5\u0005"+ + "!\u0000\u0000\u00af\u00b0\u0004\u000b\u0001\u0000\u00b0\u00b1\u0005\u000b"+ + "\u0000\u0000\u00b1\u00b5\u0005*\u0000\u0000\u00b2\u00b4\u0003&\u0013\u0000"+ + "\u00b3\u00b2\u0001\u0000\u0000\u0000\u00b4\u00b7\u0001\u0000\u0000\u0000"+ + "\u00b5\u00b3\u0001\u0000\u0000\u0000\u00b5\u00b6\u0001\u0000\u0000\u0000"+ + "\u00b6\u00b8\u0001\u0000\u0000\u0000\u00b7\u00b5\u0001\u0000\u0000\u0000"+ + "\u00b8\u00d5\u0005#\u0000\u0000\u00b9\u00ba\u0004\u000b\u0002\u0000\u00ba"+ + "\u00bb\u0005\u000b\u0000\u0000\u00bb\u00bf\u0005*\u0000\u0000\u00bc\u00be"+ + "\u0003&\u0013\u0000\u00bd\u00bc\u0001\u0000\u0000\u0000\u00be\u00c1\u0001"+ + "\u0000\u0000\u0000\u00bf\u00bd\u0001\u0000\u0000\u0000\u00bf\u00c0\u0001"+ + "\u0000\u0000\u0000\u00c0\u00d2\u0001\u0000\u0000\u0000\u00c1\u00bf\u0001"+ + "\u0000\u0000\u0000\u00c2\u00d3\u0005#\u0000\u0000\u00c3\u00d0\u0005!\u0000"+ + "\u0000\u00c4\u00c5\u0004\u000b\u0003\u0001\u00c5\u00d1\u0003\u0018\f\u0000"+ + "\u00c6\u00c8\u0003\u0014\n\u0000\u00c7\u00c6\u0001\u0000\u0000\u0000\u00c8"+ + "\u00cb\u0001\u0000\u0000\u0000\u00c9\u00c7\u0001\u0000\u0000\u0000\u00c9"+ + "\u00ca\u0001\u0000\u0000\u0000\u00ca\u00cc\u0001\u0000\u0000\u0000\u00cb"+ + "\u00c9\u0001\u0000\u0000\u0000\u00cc\u00cd\u0005\u000b\u0000\u0000\u00cd"+ + "\u00ce\u0005\'\u0000\u0000\u00ce\u00cf\u0005*\u0000\u0000\u00cf\u00d1"+ + "\u0005!\u0000\u0000\u00d0\u00c4\u0001\u0000\u0000\u0000\u00d0\u00c9\u0001"+ + "\u0000\u0000\u0000\u00d1\u00d3\u0001\u0000\u0000\u0000\u00d2\u00c2\u0001"+ + "\u0000\u0000\u0000\u00d2\u00c3\u0001\u0000\u0000\u0000\u00d3\u00d5\u0001"+ + "\u0000\u0000\u0000\u00d4\u009b\u0001\u0000\u0000\u0000\u00d4\u00af\u0001"+ + "\u0000\u0000\u0000\u00d4\u00b9\u0001\u0000\u0000\u0000\u00d5\u0017\u0001"+ + "\u0000\u0000\u0000\u00d6\u00d7\u0001\u0000\u0000\u0000\u00d7\u0019\u0001"+ + "\u0000\u0000\u0000\u00d8\u00d9\u0005\u000b\u0000\u0000\u00d9\u00da\u0005"+ + "%\u0000\u0000\u00da\u00de\u0005*\u0000\u0000\u00db\u00dd\u0003&\u0013"+ + "\u0000\u00dc\u00db\u0001\u0000\u0000\u0000\u00dd\u00e0\u0001\u0000\u0000"+ + "\u0000\u00de\u00dc\u0001\u0000\u0000\u0000\u00de\u00df\u0001\u0000\u0000"+ + "\u0000\u00df\u00e1\u0001\u0000\u0000\u0000\u00e0\u00de\u0001\u0000\u0000"+ + "\u0000\u00e1\u00e2\u0005&\u0000\u0000\u00e2\u00e3\u0005!\u0000\u0000\u00e3"+ + "\u001b\u0001\u0000\u0000\u0000\u00e4\u00e5\u0005\u0011\u0000\u0000\u00e5"+ + "\u001d\u0001\u0000\u0000\u0000\u00e6\u00e7\u0005\u0010\u0000\u0000\u00e7"+ + "\u001f\u0001\u0000\u0000\u0000\u00e8\u00e9\u0005\u000f\u0000\u0000\u00e9"+ + "!\u0001\u0000\u0000\u0000\u00ea\u00eb\u0005\u000e\u0000\u0000\u00eb#\u0001"+ + "\u0000\u0000\u0000\u00ec\u00ed\u0007\u0001\u0000\u0000\u00ed%\u0001\u0000"+ + "\u0000\u0000\u00ee\u00ef\u0005*\u0000\u0000\u00ef\u00f0\u0005(\u0000\u0000"+ + "\u00f0\u00f1\u0005)\u0000\u0000\u00f1\'\u0001\u0000\u0000\u0000\u00f2"+ + "\u00f3\u0007\u0002\u0000\u0000\u00f3)\u0001\u0000\u0000\u0000\u001b+/"+ + "27=DNW^dfmsy\u007f\u0084\u008a\u0099\u00a1\u00a8\u00b5\u00bf\u00c9\u00d0"+ + "\u00d2\u00d4\u00de"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/internal/grammar/XMLParserBase.java b/rewrite-xml/src/main/java/org/openrewrite/xml/internal/grammar/XMLParserBase.java index 21eca74350f..32dbec5f419 100644 --- a/rewrite-xml/src/main/java/org/openrewrite/xml/internal/grammar/XMLParserBase.java +++ b/rewrite-xml/src/main/java/org/openrewrite/xml/internal/grammar/XMLParserBase.java @@ -45,6 +45,16 @@ protected XMLParserBase(TokenStream input) { super(input); } + /** + * Gates the {@code element} rule so that strict XML keeps the plain two-alternative shape it had before void + * element support was added. The shape of the rule, not just which alternative matches, determines the + * resynchronization sets ANTLR's error recovery uses, so sharing one shape between the two modes would let + * HTML support alter how malformed XML recovers. + */ + public boolean isHtmlMode() { + return htmlMode; + } + public boolean isVoidElement(@Nullable String name) { return htmlMode && name != null && VOID_ELEMENTS.contains(name.toLowerCase()); } diff --git a/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java b/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java index d55a20d2a4c..b21c1e229cb 100755 --- a/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java +++ b/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java @@ -26,6 +26,7 @@ import org.openrewrite.ExecutionContext; import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.Issue; +import org.openrewrite.ParseExceptionResult; import org.openrewrite.Parser.Input; import org.openrewrite.SourceFile; import org.openrewrite.test.RecipeSpec; @@ -957,4 +958,65 @@ void malformedBareAmpersandDoesNotThrow() { assertThat(parsed).isInstanceOf(ParseError.class); assertThat(parsed.printAll()).isEqualTo("McFarland & Company"); } + + @Issue("https://github.com/openrewrite/rewrite/pull/7906") + @Test + void attributeValueWithUnescapedQuoteIsNotGivenAnExtraEquals() { + // The lexer ends a STRING at the first embedded quote, so the rest of the value re-lexes as more + // attributes. Error recovery must not synthesize an '=' for them, because the printer cannot tell a + // synthesized '=' from a real one and writes it back into the value. + SourceFile parsed = XmlParser.builder().build() + .parse(new InMemoryExecutionContext(t -> { + }), "") + .findFirst().orElseThrow(); + assertThat(parsed).isNotInstanceOf(ParseError.class); + assertThat(parsed.printAll()).isEqualTo(""); + } + + @Issue("https://github.com/openrewrite/rewrite/pull/7906") + @Test + void policyExpressionAttributeValueIsNeverRewritten() { + // Multi-line embedded expressions (e.g. Azure API Management policies) routinely carry unescaped + // quotes. Such a document is not well-formed XML, so a ParseError is correct -- but the text must + // come back byte for byte, never with an '=' inserted into a value. + @Language("xml") + String policy = """ + + + + + + """; + SourceFile parsed = XmlParser.builder().build() + .parse(new InMemoryExecutionContext(t -> { + }), policy) + .findFirst().orElseThrow(); + assertThat(parsed).isInstanceOf(ParseError.class); + assertThat(parsed.printAll()).isEqualTo(policy); + // "AAA," previously came back as "AAA=" from an '=' that error recovery invented. + assertThat(parseFailure(parsed)).doesNotContain("AAA="); + } + + @Issue("https://github.com/openrewrite/rewrite/pull/7906") + @Test + void nestedAttributeValueWithUnescapedQuoteAndAngleBracketDoesNotThrow() { + // Same input one level of nesting deeper, which previously reached visitAttribute with a null EQUALS + // token and threw a NullPointerException instead of falling back to a ParseError. + SourceFile parsed = XmlParser.builder().build() + .parse(new InMemoryExecutionContext(t -> { + }), "") + .findFirst().orElseThrow(); + assertThat(parsed).isInstanceOf(ParseError.class); + assertThat(parsed.printAll()).isEqualTo(""); + assertThat(parseFailure(parsed)).doesNotContain("NullPointerException"); + } + + private static String parseFailure(SourceFile parsed) { + return parsed.getMarkers().findFirst(ParseExceptionResult.class) + .orElseThrow().getMessage(); + } }