Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
package ak.zpath;
import java.util.List;
import java.util.ArrayList;
public class PathParser
{
public List parse(String path)
throws PathParseException
{
char c;
int startPos;
int pos = 0;
int endPos = path.length();
String token;
List tokens = new ArrayList();
while(pos < endPos) {
c = path.charAt(pos);
while(Character.isWhitespace(c) && pos < endPos - 1) {
c = path.charAt(++pos);
}
if(pos >= endPos) break;
switch(c) {
case '/':
addToken(tokens, pos, Token.TOKEN_SLASH, null);
pos++;
break;
case '[':
addToken(tokens, pos, Token.TOKEN_OPEN_BRACKET, null);
pos++;
break;
case ']':
addToken(tokens, pos, Token.TOKEN_CLOSE_BRACKET, null);
pos++;
break;
case '@':
addToken(tokens, pos, Token.TOKEN_AT, null);
pos++;
break;
case '#':
addToken(tokens, pos, Token.TOKEN_SHARP, null);
pos++;
break;
case '"':
case '\'':
startPos = pos+1;
pos = findStringEnd(path, c, startPos);
addToken(tokens, startPos-1, Token.TOKEN_STRING,
path.substring(startPos, pos));
pos++;
break;
case '=':
addToken(tokens, pos, Token.TOKEN_EQUAL, null);
pos++;
break;
case '$':
if(++pos >= endPos)
throw new PathParseException("variable name expected", pos);
c = path.charAt(pos);
if(c == '{') {
startPos = ++pos;
pos = findVariableEnd(path, c, startPos);
addToken(tokens, startPos-2,
Token.TOKEN_VARIABLE, path.substring(startPos, pos));
}
else if(Character.isLetter(c)) {
startPos = pos;
pos = findVariableEnd(path, '\u0000', pos);
addToken(tokens, startPos-1,
Token.TOKEN_VARIABLE, path.substring(startPos, pos));
}
else
throw new PathParseException("variable name expected", pos);
pos++;
break;
case ':':
if(++pos >= endPos)
throw new PathParseException("'=' expected", pos);
c = path.charAt(pos);
if(c == '=')
addToken(tokens, pos-1, Token.TOKEN_ASSIGN, null);
else
throw new PathParseException("'=' expected", pos);
pos++;
break;
case '.':
if(++pos >= endPos)
throw new PathParseException("'=' or '.' expected", pos);
c = path.charAt(pos);
if(c == '=')
addToken(tokens, pos-1, Token.TOKEN_APPEND, null);
else if(c == '.')
addToken(tokens, pos-1, Token.TOKEN_NAME, "..");
else
throw new PathParseException("'=' expected", pos);
pos++;
break;
case '*':
if(pos < endPos-1 && path.charAt(pos+1) == '*') {
addToken(tokens, pos, Token.TOKEN_NAME, "**");
pos += 2;
}
else {
addToken(tokens, pos, Token.TOKEN_NAME, "*");
pos++;
}
break;
default:
if(Character.isLetter(c) || c == '_') {
startPos = pos;
pos = findTokenEnd(path, pos);
token = path.substring(startPos, pos);
if("and".equals(token))
addToken(tokens, startPos, Token.TOKEN_AND, null);
else if("or".equals(token))
addToken(tokens, startPos, Token.TOKEN_OR, null);
else if("new".equals(token))
addToken(tokens, startPos, Token.TOKEN_NEW, null);
else
addToken(tokens, startPos, Token.TOKEN_NAME, token);
}
else
throw new PathParseException(
"unexpected character '" + c + "'", pos);
}
}
return tokens;
}
private int findStringEnd(String path, char c, int pos)
throws PathParseException
{
int endPos = path.length();
if(pos >= endPos - 1)
throw new PathParseException(
"unclosed string, '" + c + "' expected", pos);
while(path.charAt(++pos) != c) {
if(pos >= endPos - 1)
throw new PathParseException(
"unclosed string, '" + c + "' expected", pos);
}
return pos;
}
private int findVariableEnd(String path, char c, int pos)
throws PathParseException
{
int endPos = path.length();
if(pos >= endPos)
throw new PathParseException("unexpected end of variable name", pos);
char c2 = path.charAt(pos);
if(c == '{' && c2 == '}')
throw new PathParseException("empty variable name", pos);
else if(!Character.isLetter(c2) && c2 != '_')
throw new PathParseException("variable name expected", pos);
while(true) {
if(pos >= endPos - 1)
throw new PathParseException("unexpected end of variable name", pos);
c2 = path.charAt(++pos);
if(c == '{') {
if(c2 == '}') break;
if(!Character.isLetter(c2) && !Character.isDigit(c2) && c2 != '_')
throw new PathParseException("unexpected character '" + c2
+ "' in variable name is occured instead of '}'", pos);
}
else {
if(!Character.isLetter(c2) && !Character.isDigit(c2) && c2 != '_')
break;
if(pos >= endPos - 1) {
pos++;
break;
}
}
}
return pos;
}
private int findTokenEnd(String path, int pos)
throws PathParseException
{
int endPos = path.length();
char c;
while(true) {
pos++;
if(pos >= endPos) break;
c = path.charAt(pos);
if(!Character.isLetter(c) && !Character.isDigit(c) && c != '_') break;
}
return pos;
}
private void addToken(List tokens, int pos, int type, String value)
{
tokens.add(new Token(type, pos, value));
}
}