1 package cz.cuni.amis.pogamut.shady;
2
3
4
5
6
7
8 public interface IArgument<T> {
9
10 T getValue();
11 }
12
13
14
15
16
17 class Arg<T> implements IArgument<T> {
18
19 private final T value;
20
21 public Arg(T value) {
22 this.value = value;
23 }
24
25 @Override
26 public T getValue() {
27 return value;
28 }
29
30 @Override
31 public boolean equals(Object obj) {
32 if (obj == null) {
33 return false;
34 }
35 if (obj == this) {
36 return true;
37 }
38 if (!(obj instanceof IArgument)) {
39 return false;
40 }
41 IArgument arg = (IArgument) obj;
42 return this.value == null ? arg.getValue() == null : value.equals(arg.getValue());
43 }
44 }
45
46 class ArgInt extends Arg<Integer> {
47
48 public ArgInt(int number) {
49 super(number);
50 }
51 }
52
53 class ArgFloat extends Arg<Double> {
54
55 public ArgFloat(double number) {
56 super(number);
57 }
58 }
59
60 class ArgChar extends Arg<Character> {
61
62 public ArgChar(char character) {
63 super(character);
64 }
65
66
67
68
69
70
71
72
73
74 public static char unescape(String escapedChar) throws ParseException {
75 if (escapedChar.length() == 0) {
76 throw new ParseException("The string representing the escaped character must have legth > 0.");
77 }
78 StringBuilder sb = new StringBuilder(escapedChar);
79 char result = parseCharacter(sb);
80 if (sb.length() > 0)
81 throw new ParseException("There still are some unparsed characters remaining(" + sb.length() + "):" + sb.toString());
82 return result;
83 }
84
85
86
87
88
89
90
91
92
93 protected static char parseCharacter(StringBuilder sb) throws ParseException {
94 char result = sb.charAt(0);
95 sb.deleteCharAt(0);
96 if (result == '\\') {
97 Character parsed = ArgChar.parseEscapeSequence(sb);
98 if (parsed == null) {
99 throw new ParseException("Unable to unescape sequence:" + sb.toString());
100 }
101 result = parsed;
102 }
103 return result;
104 }
105
106
107
108
109
110
111 public static char parseCharacterListeral(String charLiteral) throws ParseException {
112 StringBuilder sb = new StringBuilder(charLiteral);
113 if (sb.charAt(0) != '\'') {
114 throw new ParseException("Expecting \' at the start of " + charLiteral.toString());
115 }
116 sb.deleteCharAt(0);
117
118 char result = parseCharacter(sb);
119
120 if (sb.length() != 1) {
121 throw new ParseException("Expecting exactly one character (single quote), but " + sb.length() + " characters remain:" + sb.toString());
122 }
123 if (sb.charAt(0) != '\'') {
124 throw new ParseException("Expecting ending double quote, but got: " + sb.charAt(0));
125 }
126 return result;
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143 protected static Character parseEscapeSequence(StringBuilder sb) {
144
145 Character octal = parseOctal(sb);
146 if (octal != null) {
147 return octal;
148 }
149
150 Character simpleEscape = parseSingleEscape(sb);
151 if (simpleEscape != null) {
152 return simpleEscape;
153 }
154 Character unicode = parseUnicode(sb);
155 if (unicode != null) {
156 return unicode;
157 }
158 return null;
159 }
160
161
162
163
164
165
166
167
168 protected static Character parseOctal(StringBuilder sb) {
169 if (sb.length() >= 3) {
170 String octal3 = sb.substring(0, 3);
171 if (octal3.matches("[0-3][0-7][0-7]")) {
172 sb.delete(0, 3);
173 return Character.toChars(Integer.parseInt(octal3, 8))[0];
174 }
175 }
176 if (sb.length() >= 2) {
177 String octal2 = sb.substring(0, 2);
178 if (octal2.matches("[0-7][0-7]")) {
179 sb.delete(0, 2);
180 return Character.toChars(Integer.parseInt(octal2, 8))[0];
181 }
182 }
183 String octal1 = sb.substring(0, 1);
184 if (octal1.matches("[0-7]")) {
185 sb.delete(0, 1);
186 return Character.toChars(Integer.parseInt(octal1, 8))[0];
187 }
188 return null;
189 }
190
191
192
193
194
195
196
197
198
199
200 protected static Character parseSingleEscape(StringBuilder sb) {
201 char ch = sb.charAt(0);
202 char res;
203 switch (ch) {
204 case 'b':
205 res = '\b';
206 break;
207 case 't':
208 res = '\t';
209 break;
210 case 'n':
211 res = '\n';
212 break;
213 case 'f':
214 res = '\f';
215 break;
216 case 'r':
217 res = '\r';
218 break;
219 case '"':
220 res = '\"';
221 break;
222 case '\'':
223 res = '\'';
224 break;
225 case '\\':
226 res = '\\';
227 break;
228 default:
229 return null;
230 }
231 sb.deleteCharAt(0);
232 return res;
233 }
234
235
236
237
238
239
240
241
242
243
244 protected static Character parseUnicode(StringBuilder sb) {
245 String regexp = "u+\\p{XDigit}\\p{XDigit}\\p{XDigit}\\p{XDigit}.*";
246 if (sb.toString().matches(regexp)) {
247 while (sb.charAt(0) == 'u') {
248 sb.deleteCharAt(0);
249 }
250 String hexaString = sb.substring(0, 4);
251 sb.delete(0, 4);
252 return Character.toChars(Integer.parseInt(hexaString, 16))[0];
253 }
254 return null;
255 }
256 }
257
258
259
260
261
262
263
264
265 class ArgString extends Arg<String> {
266
267
268
269
270
271
272
273 public ArgString(String string) {
274 super(string);
275 }
276
277
278
279
280
281
282
283
284 public static String unescape(String escapedString) throws ParseException {
285 if (escapedString.length() == 0) {
286 return escapedString;
287 }
288 return parseStringCharacters(new StringBuilder(escapedString));
289 }
290
291
292
293
294
295
296
297
298 protected static String parseStringLiteral(String escaped) throws ParseException {
299 StringBuilder sb = new StringBuilder(escaped);
300 if (sb.charAt(0) != '\"') {
301 throw new ParseException("Expecting \" at the start of " + escaped.toString());
302 }
303 sb.deleteCharAt(0);
304
305
306
307 String parsed = "";
308 if (sb.length() != 1) {
309 parsed = parseStringCharacters(sb);
310 }
311
312 if (sb.length() != 1) {
313 throw new ParseException("Expecting exactly one character (double quote), but " + sb.length() + " characters remain:" + sb.toString());
314 }
315
316 if (sb.charAt(0) != '\"') {
317 throw new ParseException("Expecting ending double quote, but got: " + sb.charAt(0));
318 }
319
320 return parsed.toString();
321 }
322
323
324
325
326
327
328
329
330 private static String parseStringCharacters(StringBuilder sb) throws ParseException {
331 Character ch;
332 StringBuilder stringCharacters = new StringBuilder();
333 while ((ch = parseStringCharacter(sb)) != null) {
334 stringCharacters.append(ch);
335 }
336 return stringCharacters.toString();
337 }
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359 protected static Character parseStringCharacter(StringBuilder sb) throws ParseException {
360 if (sb.length() == 0) {
361 return null;
362 }
363 char ch = sb.charAt(0);
364 if (ch == '\"' || ch == '\r' || ch == '\n') {
365 return null;
366 }
367
368 sb.deleteCharAt(0);
369
370 if (ch == '\\') {
371 Character res = ArgChar.parseEscapeSequence(sb);
372 if (res == null) {
373 throw new ParseException("Unable to unescape sequence:" + sb.toString());
374 }
375 return res;
376 }
377 return ch;
378 }
379 }