KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jasper > compiler > ELParser


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.jasper.compiler;
19
20 /**
21  * This class implements a parser for EL expressions.
22  *
23  * It takes strings of the form xxx${..}yyy${..}zzz etc, and turn it into a
24  * ELNode.Nodes.
25  *
26  * Currently, it only handles text outside ${..} and functions in ${ ..}.
27  *
28  * @author Kin-man Chung
29  */

30
31 public class ELParser {
32
33     private Token curToken; // current token
34

35     private ELNode.Nodes expr;
36
37     private ELNode.Nodes ELexpr;
38
39     private int index; // Current index of the expression
40

41     private String JavaDoc expression; // The EL expression
42

43     private char type;
44
45     private boolean escapeBS; // is '\' an escape char in text outside EL?
46

47     private static final String JavaDoc reservedWords[] = { "and", "div", "empty",
48             "eq", "false", "ge", "gt", "instanceof", "le", "lt", "mod", "ne",
49             "not", "null", "or", "true" };
50
51     public ELParser(String JavaDoc expression) {
52         index = 0;
53         this.expression = expression;
54         expr = new ELNode.Nodes();
55     }
56
57     /**
58      * Parse an EL expression
59      *
60      * @param expression
61      * The input expression string of the form Char* ('${' Char*
62      * '}')* Char*
63      * @return Parsed EL expression in ELNode.Nodes
64      */

65     public static ELNode.Nodes parse(String JavaDoc expression) {
66         ELParser parser = new ELParser(expression);
67         while (parser.hasNextChar()) {
68             String JavaDoc text = parser.skipUntilEL();
69             if (text.length() > 0) {
70                 parser.expr.add(new ELNode.Text(text));
71             }
72             ELNode.Nodes elexpr = parser.parseEL();
73             if (!elexpr.isEmpty()) {
74                 parser.expr.add(new ELNode.Root(elexpr, parser.type));
75             }
76         }
77         return parser.expr;
78     }
79
80     /**
81      * Parse an EL expression string '${...}'
82      *
83      * @return An ELNode.Nodes representing the EL expression TODO: Currently
84      * only parsed into functions and text strings. This should be
85      * rewritten for a full parser.
86      */

87     private ELNode.Nodes parseEL() {
88
89         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
90         ELexpr = new ELNode.Nodes();
91         while (hasNext()) {
92             curToken = nextToken();
93             if (curToken instanceof Char) {
94                 if (curToken.toChar() == '}') {
95                     break;
96                 }
97                 buf.append(curToken.toChar());
98             } else {
99                 // Output whatever is in buffer
100
if (buf.length() > 0) {
101                     ELexpr.add(new ELNode.ELText(buf.toString()));
102                 }
103                 if (!parseFunction()) {
104                     ELexpr.add(new ELNode.ELText(curToken.toString()));
105                 }
106             }
107         }
108         if (buf.length() > 0) {
109             ELexpr.add(new ELNode.ELText(buf.toString()));
110         }
111
112         return ELexpr;
113     }
114
115     /**
116      * Parse for a function FunctionInvokation ::= (identifier ':')? identifier
117      * '(' (Expression (,Expression)*)? ')' Note: currently we don't parse
118      * arguments
119      */

120     private boolean parseFunction() {
121         if (!(curToken instanceof Id) || isELReserved(curToken.toString())) {
122             return false;
123         }
124         String JavaDoc s1 = null; // Function prefix
125
String JavaDoc s2 = curToken.toString(); // Function name
126
int mark = getIndex();
127         if (hasNext()) {
128             Token t = nextToken();
129             if (t.toChar() == ':') {
130                 if (hasNext()) {
131                     Token t2 = nextToken();
132                     if (t2 instanceof Id) {
133                         s1 = s2;
134                         s2 = t2.toString();
135                         if (hasNext()) {
136                             t = nextToken();
137                         }
138                     }
139                 }
140             }
141             if (t.toChar() == '(') {
142                 ELexpr.add(new ELNode.Function(s1, s2));
143                 return true;
144             }
145         }
146         setIndex(mark);
147         return false;
148     }
149
150     /**
151      * Test if an id is a reserved word in EL
152      */

153     private boolean isELReserved(String JavaDoc id) {
154         int i = 0;
155         int j = reservedWords.length;
156         while (i < j) {
157             int k = (i + j) / 2;
158             int result = reservedWords[k].compareTo(id);
159             if (result == 0) {
160                 return true;
161             }
162             if (result < 0) {
163                 i = k + 1;
164             } else {
165                 j = k;
166             }
167         }
168         return false;
169     }
170
171     /**
172      * Skip until an EL expression ('${' || '#{') is reached, allowing escape
173      * sequences '\\' and '\$' and '\#'.
174      *
175      * @return The text string up to the EL expression
176      */

177     private String JavaDoc skipUntilEL() {
178         char prev = 0;
179         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
180         while (hasNextChar()) {
181             char ch = nextChar();
182             if (prev == '\\') {
183                 prev = 0;
184                 if (ch == '\\') {
185                     buf.append('\\');
186                     if (!escapeBS)
187                         prev = '\\';
188                 } else if (ch == '$' || ch == '#') {
189                     buf.append(ch);
190                 }
191                 // else error!
192
} else if (prev == '$' || prev == '#') {
193                 if (ch == '{') {
194                     this.type = prev;
195                     prev = 0;
196                     break;
197                 }
198                 buf.append(prev);
199                 prev = 0;
200             }
201             if (ch == '\\' || ch == '$' || ch == '#') {
202                 prev = ch;
203             } else {
204                 buf.append(ch);
205             }
206         }
207         if (prev != 0) {
208             buf.append(prev);
209         }
210         return buf.toString();
211     }
212
213     /*
214      * @return true if there is something left in EL expression buffer other
215      * than white spaces.
216      */

217     private boolean hasNext() {
218         skipSpaces();
219         return hasNextChar();
220     }
221
222     /*
223      * @return The next token in the EL expression buffer.
224      */

225     private Token nextToken() {
226         skipSpaces();
227         if (hasNextChar()) {
228             char ch = nextChar();
229             if (Character.isJavaIdentifierStart(ch)) {
230                 StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
231                 buf.append(ch);
232                 while ((ch = peekChar()) != -1
233                         && Character.isJavaIdentifierPart(ch)) {
234                     buf.append(ch);
235                     nextChar();
236                 }
237                 return new Id(buf.toString());
238             }
239
240             if (ch == '\'' || ch == '"') {
241                 return parseQuotedChars(ch);
242             } else {
243                 // For now...
244
return new Char(ch);
245             }
246         }
247         return null;
248     }
249
250     /*
251      * Parse a string in single or double quotes, allowing for escape sequences
252      * '\\', and ('\"', or "\'")
253      */

254     private Token parseQuotedChars(char quote) {
255         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
256         buf.append(quote);
257         while (hasNextChar()) {
258             char ch = nextChar();
259             if (ch == '\\') {
260                 ch = nextChar();
261                 if (ch == '\\' || ch == quote) {
262                     buf.append(ch);
263                 }
264                 // else error!
265
} else if (ch == quote) {
266                 buf.append(ch);
267                 break;
268             } else {
269                 buf.append(ch);
270             }
271         }
272         return new QuotedString(buf.toString());
273     }
274
275     /*
276      * A collection of low level parse methods dealing with character in the EL
277      * expression buffer.
278      */

279
280     private void skipSpaces() {
281         while (hasNextChar()) {
282             if (expression.charAt(index) > ' ')
283                 break;
284             index++;
285         }
286     }
287
288     private boolean hasNextChar() {
289         return index < expression.length();
290     }
291
292     private char nextChar() {
293         if (index >= expression.length()) {
294             return (char) -1;
295         }
296         return expression.charAt(index++);
297     }
298
299     private char peekChar() {
300         if (index >= expression.length()) {
301             return (char) -1;
302         }
303         return expression.charAt(index);
304     }
305
306     private int getIndex() {
307         return index;
308     }
309
310     private void setIndex(int i) {
311         index = i;
312     }
313
314     /*
315      * Represents a token in EL expression string
316      */

317     private static class Token {
318
319         char toChar() {
320             return 0;
321         }
322
323         public String JavaDoc toString() {
324             return "";
325         }
326     }
327
328     /*
329      * Represents an ID token in EL
330      */

331     private static class Id extends Token {
332         String JavaDoc id;
333
334         Id(String JavaDoc id) {
335             this.id = id;
336         }
337
338         public String JavaDoc toString() {
339             return id;
340         }
341     }
342
343     /*
344      * Represents a character token in EL
345      */

346     private static class Char extends Token {
347
348         private char ch;
349
350         Char(char ch) {
351             this.ch = ch;
352         }
353
354         char toChar() {
355             return ch;
356         }
357
358         public String JavaDoc toString() {
359             return (new Character JavaDoc(ch)).toString();
360         }
361     }
362
363     /*
364      * Represents a quoted (single or double) string token in EL
365      */

366     private static class QuotedString extends Token {
367
368         private String JavaDoc value;
369
370         QuotedString(String JavaDoc v) {
371             this.value = v;
372         }
373
374         public String JavaDoc toString() {
375             return value;
376         }
377     }
378
379     public char getType() {
380         return type;
381     }
382 }
383
Popular Tags