/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.
*/ package org.apache.jasper.compiler;
/** * This class implements a parser for EL expressions. * * It takes strings of the form xxx${..}yyy${..}zzz etc, and turn it into a * ELNode.Nodes. * * Currently, it only handles text outside ${..} and functions in ${ ..}. * * @author Kin-man Chung
*/
public ELParser(String expression, boolean isDeferredSyntaxAllowedAsLiteral) {
index = 0; this.expression = expression; this.isDeferredSyntaxAllowedAsLiteral = isDeferredSyntaxAllowedAsLiteral;
expr = new ELNode.Nodes();
}
/** * Parse an EL expression * * @param expression * The input expression string of the form Char* ('${' Char* * '}')* Char* * @param isDeferredSyntaxAllowedAsLiteral * Are deferred expressions treated as literals? * @return Parsed EL expression in ELNode.Nodes
*/ publicstatic ELNode.Nodes parse(String expression, boolean isDeferredSyntaxAllowedAsLiteral) {
ELParser parser = new ELParser(expression,
isDeferredSyntaxAllowedAsLiteral); while (parser.hasNextChar()) {
String text = parser.skipUntilEL(); if (text.length() > 0) {
parser.expr.add(new ELNode.Text(text));
}
ELNode.Nodes elexpr = parser.parseEL(); if (!elexpr.isEmpty()) {
parser.expr.add(new ELNode.Root(elexpr, parser.type));
}
} return parser.expr;
}
/** * Parse an EL expression string '${...}'. Currently only separates the EL * into functions and everything else. * * @return An ELNode.Nodes representing the EL expression * * Note: This cannot be refactored to use the standard EL implementation as * the EL API does not provide the level of access required to the * parsed expression.
*/ private ELNode.Nodes parseEL() {
StringBuilder buf = new StringBuilder();
ELexpr = new ELNode.Nodes();
curToken = null;
prevToken = null; int openBraces = 0; while (hasNext()) {
curToken = nextToken(); if (curToken instanceofChar) { if (curToken.toChar() == '}') {
openBraces--; if (openBraces < 0) { break;
}
} elseif (curToken.toChar() == '{') {
openBraces++;
}
buf.append(curToken.toString());
} else { // Output whatever is in buffer if (buf.length() > 0) {
ELexpr.add(new ELNode.ELText(buf.toString()));
buf.setLength(0);
} if (!parseFunction()) {
ELexpr.add(new ELNode.ELText(curToken.toString()));
}
}
} if (curToken != null) {
buf.append(curToken.getWhiteSpace());
} if (buf.length() > 0) {
ELexpr.add(new ELNode.ELText(buf.toString()));
}
return ELexpr;
}
/** * Parse for a function FunctionInvocation ::= (identifier ':')? identifier * '(' (Expression (,Expression)*)? ')' Note: currently we don't parse * arguments
*/ privateboolean parseFunction() { if (!(curToken instanceof Id) || isELReserved(curToken.toTrimmedString()) ||
prevToken instanceofChar && prevToken.toChar() == '.') { returnfalse;
}
String s1 = null; // Function prefix
String s2 = curToken.toTrimmedString(); // Function name int start = index - curToken.toString().length();
Token original = curToken; if (hasNext()) { int mark = getIndex() - whiteSpace.length();
curToken = nextToken(); if (curToken.toChar() == ':') { if (hasNext()) {
Token t2 = nextToken(); if (t2 instanceof Id) {
s1 = s2;
s2 = t2.toTrimmedString(); if (hasNext()) {
curToken = nextToken();
}
}
}
} if (curToken.toChar() == '(') {
ELexpr.add(new ELNode.Function(s1, s2, expression.substring(start, index - 1))); returntrue;
}
curToken = original;
setIndex(mark);
} returnfalse;
}
/** * Test if an id is a reserved word in EL
*/ privateboolean isELReserved(String id) { int i = 0; int j = reservedWords.length; while (i < j) { int k = (i + j) >>> 1; int result = reservedWords[k].compareTo(id); if (result == 0) { returntrue;
} if (result < 0) {
i = k + 1;
} else {
j = k;
}
} returnfalse;
}
/** * Skip until an EL expression ('${' || '#{') is reached, allowing escape * sequences '\$' and '\#'. * * @return The text string up to the EL expression
*/ private String skipUntilEL() {
StringBuilder buf = new StringBuilder(); while (hasNextChar()) { char ch = nextChar(); if (ch == '\\') { // Is this the start of a "\$" or "\#" escape sequence? char p0 = peek(0); if (p0 == '$' || (p0 == '#' && !isDeferredSyntaxAllowedAsLiteral)) {
buf.append(nextChar());
} else {
buf.append(ch);
}
} elseif ((ch == '$' || (ch == '#' && !isDeferredSyntaxAllowedAsLiteral)) &&
peek(0) == '{') { this.type = ch;
nextChar(); break;
} else {
buf.append(ch);
}
} return buf.toString();
}
/** * Escape '$' and '#', inverting the unescaping performed in * {@link #skipUntilEL()} but only for ${ and #{ sequences since escaping * for $ and # is optional. * * @param input Non-EL input to be escaped * @param isDeferredSyntaxAllowedAsLiteral Flag that indicates if deferred * syntax (#{) is allowed as a literal.\ * * @return The escaped version of the input
*/ static String escapeLiteralExpression(String input, boolean isDeferredSyntaxAllowedAsLiteral) { int len = input.length(); int lastAppend = 0;
StringBuilder output = null; for (int i = 0; i < len; i++) { char ch = input.charAt(i); if (ch =='$' || (!isDeferredSyntaxAllowedAsLiteral && ch == '#')) { if (i + 1 < len && input.charAt(i + 1) == '{') { if (output == null) {
output = new StringBuilder(len + 20);
}
output.append(input.substring(lastAppend, i));
lastAppend = i + 1;
output.append('\\');
output.append(ch);
}
}
} if (output == null) { return input;
} else {
output.append(input.substring(lastAppend, len)); return output.toString();
}
}
/** * Escape '\\', '\'' and '\"', inverting the unescaping performed in * {@link #skipUntilEL()}. * * @param input Non-EL input to be escaped * * @return The escaped version of the input
*/ privatestatic String escapeELText(String input) { int len = input.length(); char quote = 0; int lastAppend = 0; int start = 0; int end = len;
// Look to see if the value is quoted
String trimmed = input.trim(); int trimmedLen = trimmed.length(); if (trimmedLen > 1) { // Might be quoted
quote = trimmed.charAt(0); if (quote == '\'' || quote == '\"') { if (trimmed.charAt(trimmedLen - 1) != quote) { thrownew IllegalArgumentException(Localizer.getMessage( "org.apache.jasper.compiler.ELParser.invalidQuotesForStringLiteral",
input));
}
start = input.indexOf(quote) + 1;
end = start + trimmedLen - 2;
} else {
quote = 0;
}
}
StringBuilder output = null; for (int i = start; i < end; i++) { char ch = input.charAt(i); if (ch == '\\' || ch == quote) { if (output == null) {
output = new StringBuilder(len + 20);
}
output.append(input.substring(lastAppend, i));
lastAppend = i + 1;
output.append('\\');
output.append(ch);
}
} if (output == null) { return input;
} else {
output.append(input.substring(lastAppend, len)); return output.toString();
}
}
/* * @return true if there is something left in EL expression buffer other * than white spaces.
*/ privateboolean hasNext() {
skipSpaces(); return hasNextChar();
}
/* * Implementation note: This method assumes that it is always preceded by a * call to hasNext() in order for whitespace handling to be correct. * * @return The next token in the EL expression buffer.
*/ private Token nextToken() {
prevToken = curToken; if (hasNextChar()) { char ch = nextChar(); if (Character.isJavaIdentifierStart(ch)) { int start = index - 1; while (index < expression.length() &&
Character.isJavaIdentifierPart(
ch = expression.charAt(index))) {
nextChar();
} returnnew Id(getAndResetWhiteSpace(), expression.substring(start, index));
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.