📄 parser.java
字号:
/*
* ExpressionBody ::= (Char* - (char* '%>')) '%>'
*/
private void parseExpression(Node parent) throws JasperException {
start = reader.mark();
Mark stop = reader.skipUntil("%>");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated", "<%=");
}
new Node.Expression(parseScriptText(reader.getText(start, stop)),
start, parent);
}
/*
* XMLExpressionBody ::= ( S? '/>' ) | ( S? '>' (Char* - (char* '<'))
* CDSect?)* ETag ) | <TRANSLATION_ERROR>
*/
private void parseXMLExpression(Node parent) throws JasperException {
reader.skipSpaces();
if (!reader.matches("/>")) {
if (!reader.matches(">")) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:expression>");
}
Mark stop;
String text;
while (true) {
start = reader.mark();
stop = reader.skipUntil("<");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:expression>");
}
text = parseScriptText(reader.getText(start, stop));
new Node.Expression(text, start, parent);
if (reader.matches("![CDATA[")) {
start = reader.mark();
stop = reader.skipUntil("]]>");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated", "CDATA");
}
text = parseScriptText(reader.getText(start, stop));
new Node.Expression(text, start, parent);
} else {
break;
}
}
if (!reader.matchesETagWithoutLessThan("jsp:expression")) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:expression>");
}
}
}
/*
* ELExpressionBody (following "${" to first unquoted "}") // XXX add formal
* production and confirm implementation against it, // once it's decided
*/
private void parseELExpression(Node parent, char type) throws JasperException {
start = reader.mark();
Mark last = null;
boolean singleQuoted = false, doubleQuoted = false;
int currentChar;
do {
// XXX could move this logic to JspReader
last = reader.mark(); // XXX somewhat wasteful
currentChar = reader.nextChar();
if (currentChar == '\\' && (singleQuoted || doubleQuoted)) {
// skip character following '\' within quotes
reader.nextChar();
currentChar = reader.nextChar();
}
if (currentChar == -1)
err.jspError(start, "jsp.error.unterminated", type + "{");
if (currentChar == '"')
doubleQuoted = !doubleQuoted;
if (currentChar == '\'')
singleQuoted = !singleQuoted;
} while (currentChar != '}' || (singleQuoted || doubleQuoted));
new Node.ELExpression(type, reader.getText(start, last), start, parent);
}
/*
* ScriptletBody ::= (Char* - (char* '%>')) '%>'
*/
private void parseScriptlet(Node parent) throws JasperException {
start = reader.mark();
Mark stop = reader.skipUntil("%>");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated", "<%");
}
new Node.Scriptlet(parseScriptText(reader.getText(start, stop)), start,
parent);
}
/*
* XMLScriptletBody ::= ( S? '/>' ) | ( S? '>' (Char* - (char* '<'))
* CDSect?)* ETag ) | <TRANSLATION_ERROR>
*/
private void parseXMLScriptlet(Node parent) throws JasperException {
reader.skipSpaces();
if (!reader.matches("/>")) {
if (!reader.matches(">")) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:scriptlet>");
}
Mark stop;
String text;
while (true) {
start = reader.mark();
stop = reader.skipUntil("<");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:scriptlet>");
}
text = parseScriptText(reader.getText(start, stop));
new Node.Scriptlet(text, start, parent);
if (reader.matches("![CDATA[")) {
start = reader.mark();
stop = reader.skipUntil("]]>");
if (stop == null) {
err.jspError(start, "jsp.error.unterminated", "CDATA");
}
text = parseScriptText(reader.getText(start, stop));
new Node.Scriptlet(text, start, parent);
} else {
break;
}
}
if (!reader.matchesETagWithoutLessThan("jsp:scriptlet")) {
err.jspError(start, "jsp.error.unterminated",
"<jsp:scriptlet>");
}
}
}
/**
* Param ::= '<jsp:param' S Attributes S? EmptyBody S?
*/
private void parseParam(Node parent) throws JasperException {
if (!reader.matches("<jsp:param")) {
err.jspError(reader.mark(), "jsp.error.paramexpected");
}
Attributes attrs = parseAttributes();
reader.skipSpaces();
Node paramActionNode = new Node.ParamAction(attrs, start, parent);
parseEmptyBody(paramActionNode, "jsp:param");
reader.skipSpaces();
}
/*
* For Include: StdActionContent ::= Attributes ParamBody
*
* ParamBody ::= EmptyBody | ( '>' S? ( '<jsp:attribute' NamedAttributes )? '<jsp:body'
* (JspBodyParam | <TRANSLATION_ERROR> ) S? ETag ) | ( '>' S? Param* ETag )
*
* EmptyBody ::= '/>' | ( '>' ETag ) | ( '>' S? '<jsp:attribute'
* NamedAttributes ETag )
*
* JspBodyParam ::= S? '>' Param* '</jsp:body>'
*/
private void parseInclude(Node parent) throws JasperException {
Attributes attrs = parseAttributes();
reader.skipSpaces();
Node includeNode = new Node.IncludeAction(attrs, start, parent);
parseOptionalBody(includeNode, "jsp:include", JAVAX_BODY_CONTENT_PARAM);
}
/*
* For Forward: StdActionContent ::= Attributes ParamBody
*/
private void parseForward(Node parent) throws JasperException {
Attributes attrs = parseAttributes();
reader.skipSpaces();
Node forwardNode = new Node.ForwardAction(attrs, start, parent);
parseOptionalBody(forwardNode, "jsp:forward", JAVAX_BODY_CONTENT_PARAM);
}
private void parseInvoke(Node parent) throws JasperException {
Attributes attrs = parseAttributes();
reader.skipSpaces();
Node invokeNode = new Node.InvokeAction(attrs, start, parent);
parseEmptyBody(invokeNode, "jsp:invoke");
}
private void parseDoBody(Node parent) throws JasperException {
Attributes attrs = parseAttributes();
reader.skipSpaces();
Node doBodyNode = new Node.DoBodyAction(attrs, start, parent);
parseEmptyBody(doBodyNode, "jsp:doBody");
}
private void parseElement(Node parent) throws JasperException {
Attributes attrs = parseAttributes();
reader.skipSpaces();
Node elementNode = new Node.JspElement(attrs, start, parent);
parseOptionalBody(elementNode, "jsp:element", TagInfo.BODY_CONTENT_JSP);
}
/*
* For GetProperty: StdActionContent ::= Attributes EmptyBody
*/
private void parseGetProperty(Node parent) throws JasperException {
Attributes attrs = parseAttributes();
reader.skipSpaces();
Node getPropertyNode = new Node.GetProperty(attrs, start, parent);
parseOptionalBody(getPropertyNode, "jsp:getProperty",
TagInfo.BODY_CONTENT_EMPTY);
}
/*
* For SetProperty: StdActionContent ::= Attributes EmptyBody
*/
private void parseSetProperty(Node parent) throws JasperException {
Attributes attrs = parseAttributes();
reader.skipSpaces();
Node setPropertyNode = new Node.SetProperty(attrs, start, parent);
parseOptionalBody(setPropertyNode, "jsp:setProperty",
TagInfo.BODY_CONTENT_EMPTY);
}
/*
* EmptyBody ::= '/>' | ( '>' ETag ) | ( '>' S? '<jsp:attribute'
* NamedAttributes ETag )
*/
private void parseEmptyBody(Node parent, String tag) throws JasperException {
if (reader.matches("/>")) {
// Done
} else if (reader.matches(">")) {
if (reader.matchesETag(tag)) {
// Done
} else if (reader.matchesOptionalSpacesFollowedBy("<jsp:attribute")) {
// Parse the one or more named attribute nodes
parseNamedAttributes(parent);
if (!reader.matchesETag(tag)) {
// Body not allowed
err.jspError(reader.mark(),
"jsp.error.jspbody.emptybody.only", "<" + tag);
}
} else {
err.jspError(reader.mark(), "jsp.error.jspbody.emptybody.only",
"<" + tag);
}
} else {
err.jspError(reader.mark(), "jsp.error.unterminated", "<" + tag);
}
}
/*
* For UseBean: StdActionContent ::= Attributes OptionalBody
*/
private void parseUseBean(Node parent) throws JasperException {
Attributes attrs = parseAttributes();
reader.skipSpaces();
Node useBeanNode = new Node.UseBean(attrs, start, parent);
parseOptionalBody(useBeanNode, "jsp:useBean", TagInfo.BODY_CONTENT_JSP);
}
/*
* Parses OptionalBody, but also reused to parse bodies for plugin and param
* since the syntax is identical (the only thing that differs substantially
* is how to process the body, and thus we accept the body type as a
* parameter).
*
* OptionalBody ::= EmptyBody | ActionBody
*
* ScriptlessOptionalBody ::= EmptyBody | ScriptlessActionBody
*
* TagDependentOptionalBody ::= EmptyBody | TagDependentActionBody
*
* EmptyBody ::= '/>' | ( '>' ETag ) | ( '>' S? '<jsp:attribute'
* NamedAttributes ETag )
*
* ActionBody ::= JspAttributeAndBody | ( '>' Body ETag )
*
* ScriptlessActionBody ::= JspAttributeAndBody | ( '>' ScriptlessBody ETag )
*
* TagDependentActionBody ::= JspAttributeAndBody | ( '>' TagDependentBody
* ETag )
*
*/
private void parseOptionalBody(Node parent, String tag, String bodyType)
throws JasperException {
if (reader.matches("/>")) {
// EmptyBody
return;
}
if (!reader.matches(">")) {
err.jspError(reader.mark(), "jsp.error.unterminated", "<" + tag);
}
if (reader.matchesETag(tag)) {
// EmptyBody
return;
}
if (!parseJspAttributeAndBody(parent, tag, bodyType)) {
// Must be ( '>' # Body ETag )
parseBody(parent, tag, bodyType);
}
}
/**
* Attempts to parse 'JspAttributeAndBody' production. Returns true if it
* matched, or false if not. Assumes EmptyBody is okay as well.
*
* JspAttributeAndBody ::= ( '>' # S? ( '<jsp:attribute' NamedAttributes )? '<jsp:body' (
* JspBodyBody | <TRANSLATION_ERROR> ) S? ETag )
*/
private boolean parseJspAttributeAndBody(Node parent, String tag,
String bodyType) throws JasperException {
boolean result = false;
if (reader.matchesOptionalSpacesFollowedBy("<jsp:attribute")) {
// May be an EmptyBody, depending on whether
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -