/*
* FindBugs - Find Bugs in Java programs
* Copyright (C) 2006, University of Maryland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307, USA
*/
package edu.umd.cs.findbugs.sourceViewer;
import java.text.CharacterIterator;
import java.util.HashSet;
public class JavaScanner {
public final static int NORMAL_TEXT = 0;
public final static int COMMENT= 1;
public final static int JAVADOC = 2;
public final static int KEYWORD = 3;
public final static int QUOTE= 4;
public final static int EOF = -1;
private final static HashSet<String> KEYWORDS = new HashSet<String>();
private final static int MAX_KEYWORD_LENGTH;
static {
String[] keywordList = new String[] { "abstract", "assert", "boolean",
"break", "byte", "case", "catch", "char", "class", "const",
"continue", "default", "do", "double", "else", "enum",
"extends", "false", "final", "finally", "float", "for", "goto",
"if", "implements", "import", "instanceof", "int", "interface",
"long", "native", "new", "null", "package", "private",
"protected", "public", "return", "short", "static", "strictfp",
"super", "switch", "synchronized", "this", "throw", "throws",
"transient", "true", "try", "void", "volatile", "while" };
int max = 0;
for (String s : keywordList) {
if (max < s.length())
max = s.length();
KEYWORDS.add(s);
}
MAX_KEYWORD_LENGTH = max;
}
private final StringBuilder buf = new StringBuilder();
private final CharacterIterator iterator;
private int kind;
private int startPosition;
public JavaScanner(CharacterIterator iterator) {
this.iterator = iterator;
}
public int getStartPosition() {
return startPosition;
}
public int getEndPosition() {
return iterator.getIndex();
}
public int getLength() {
return iterator.getIndex() - startPosition;
}
public int getKind() {
return kind;
}
public int next() {
startPosition = iterator.getIndex();
char c = iterator.current();
iterator.next(); // advance
if (c == CharacterIterator.DONE) {
kind = EOF;
}
else if (Character.isJavaIdentifierStart(c)) {
buf.append(c);
boolean couldBeKeyword = Character.isLowerCase(c);
while (true) {
c = iterator.current();
if (!Character.isJavaIdentifierPart(c))
break;
buf.append(c);
if (couldBeKeyword) {
if (!Character.isLowerCase(c)
|| buf.length() > MAX_KEYWORD_LENGTH)
couldBeKeyword = false;
}
c = iterator.next();
}
kind = NORMAL_TEXT;
if (couldBeKeyword) {
if (KEYWORDS.contains(buf.toString()))
kind = KEYWORD;
}
buf.setLength(0);
} else if (c == '/') {
char c2 = iterator.current();
if (c2 == '/') {
while (true) {
c2 = iterator.next();
if (c2 == '\n' || c2 == '\r' || c2 == CharacterIterator.DONE)
break;
}
kind = COMMENT;
return kind;
} else if (c2 == '*') {
scanComment: while (c2 != CharacterIterator.DONE) {
c2 = iterator.next();
if (c2 == '*') {
do {
c2 = iterator.next();
if (c2 == '/')
break scanComment;
} while(c2 == '*');
}
}
kind = JAVADOC;
return kind;
}
} else if (c == '"') {
kind = QUOTE;
char c2 = iterator.current();
while (c2 != '"' && c2 != '\n' && c2 != '\r' && c2 != CharacterIterator.DONE) {
if (c2 == '\\') {
c2 = iterator.next();
if (c2 == '\n' || c2 == '\r')
break;
}
c2 = iterator.next();
}
iterator.next(); // advance past closing char
} else if (c == '\'') {
// need to catch '"' so isn't considered to start a String
kind = QUOTE; // or NORMAL_TEXT ?
char c2 = iterator.current();
if (c2 == '\\') c2 = iterator.next(); // advance past the escape char
if (c2 != '\n' && c2 != '\r' && c2 != CharacterIterator.DONE)
c2 = iterator.next(); // advance past the content char
if (c2 != '\n' && c2 != '\r' && c2 != CharacterIterator.DONE)
iterator.next(); // advance past closing char
} else
kind = NORMAL_TEXT;
// System.out.println(kind + " " + startPosition + "-" + iterator.getIndex());
return kind;
}
}