Skip to content

Commit f5b00eb

Browse files
timtebeekclaude
andauthored
Extend JSP parser to support scriptlets, expressions, declarations, and comments (#6054)
* feat(xml): Add lexer tokens for JSP scriptlets, expressions, declarations, and comments Added new lexer tokens to XMLLexer.g4: - JSP_COMMENT for <%-- comment --%> - JSP_DECLARATION for <%! declarations %> - JSP_EXPRESSION for <%= expressions %> - JSP_SCRIPTLET for <% scriptlets %> These tokens enable parsing of JSP-specific elements beyond the currently supported directives. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat(xml): Update parser grammar to recognize JSP elements Extended XMLParser.g4 to include grammar rules for: - jspscriptlet for <% scriptlets %> - jspexpression for <%= expressions %> - jspdeclaration for <%! declarations %> - jspcomment for <%-- comments --%> Also updated content rule to include these new JSP elements as valid content types. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat(xml): Add AST classes for JSP scriptlets, expressions, declarations, and comments Added four new AST node classes to represent JSP elements: - JspScriptlet for <% Java code %> - JspExpression for <%= expression %> - JspDeclaration for <%! declaration %> - JspComment for <%-- comment --%> Each class implements Xml and Content interfaces with proper prefix handling, visitor pattern support, and toString implementations. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat(xml): Implement parser visitor methods for JSP elements Added visitor methods in XmlParserVisitor to handle parsing of: - visitJspscriptlet() for <% scriptlets %> - visitJspexpression() for <%= expressions %> - visitJspdeclaration() for <%! declarations %> - visitJspcomment() for <%-- comments --%> Each method extracts the content from the JSP tags and creates the corresponding AST node. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat(xml): Add visitor methods for JSP elements in XmlVisitor Added visitor methods to handle traversal of new JSP AST nodes: - visitJspScriptlet() for JspScriptlet nodes - visitJspExpression() for JspExpression nodes - visitJspDeclaration() for JspDeclaration nodes - visitJspComment() for JspComment nodes 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * feat(xml): Add printer methods for JSP elements Implemented printing support for new JSP AST nodes: - visitJspScriptlet() prints <% content %> - visitJspExpression() prints <%= content %> - visitJspDeclaration() prints <%! content %> - visitJspComment() prints <%-- content --%> This ensures proper round-trip parsing and printing of JSP elements. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * test(xml): Add comprehensive tests for JSP element parsing Added test cases for all new JSP elements: - jspScriptlet() tests <% scriptlet %> parsing - jspExpression() tests <%= expression %> parsing - jspDeclaration() tests <%! declaration %> parsing - jspComment() tests <%-- comment --%> parsing - mixedJspElements() tests various JSP elements together These tests verify proper parsing and round-trip printing of JSP-specific syntax. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(xml): Fix JSP parsing issues - preserve whitespace and allow in prolog - Preserve all whitespace in JSP content (don't strip leading spaces) - Allow JspDeclaration and JspComment as Misc items in prolog - Fix lexer regex to properly exclude JSP comment pattern from scriptlet - Update AST classes to implement Misc interface where appropriate This allows JSP declarations to appear after DOCTYPE and before root element, and preserves exact formatting of JSP content. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(xml): Update XmlParserVisitor to handle JSP elements in misc Added handling for jspdeclaration and jspcomment in visitMisc method so they can be properly parsed when appearing in the prolog after DOCTYPE. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(xml): Allow JSP directives and misc items to be interspersed in prolog - Updated grammar to use prologContent rule that allows misc and jspdirective in any order in the prolog - Modified XmlParserVisitor to handle flexible prolog content ordering - Adjusted test to reflect valid JSP structure This allows more flexible JSP file structures where declarations and directives can appear in any order after DOCTYPE. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(xml): Prevent XmlDecl from being duplicated in prolog XmlDecl implements both Xml and Misc interfaces, which was causing it to be included twice in the prolog when processing prologContent. Added check to skip XmlDecl when collecting misc items since it's handled separately. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Update headers * Apply best practices * fix(xml): Revert prolog grammar changes to fix duplicate XmlDecl issue The flexible prologContent approach was causing XmlDecl to be printed twice. Reverted to the original prolog structure with misc* jspdirective* which properly separates these elements. JSP declarations and comments are still supported as Misc items within content areas. Also moved JSP declaration in test to content area where it belongs. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Update headers & apply best practices --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent caa9585 commit f5b00eb

17 files changed

Lines changed: 1421 additions & 546 deletions

rewrite-xml/src/main/antlr/XMLLexer.g4

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ SPECIAL_OPEN : '<' QUESTION_MARK Name -> pushMode(INSIDE_PROCESS_IN
5252

5353
DTD_OPEN : '<!' -> pushMode(INSIDE_DTD) ;
5454

55+
// JSP elements
56+
JSP_COMMENT : '<%--' .*? '--%>' ;
57+
JSP_DECLARATION : '<%!' .*? '%>' ;
58+
JSP_EXPRESSION : '<%=' .*? '%>' ;
59+
JSP_SCRIPTLET : '<%' ~[@=!-] .*? '%>' ; // Matches <% but not <%@, <%=, <%!, or <%--
60+
5561
TEXT : ~[<&]+ ; // match any 16 bit char other than < and &
5662

5763
fragment

rewrite-xml/src/main/antlr/XMLParser.g4

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ xmldecl
4444
;
4545

4646
misc
47-
: (COMMENT | doctypedecl | processinginstruction)
47+
: (COMMENT | doctypedecl | processinginstruction | jspdeclaration | jspcomment)
4848
;
4949

5050
doctypedecl
@@ -73,7 +73,8 @@ processinginstruction
7373
;
7474

7575
content
76-
: (element | reference | processinginstruction | CDATA | COMMENT | chardata) ;
76+
: (element | reference | processinginstruction | CDATA | COMMENT |
77+
jspscriptlet | jspexpression | jspdeclaration | jspcomment | chardata) ;
7778

7879
element
7980
: OPEN Name attribute* CLOSE content* OPEN '/' Name CLOSE
@@ -84,6 +85,22 @@ jspdirective
8485
: OPEN DIRECTIVE_OPEN Name attribute* DIRECTIVE_CLOSE CLOSE
8586
;
8687

88+
jspscriptlet
89+
: JSP_SCRIPTLET
90+
;
91+
92+
jspexpression
93+
: JSP_EXPRESSION
94+
;
95+
96+
jspdeclaration
97+
: JSP_DECLARATION
98+
;
99+
100+
jspcomment
101+
: JSP_COMMENT
102+
;
103+
87104
reference
88105
: (EntityRef | CharRef) ;
89106

rewrite-xml/src/main/java/org/openrewrite/xml/XmlVisitor.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,20 @@ public Xml visitJspDirective(Xml.JspDirective jspDirective, P p) {
149149
j = j.withMarkers(visitMarkers(j.getMarkers(), p));
150150
return j.withAttributes(ListUtils.map(j.getAttributes(), a -> visitAndCast(a, p)));
151151
}
152+
153+
public Xml visitJspScriptlet(Xml.JspScriptlet jspScriptlet, P p) {
154+
return jspScriptlet.withMarkers(visitMarkers(jspScriptlet.getMarkers(), p));
155+
}
156+
157+
public Xml visitJspExpression(Xml.JspExpression jspExpression, P p) {
158+
return jspExpression.withMarkers(visitMarkers(jspExpression.getMarkers(), p));
159+
}
160+
161+
public Xml visitJspDeclaration(Xml.JspDeclaration jspDeclaration, P p) {
162+
return jspDeclaration.withMarkers(visitMarkers(jspDeclaration.getMarkers(), p));
163+
}
164+
165+
public Xml visitJspComment(Xml.JspComment jspComment, P p) {
166+
return jspComment.withMarkers(visitMarkers(jspComment.getMarkers(), p));
167+
}
152168
}

rewrite-xml/src/main/java/org/openrewrite/xml/internal/XmlParserVisitor.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ public Xml visitMisc(XMLParser.MiscContext ctx) {
9696
prefix,
9797
Markers.EMPTY,
9898
comment.getText().substring("<!--".length(), comment.getText().length() - "-->".length())));
99+
} else if (ctx.jspdeclaration() != null) {
100+
return visitJspdeclaration(ctx.jspdeclaration());
101+
} else if (ctx.jspcomment() != null) {
102+
return visitJspcomment(ctx.jspcomment());
99103
} else {
100104
return super.visitMisc(ctx);
101105
}
@@ -245,6 +249,70 @@ public Xml visitJspdirective(XMLParser.JspdirectiveContext ctx) {
245249
});
246250
}
247251

252+
@Override
253+
public Xml visitJspscriptlet(XMLParser.JspscriptletContext ctx) {
254+
return convert(ctx, (c, prefix) -> {
255+
String scriptletText = ctx.JSP_SCRIPTLET().getText();
256+
// Extract content between <% and %>, preserving all whitespace
257+
String content = scriptletText.substring(2, scriptletText.length() - 2);
258+
259+
return new Xml.JspScriptlet(
260+
randomId(),
261+
prefix,
262+
Markers.EMPTY,
263+
content
264+
);
265+
});
266+
}
267+
268+
@Override
269+
public Xml visitJspexpression(XMLParser.JspexpressionContext ctx) {
270+
return convert(ctx, (c, prefix) -> {
271+
String expressionText = ctx.JSP_EXPRESSION().getText();
272+
// Extract content between <%= and %>, preserving all whitespace
273+
String content = expressionText.substring(3, expressionText.length() - 2);
274+
275+
return new Xml.JspExpression(
276+
randomId(),
277+
prefix,
278+
Markers.EMPTY,
279+
content
280+
);
281+
});
282+
}
283+
284+
@Override
285+
public Xml visitJspdeclaration(XMLParser.JspdeclarationContext ctx) {
286+
return convert(ctx, (c, prefix) -> {
287+
String declarationText = ctx.JSP_DECLARATION().getText();
288+
// Extract content between <%! and %>, preserving all whitespace
289+
String content = declarationText.substring(3, declarationText.length() - 2);
290+
291+
return new Xml.JspDeclaration(
292+
randomId(),
293+
prefix,
294+
Markers.EMPTY,
295+
content
296+
);
297+
});
298+
}
299+
300+
@Override
301+
public Xml visitJspcomment(XMLParser.JspcommentContext ctx) {
302+
return convert(ctx, (c, prefix) -> {
303+
String commentText = ctx.JSP_COMMENT().getText();
304+
// Extract content between <%-- and --%>, preserving all whitespace
305+
String content = commentText.substring(4, commentText.length() - 4);
306+
307+
return new Xml.JspComment(
308+
randomId(),
309+
prefix,
310+
Markers.EMPTY,
311+
content
312+
);
313+
});
314+
}
315+
248316
@Override
249317
public Xml.Tag visitElement(XMLParser.ElementContext ctx) {
250318
return convert(ctx, (c, prefix) -> {

rewrite-xml/src/main/java/org/openrewrite/xml/internal/XmlPrinter.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,46 @@ public Xml visitJspDirective(Xml.JspDirective jsp, PrintOutputCapture<P> p) {
206206
return jsp;
207207
}
208208

209+
@Override
210+
public Xml visitJspScriptlet(Xml.JspScriptlet jsp, PrintOutputCapture<P> p) {
211+
beforeSyntax(jsp, p);
212+
p.append("<%");
213+
p.append(jsp.getContent());
214+
p.append("%>");
215+
afterSyntax(jsp, p);
216+
return jsp;
217+
}
218+
219+
@Override
220+
public Xml visitJspExpression(Xml.JspExpression jsp, PrintOutputCapture<P> p) {
221+
beforeSyntax(jsp, p);
222+
p.append("<%=");
223+
p.append(jsp.getContent());
224+
p.append("%>");
225+
afterSyntax(jsp, p);
226+
return jsp;
227+
}
228+
229+
@Override
230+
public Xml visitJspDeclaration(Xml.JspDeclaration jsp, PrintOutputCapture<P> p) {
231+
beforeSyntax(jsp, p);
232+
p.append("<%!");
233+
p.append(jsp.getContent());
234+
p.append("%>");
235+
afterSyntax(jsp, p);
236+
return jsp;
237+
}
238+
239+
@Override
240+
public Xml visitJspComment(Xml.JspComment jsp, PrintOutputCapture<P> p) {
241+
beforeSyntax(jsp, p);
242+
p.append("<%--");
243+
p.append(jsp.getContent());
244+
p.append("--%>");
245+
afterSyntax(jsp, p);
246+
return jsp;
247+
}
248+
209249
private static final UnaryOperator<String> XML_MARKER_WRAPPER =
210250
out -> "<!--~~" + out + (out.isEmpty() ? "" : "~~") + ">-->";
211251

rewrite-xml/src/main/java/org/openrewrite/xml/internal/grammar/XMLLexer.interp

Lines changed: 13 additions & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)