Subversion Repositories general

Rev

Rev 1005 | Details | Compare with Previous | 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:
1006 dev 123
          if(Character.isDigit(c)) {
1005 dev 124
            startPos = pos;
1006 dev 125
            pos = findIntegerEnd(path, pos);
126
            token = path.substring(startPos, pos);
127
            addToken(tokens, startPos, Token.TOKEN_INDEX, token);
128
          }
129
          else if(Character.isLetter(c) || c == '_') {
130
            startPos = pos;
1005 dev 131
            pos = findTokenEnd(path, pos);
132
            token = path.substring(startPos, pos);
133
            if("and".equals(token))
134
              addToken(tokens, startPos, Token.TOKEN_AND, null);
135
            else if("or".equals(token))
136
              addToken(tokens, startPos, Token.TOKEN_OR, null);
137
            else if("new".equals(token))
138
              addToken(tokens, startPos, Token.TOKEN_NEW, null);
139
            else
140
              addToken(tokens, startPos, Token.TOKEN_NAME, token);
141
          }
142
          else
143
            throw new PathParseException(
144
              "unexpected character '" + c + "'", pos);
145
      }
146
    }
147
 
148
    return tokens;
149
  }
150
 
151
  private int findStringEnd(String path, char c, int pos)
152
    throws PathParseException
153
  {
154
    int endPos = path.length();
155
 
156
    if(pos >= endPos - 1)
157
      throw new PathParseException(
158
        "unclosed string, '" + c + "' expected", pos);
159
 
160
    while(path.charAt(++pos) != c) {
161
      if(pos >= endPos - 1)
162
        throw new PathParseException(
163
          "unclosed string, '" + c + "' expected", pos);
164
    }
165
 
166
    return pos;
167
  }
168
 
169
  private int findVariableEnd(String path, char c, int pos)
170
    throws PathParseException
171
  {
172
    int endPos = path.length();
173
 
174
    if(pos >= endPos)
175
      throw new PathParseException("unexpected end of variable name", pos);
176
 
177
    char c2 = path.charAt(pos);
178
 
179
    if(c == '{' && c2 == '}')
180
      throw new PathParseException("empty variable name", pos);
181
    else if(!Character.isLetter(c2) && c2 != '_')
182
      throw new PathParseException("variable name expected", pos);
183
 
184
    while(true) {
185
      if(pos >= endPos - 1)
186
        throw new PathParseException("unexpected end of variable name", pos);
187
 
188
      c2 = path.charAt(++pos);
189
 
190
      if(c == '{') {
191
        if(c2 == '}') break;
192
        if(!Character.isLetter(c2) && !Character.isDigit(c2) && c2 != '_')
193
          throw new PathParseException("unexpected character '" + c2
194
            + "' in variable name is occured instead of '}'", pos);
195
      }
196
      else {
197
        if(!Character.isLetter(c2) && !Character.isDigit(c2) && c2 != '_')
198
          break;
199
        if(pos >= endPos - 1) {
200
          pos++;
201
          break;
202
        }
203
      }
204
    }
205
 
206
    return pos;
207
  }
208
 
209
  private int findTokenEnd(String path, int pos)
210
    throws PathParseException
211
  {
212
    int endPos = path.length();
213
    char c;
214
 
215
    while(true) {
216
      pos++;
217
      if(pos >= endPos) break;
218
 
219
      c = path.charAt(pos);
220
      if(!Character.isLetter(c) && !Character.isDigit(c) && c != '_') break;
221
    }
222
 
223
    return pos;
224
  }
225
 
1006 dev 226
  private int findIntegerEnd(String path, int pos)
227
    throws PathParseException
228
  {
229
    int endPos = path.length();
230
    char c;
231
 
232
    while(true) {
233
      pos++;
234
      if(pos >= endPos) break;
235
 
236
      c = path.charAt(pos);
237
      if(!Character.isDigit(c)) break;
238
    }
239
 
240
    return pos;
241
  }
242
 
1005 dev 243
  private void addToken(List tokens, int pos, int type, String value)
244
  {
245
    tokens.add(new Token(type, pos, value));
246
  }
247
}