Subversion Repositories general

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1005 dev 1
package ak.zpath;
2
 
3
import java.util.List;
4
import java.util.ArrayList;
5
 
6
public class PathParser
7
{
8
  public List parse(String path)
9
    throws PathParseException
10
  {
11
    char   c;
12
    int    startPos;
13
    int    pos      = 0;
14
    int    endPos   = path.length();
15
    String token;
16
    List   tokens = new ArrayList();
17
 
18
    while(pos < endPos) {
19
      c = path.charAt(pos);
20
 
21
      while(Character.isWhitespace(c) && pos < endPos - 1) {
22
        c = path.charAt(++pos);
23
      }
24
      if(pos >= endPos) break;
25
 
26
      switch(c) {
27
        case '/':
28
          addToken(tokens, pos, Token.TOKEN_SLASH, null);
29
          pos++;
30
          break;
31
 
32
        case '[':
33
          addToken(tokens, pos, Token.TOKEN_OPEN_BRACKET, null);
34
          pos++;
35
          break;
36
 
37
        case ']':
38
          addToken(tokens, pos, Token.TOKEN_CLOSE_BRACKET, null);
39
          pos++;
40
          break;
41
 
42
        case '@':
43
          addToken(tokens, pos, Token.TOKEN_AT, null);
44
          pos++;
45
          break;
46
 
47
        case '#':
48
          addToken(tokens, pos, Token.TOKEN_SHARP, null);
49
          pos++;
50
          break;
51
 
52
        case '"':
53
        case '\'':
54
          startPos = pos+1;
55
          pos = findStringEnd(path, c, startPos);
56
          addToken(tokens, startPos-1, Token.TOKEN_STRING,
57
            path.substring(startPos, pos));
58
          pos++;
59
          break;
60
 
61
        case '=':
62
          addToken(tokens, pos, Token.TOKEN_EQUAL, null);
63
          pos++;
64
          break;
65
 
66
        case '$':
67
          if(++pos >= endPos)
68
            throw new PathParseException("variable name expected", pos);
69
          c = path.charAt(pos);
70
          if(c == '{') {
71
            startPos = ++pos;
72
            pos = findVariableEnd(path, c, startPos);
73
            addToken(tokens, startPos-2,
74
              Token.TOKEN_VARIABLE, path.substring(startPos, pos));
75
          }
76
          else if(Character.isLetter(c)) {
77
            startPos = pos;
78
            pos = findVariableEnd(path, '\u0000', pos);
79
            addToken(tokens, startPos-1,
80
              Token.TOKEN_VARIABLE, path.substring(startPos, pos));
81
          }
82
          else
83
            throw new PathParseException("variable name expected", pos);
84
          pos++;
85
          break;
86
 
87
        case ':':
88
          if(++pos >= endPos)
89
            throw new PathParseException("'=' expected", pos);
90
          c = path.charAt(pos);
91
          if(c == '=')
92
            addToken(tokens, pos-1, Token.TOKEN_ASSIGN, null);
93
          else
94
            throw new PathParseException("'=' expected", pos);
95
          pos++;
96
          break;
97
 
98
        case '.':
99
          if(++pos >= endPos)
100
            throw new PathParseException("'=' or '.' expected", pos);
101
          c = path.charAt(pos);
102
          if(c == '=')
103
            addToken(tokens, pos-1, Token.TOKEN_APPEND, null);
104
          else if(c == '.')
105
            addToken(tokens, pos-1, Token.TOKEN_NAME, "..");
106
          else
107
            throw new PathParseException("'=' expected", pos);
108
          pos++;
109
          break;
110
 
111
        case '*':
112
          if(pos < endPos-1 && path.charAt(pos+1) == '*') {
113
            addToken(tokens, pos, Token.TOKEN_NAME, "**");
114
            pos += 2;
115
          }
116
          else {
117
            addToken(tokens, pos, Token.TOKEN_NAME, "*");
118
            pos++;
119
          }
120
          break;
121
 
122
        default:
123
          if(Character.isLetter(c) || c == '_') {
124
            startPos = pos;
125
            pos = findTokenEnd(path, pos);
126
            token = path.substring(startPos, pos);
127
            if("and".equals(token))
128
              addToken(tokens, startPos, Token.TOKEN_AND, null);
129
            else if("or".equals(token))
130
              addToken(tokens, startPos, Token.TOKEN_OR, null);
131
            else if("new".equals(token))
132
              addToken(tokens, startPos, Token.TOKEN_NEW, null);
133
            else
134
              addToken(tokens, startPos, Token.TOKEN_NAME, token);
135
          }
136
          else
137
            throw new PathParseException(
138
              "unexpected character '" + c + "'", pos);
139
      }
140
    }
141
 
142
    return tokens;
143
  }
144
 
145
  private int findStringEnd(String path, char c, int pos)
146
    throws PathParseException
147
  {
148
    int endPos = path.length();
149
 
150
    if(pos >= endPos - 1)
151
      throw new PathParseException(
152
        "unclosed string, '" + c + "' expected", pos);
153
 
154
    while(path.charAt(++pos) != c) {
155
      if(pos >= endPos - 1)
156
        throw new PathParseException(
157
          "unclosed string, '" + c + "' expected", pos);
158
    }
159
 
160
    return pos;
161
  }
162
 
163
  private int findVariableEnd(String path, char c, int pos)
164
    throws PathParseException
165
  {
166
    int endPos = path.length();
167
 
168
    if(pos >= endPos)
169
      throw new PathParseException("unexpected end of variable name", pos);
170
 
171
    char c2 = path.charAt(pos);
172
 
173
    if(c == '{' && c2 == '}')
174
      throw new PathParseException("empty variable name", pos);
175
    else if(!Character.isLetter(c2) && c2 != '_')
176
      throw new PathParseException("variable name expected", pos);
177
 
178
    while(true) {
179
      if(pos >= endPos - 1)
180
        throw new PathParseException("unexpected end of variable name", pos);
181
 
182
      c2 = path.charAt(++pos);
183
 
184
      if(c == '{') {
185
        if(c2 == '}') break;
186
        if(!Character.isLetter(c2) && !Character.isDigit(c2) && c2 != '_')
187
          throw new PathParseException("unexpected character '" + c2
188
            + "' in variable name is occured instead of '}'", pos);
189
      }
190
      else {
191
        if(!Character.isLetter(c2) && !Character.isDigit(c2) && c2 != '_')
192
          break;
193
        if(pos >= endPos - 1) {
194
          pos++;
195
          break;
196
        }
197
      }
198
    }
199
 
200
    return pos;
201
  }
202
 
203
  private int findTokenEnd(String path, int pos)
204
    throws PathParseException
205
  {
206
    int endPos = path.length();
207
    char c;
208
 
209
    while(true) {
210
      pos++;
211
      if(pos >= endPos) break;
212
 
213
      c = path.charAt(pos);
214
      if(!Character.isLetter(c) && !Character.isDigit(c) && c != '_') break;
215
    }
216
 
217
    return pos;
218
  }
219
 
220
  private void addToken(List tokens, int pos, int type, String value)
221
  {
222
    tokens.add(new Token(type, pos, value));
223
  }
224
}