KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > j > JavaFormatter


1 /*
2  * JavaFormatter.java
3  *
4  * Copyright (C) 1998-2004 Peter Graves
5  * $Id: JavaFormatter.java,v 1.3 2004/02/28 17:59:08 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

21
22 package org.armedbear.j;
23
24 public final class JavaFormatter extends Formatter implements Constants
25 {
26     private static final int JAVA_FORMAT_TEXT = 0;
27     private static final int JAVA_FORMAT_COMMENT = 1;
28     private static final int JAVA_FORMAT_STRING = 2;
29     private static final int JAVA_FORMAT_IDENTIFIER = 3;
30     private static final int JAVA_FORMAT_KEYWORD = 4;
31     private static final int JAVA_FORMAT_FUNCTION = 5;
32     private static final int JAVA_FORMAT_OPERATOR = 6;
33     private static final int JAVA_FORMAT_BRACE = 7;
34     private static final int JAVA_FORMAT_NUMBER = 8;
35
36     public static final int JAVA_FORMAT_LAST = 8;
37
38     private final int language;
39
40     public JavaFormatter(Buffer buffer)
41     {
42         this(buffer, LANGUAGE_JAVA);
43     }
44
45     public JavaFormatter(Buffer buffer, int language)
46     {
47         this.buffer = buffer;
48         this.language = language;
49     }
50
51     private int tokenBegin = 0;
52
53     private void endToken(String JavaDoc text, int tokenEnd, int state)
54     {
55         if (tokenEnd - tokenBegin > 0) {
56             int format = JAVA_FORMAT_TEXT;
57             switch (state) {
58                 case STATE_NEUTRAL:
59                     format = JAVA_FORMAT_TEXT;
60                     break;
61                 case STATE_QUOTE:
62                     format = JAVA_FORMAT_STRING;
63                     break;
64                 case STATE_IDENTIFIER:
65                     format = JAVA_FORMAT_IDENTIFIER;
66                     break;
67                 case STATE_COMMENT:
68                     format = JAVA_FORMAT_COMMENT;
69                     break;
70                 case STATE_OPERATOR:
71                     format = JAVA_FORMAT_OPERATOR;
72                     break;
73                 case STATE_BRACE:
74                     format = JAVA_FORMAT_BRACE;
75                     break;
76                 case STATE_NUMBER:
77                 case STATE_HEXNUMBER:
78                     format = JAVA_FORMAT_NUMBER;
79                     break;
80             }
81             addSegment(text, tokenBegin, tokenEnd, format);
82             tokenBegin = tokenEnd;
83         }
84     }
85
86     private void parseLine(Line line)
87     {
88         final String JavaDoc text = getDetabbedText(line);
89         tokenBegin = 0;
90         boolean isPreprocessorLine = false;
91         char quoteChar = '\0';
92         int state = line.flags();
93         if (state == STATE_QUOTE)
94             quoteChar = '"';
95         int i = 0;
96         final int limit = text.length();
97         // Skip whitespace at start of line.
98
while (i < limit) {
99             if (Character.isWhitespace(text.charAt(i)))
100                 ++i;
101             else {
102                 endToken(text, i, state);
103                 break;
104             }
105         }
106         char c;
107         if (state == STATE_SCRIPT)
108             state = STATE_NEUTRAL;
109         while (i < limit) {
110             c = text.charAt(i);
111             if (state == STATE_COMMENT) {
112                 if (i < limit - 1 && c == '*' && text.charAt(i+1) == '/') {
113                     endToken(text, i + 2, state);
114                     state = STATE_NEUTRAL;
115                     i += 2;
116                 }
117                 else
118                     ++i;
119                 continue;
120             }
121             if (state == STATE_QUOTE) {
122                 if (c == quoteChar) {
123                     endToken(text, i+1, state);
124                     state = STATE_NEUTRAL;
125                 } else if (c == '\\' && i < limit-1) {
126                     // Escape char.
127
++i;
128                 }
129                 ++i;
130                 continue;
131             }
132             // Reaching here, we're not in a comment or a quoted string.
133
if (c == '"' || c == '\'') {
134                 endToken(text, i, state);
135                 state = STATE_QUOTE;
136                 quoteChar = c;
137                 ++i;
138                 continue;
139             }
140             if (c == '/') {
141                 if (i < limit-1) {
142                     if (text.charAt(i+1) == '*') {
143                         endToken(text, i, state);
144                         state = STATE_COMMENT;
145                         i += 2;
146                     } else if (text.charAt(i+1) == '/') {
147                         endToken(text, i, state);
148                         endToken(text, limit, STATE_COMMENT);
149                         return;
150                     } else
151                         ++i;
152                 } else
153                     ++i;
154                 continue;
155             }
156             if (isOperatorChar(c)) {
157                 if (state != STATE_OPERATOR) {
158                     endToken(text, i, state);
159                     // Check for keyword (as in e.g. "char*").
160
LineSegment segment = getLastSegment();
161                     if (segment != null && isKeyword(segment.getText()))
162                         segment.setFormat(JAVA_FORMAT_KEYWORD);
163                     state = STATE_OPERATOR;
164                 }
165                 ++i;
166                 continue;
167             }
168             if (c == '{' || c == '}') {
169                 if (state != STATE_BRACE) {
170                     endToken(text, i, state);
171                     // Check for keyword (e.g. "try").
172
LineSegment segment = getLastSegment();
173                     if (segment != null && isKeyword(segment.getText()))
174                         segment.setFormat(JAVA_FORMAT_KEYWORD);
175                     state = STATE_BRACE;
176                 }
177                 ++i;
178                 continue;
179             }
180             if (state == STATE_OPERATOR || state == STATE_BRACE) {
181                 if (Character.isJavaIdentifierStart(c)) {
182                     endToken(text, i, state);
183                     state = STATE_IDENTIFIER;
184                 } else if (Character.isDigit(c)) {
185                     endToken(text, i, state);
186                     state = STATE_NUMBER;
187                 } else {
188                     endToken(text, i, state);
189                     state = STATE_NEUTRAL;
190                 }
191                 ++i;
192                 continue;
193             }
194             if (state == STATE_IDENTIFIER) {
195                 if (!Character.isJavaIdentifierPart(c)) {
196                     endToken(text, i, state);
197                     // Check for keyword or function.
198
LineSegment segment = getLastSegment();
199                     if (segment != null) {
200                         String JavaDoc segmentText = segment.getText();
201                         if (!isPreprocessorLine && isKeyword(segmentText))
202                             segment.setFormat(JAVA_FORMAT_KEYWORD);
203                         else if (c == '(')
204                             segment.setFormat(JAVA_FORMAT_FUNCTION);
205                         else if (Character.isWhitespace(c)) {
206                             // Look ahead to see if next non-whitespace char is '('.
207
int j = i + 1;
208                             while (j < limit && Character.isWhitespace(c = text.charAt(j)))
209                                 ++j;
210                             if (c == '(')
211                                 segment.setFormat(JAVA_FORMAT_FUNCTION);
212                         }
213                     }
214                     state = STATE_NEUTRAL;
215                 }
216                 ++i;
217                 continue;
218             }
219             if (state == STATE_NUMBER) {
220                 if (Character.isDigit(c))
221                     ;
222                 else if (c == 'u' || c == 'U' || c == 'l' || c == 'L')
223                     ;
224                 else if (i - tokenBegin == 1 && c == 'x' || c == 'X')
225                     state = STATE_HEXNUMBER;
226                 else {
227                     endToken(text, i, state);
228                     if (Character.isJavaIdentifierStart(c))
229                         state = STATE_IDENTIFIER;
230                     else
231                         state = STATE_NEUTRAL;
232                 }
233                 ++i;
234                 continue;
235             }
236             if (state == STATE_HEXNUMBER) {
237                 if (Character.isDigit(c))
238                     ;
239                 else if ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
240                     ;
241                 else if (c == 'u' || c == 'U' || c == 'l' || c == 'L')
242                     ;
243                 else {
244                     endToken(text, i, state);
245                     if (Character.isJavaIdentifierStart(c))
246                         state = STATE_IDENTIFIER;
247                     else
248                         state = STATE_NEUTRAL;
249                 }
250                 ++i;
251                 continue;
252             }
253             if (state == STATE_NEUTRAL) {
254                 if (Character.isJavaIdentifierStart(c)) {
255                     endToken(text, i, state);
256                     state = STATE_IDENTIFIER;
257                 } else if (Character.isDigit(c)) {
258                     endToken(text, i, state);
259                     state = STATE_NUMBER;
260                 }
261             }
262             ++i;
263         }
264         // Reached end of line.
265
endToken(text, i, state);
266         if (state == STATE_IDENTIFIER) {
267             // Last token might be a keyword.
268
LineSegment segment = getLastSegment();
269             if (segment != null && isKeyword(segment.getText()))
270                 segment.setFormat(JAVA_FORMAT_KEYWORD);
271         }
272     }
273
274     public LineSegmentList formatLine(Line line)
275     {
276         clearSegmentList();
277         if (line == null) {
278             addSegment("", JAVA_FORMAT_TEXT);
279             return segmentList;
280         }
281         parseLine(line);
282         return segmentList;
283     }
284
285     public boolean parseBuffer()
286     {
287         int state = STATE_NEUTRAL;
288         Line line = buffer.getFirstLine();
289         boolean changed = false;
290         while (line != null) {
291             int oldflags = line.flags();
292             // Quoted strings can't span lines in Java.
293
if (state == STATE_QUOTE && language == LANGUAGE_JAVA)
294                 state = STATE_NEUTRAL;
295
296             if (state != oldflags) {
297                 line.setFlags(state);
298                 changed = true;
299             }
300             char quoteChar = state == STATE_QUOTE ? '"' : '\0';
301             final int limit = line.length();
302             for (int i = 0; i < limit; i++) {
303                 char c = line.charAt(i);
304                 if (c == '\\' && i < limit-1) {
305                     // Escape.
306
++i;
307                     continue;
308                 }
309                 if (state == STATE_COMMENT) {
310                     if (c == '*' && i < limit-1) {
311                         c = line.charAt(i+1);
312                         if (c == '/') {
313                             ++i;
314                             state = STATE_NEUTRAL;
315                         }
316                     }
317                     continue;
318                 }
319                 if (state == STATE_QUOTE) {
320                     if (c == quoteChar) {
321                         state = STATE_NEUTRAL;
322                         quoteChar = '\0';
323                     }
324                     continue;
325                 }
326
327                 // Not in comment or quoted string.
328
if (c == '/' && i < limit-1) {
329                     c = line.charAt(++i);
330                     if (c == '/') {
331                         // Single-line comment beginning.
332
// Ignore rest of line.
333
break;
334                     } else if (c == '*')
335                         state = STATE_COMMENT;
336                 } else if (c == '"' || c == '\'') {
337                     state = STATE_QUOTE;
338                     quoteChar = c;
339                 }
340             }
341             line = line.next();
342         }
343         buffer.setNeedsParsing(false);
344         return changed;
345     }
346
347     private static final boolean isOperatorChar(char c)
348     {
349         return "!&|<>=+/*-^".indexOf(c) >= 0;
350     }
351
352     public FormatTable getFormatTable()
353     {
354         if (formatTable == null) {
355             formatTable = new FormatTable("JavaMode");
356             formatTable.addEntryFromPrefs(JAVA_FORMAT_TEXT, "text");
357             formatTable.addEntryFromPrefs(JAVA_FORMAT_COMMENT, "comment");
358             formatTable.addEntryFromPrefs(JAVA_FORMAT_STRING, "string");
359             formatTable.addEntryFromPrefs(JAVA_FORMAT_IDENTIFIER, "identifier", "text");
360             formatTable.addEntryFromPrefs(JAVA_FORMAT_KEYWORD, "keyword");
361             formatTable.addEntryFromPrefs(JAVA_FORMAT_FUNCTION, "function");
362             formatTable.addEntryFromPrefs(JAVA_FORMAT_OPERATOR, "operator");
363             formatTable.addEntryFromPrefs(JAVA_FORMAT_BRACE, "brace");
364             formatTable.addEntryFromPrefs(JAVA_FORMAT_NUMBER, "number");
365         }
366         return formatTable;
367     }
368 }
369
Popular Tags