source: josm/trunk/src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java@ 3385

Last change on this file since 3385 was 3385, checked in by jttt, 14 years ago

Fix warnings

  • Property svn:eol-style set to native
File size: 6.2 KB
RevLine 
[513]1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.actions.search;
3
[2863]4import static org.openstreetmap.josm.tools.I18n.marktr;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
[513]7import java.io.IOException;
[2645]8import java.io.Reader;
[3046]9import java.util.Arrays;
10import java.util.List;
[513]11
[2645]12import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError;
13
[513]14public class PushbackTokenizer {
[2993]15
[3385]16 public static class Range {
[2993]17 private final long start;
18 private final long end;
19
20 public Range(long start, long end) {
21 this.start = start;
22 this.end = end;
23 }
24
25 public long getStart() {
26 return start;
27 }
28
29 public long getEnd() {
30 return end;
31 }
32 }
33
[2645]34 private final Reader search;
[513]35
[2645]36 private Token currentToken;
37 private String currentText;
[3046]38 private Long currentNumber;
39 private Long currentRange;
[2645]40 private int c;
[513]41
[2645]42 public PushbackTokenizer(Reader search) {
[1169]43 this.search = search;
[2645]44 getChar();
[1169]45 }
[513]46
[2863]47 public enum Token {
48 NOT(marktr("<not>")), OR(marktr("<or>")), LEFT_PARENT(marktr("<left parent>")),
49 RIGHT_PARENT(marktr("<right parent>")), COLON(marktr("<colon>")), EQUALS(marktr("<equals>")),
[3046]50 KEY(marktr("<key>")), QUESTION_MARK(marktr("<question mark>")),
51 EOF(marktr("<end-of-file>"));
[2645]52
[2863]53 private Token(String name) {
54 this.name = name;
55 }
56
57 private final String name;
58
59 @Override
60 public String toString() {
61 return tr(name);
62 }
63 }
64
65
[2645]66 private void getChar() {
67 try {
68 c = search.read();
69 } catch (IOException e) {
70 throw new RuntimeException(e.getMessage(), e);
71 }
72 }
73
[2973]74 private long getNumber() {
75 long result = 0;
76 while (Character.isDigit(c)) {
77 result = result * 10 + (c - '0');
78 getChar();
79 }
80 return result;
81 }
82
[3049]83 private static final List<Character> specialChars = Arrays.asList(new Character[] {'"', ':', '(', ')', '|', '=', '?'});
84 private static final List<Character> specialCharsQuoted = Arrays.asList(new Character[] {'"'});
[3046]85
86 private String getString(boolean quoted) {
[3049]87 List<Character> sChars = quoted ? specialCharsQuoted : specialChars;
[3046]88 StringBuilder s = new StringBuilder();
89 boolean escape = false;
[3050]90 while (c != -1 && (escape || (!sChars.contains((char)c) && (quoted || !Character.isWhitespace(c))))) {
[3046]91 if (c == '\\' && !escape) {
92 escape = true;
93 } else {
94 s.append((char)c);
95 escape = false;
96 }
97 getChar();
98 }
99 return s.toString();
100 }
101
102 private String getString() {
103 return getString(false);
104 }
105
[1169]106 /**
107 * The token returned is <code>null</code> or starts with an identifier character:
108 * - for an '-'. This will be the only character
109 * : for an key. The value is the next token
110 * | for "OR"
111 * ' ' for anything else.
112 * @return The next token in the stream.
113 */
[2645]114 public Token nextToken() {
115 if (currentToken != null) {
116 Token result = currentToken;
117 currentToken = null;
118 return result;
[1169]119 }
[513]120
[2645]121 while (Character.isWhitespace(c)) {
122 getChar();
123 }
124 switch (c) {
125 case -1:
126 getChar();
127 return Token.EOF;
128 case ':':
129 getChar();
130 return Token.COLON;
131 case '=':
132 getChar();
133 return Token.EQUALS;
134 case '(':
135 getChar();
136 return Token.LEFT_PARENT;
137 case ')':
138 getChar();
139 return Token.RIGHT_PARENT;
140 case '|':
141 getChar();
142 return Token.OR;
[2863]143 case '?':
144 getChar();
145 return Token.QUESTION_MARK;
[2645]146 case '"':
[2768]147 getChar();
[3046]148 currentText = getString(true);
[2645]149 getChar();
150 return Token.KEY;
151 default:
[3046]152 String prefix = "";
153 if (c == '-') {
[2645]154 getChar();
[3046]155 if (!Character.isDigit(c))
156 return Token.NOT;
157 prefix = "-";
[1169]158 }
[3046]159 currentText = prefix + getString();
[2645]160 if ("or".equals(currentText))
161 return Token.OR;
[3046]162 try {
163 currentNumber = Long.parseLong(currentText);
164 } catch (NumberFormatException e) {
165 currentNumber = null;
166 }
167 int pos = currentText.indexOf('-', 1);
168 if (pos > 0) {
169 try {
170 currentNumber = Long.parseLong(currentText.substring(0, pos));
171 currentRange = Long.parseLong(currentText.substring(pos + 1));
172 } catch (NumberFormatException e) {
173 currentNumber = null;
174 currentRange = null;
175 }
176 }
177 return Token.KEY;
[1169]178 }
179 }
[513]180
[2645]181 public boolean readIfEqual(Token token) {
182 Token nextTok = nextToken();
183 if (nextTok == null ? token == null : nextTok == token)
[1169]184 return true;
[2645]185 currentToken = nextTok;
[1169]186 return false;
187 }
[513]188
[2993]189 public String readTextOrNumber() {
[2645]190 Token nextTok = nextToken();
191 if (nextTok == Token.KEY)
192 return currentText;
193 currentToken = nextTok;
[1169]194 return null;
195 }
[513]196
[2973]197 public long readNumber(String errorMessage) throws ParseError {
[3046]198 if ((nextToken() == Token.KEY) && (currentNumber != null))
[2973]199 return currentNumber;
200 else
201 throw new ParseError(errorMessage);
202 }
203
[2993]204 public long getReadNumber() {
[3046]205 return (currentNumber != null) ? currentNumber : 0;
[2993]206 }
207
[3046]208 public Range readRange(String errorMessage) throws ParseError {
209 if ((nextToken() == Token.KEY) && (currentNumber != null)) {
210 if (currentRange == null)
211 return new Range(currentNumber, currentNumber);
212 else
213 return new Range(currentNumber, currentRange);
214 } else
215 throw new ParseError(errorMessage);
[2993]216 }
217
[2645]218 public String getText() {
219 return currentText;
220 }
[513]221}
Note: See TracBrowser for help on using the repository browser.