]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/icu/dev/test/util/Tokenizer.java
go
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / icu / dev / test / util / Tokenizer.java
1 //##header J2SE15
2 //#if defined(FOUNDATION10) || defined(J2SE13)
3 //#else
4 /*
5  *******************************************************************************
6  * Copyright (C) 2002-2009, International Business Machines Corporation and    *
7  * others. All Rights Reserved.                                                *
8  *******************************************************************************
9  */
10 package com.ibm.icu.dev.test.util;
11
12 import java.text.ParsePosition;
13
14 import com.ibm.icu.text.*;
15 import com.ibm.icu.lang.*;
16
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.Set;
20 import java.util.Map;
21
22 public class Tokenizer {
23     protected String source;
24     
25     protected StringBuffer buffer = new StringBuffer();
26     protected long number;
27     protected UnicodeSet unicodeSet = null;
28     protected int index;
29     boolean backedup = false;
30     protected int lastIndex = -1;
31     protected int nextIndex;
32     int lastValue = BACKEDUP_TOO_FAR;
33     TokenSymbolTable symbolTable = new TokenSymbolTable();
34
35     private static final char
36         QUOTE = '\'',
37         BSLASH = '\\';
38     private static final UnicodeSet QUOTERS = new UnicodeSet().add(QUOTE).add(BSLASH);
39     private static final UnicodeSet WHITESPACE = new UnicodeSet("[" +
40         "\\u0009-\\u000D\\u0020\\u0085\\u200E\\u200F\\u2028\\u2029" +
41         "]");
42     private static final UnicodeSet SYNTAX = new UnicodeSet("[" +
43         "\\u0021-\\u002F\\u003A-\\u0040\\u005B-\\u0060\\u007B-\\u007E" +
44         "\\u00A1-\\u00A7\\u00A9\\u00AB-\\u00AC\\u00AE" +
45         "\\u00B0-\\u00B1\\u00B6\\u00B7\\u00BB\\u00BF\\u00D7\\u00F7" +
46         "\\u2010-\\u2027\\u2030-\\u205E\\u2190-\\u2BFF" +
47         "\\u3001\\u3003\\u3008-\\u3020\\u3030" +
48         "\\uFD3E\\uFD3F\\uFE45\\uFE46" +
49         "]").removeAll(QUOTERS).remove('$');
50     private static final UnicodeSet NEWLINE = new UnicodeSet("[\\u000A\\u000D\\u0085\\u2028\\u2029]");
51     //private static final UnicodeSet DECIMAL = new UnicodeSet("[:Nd:]");
52     private static final UnicodeSet NON_STRING = new UnicodeSet()
53         .addAll(WHITESPACE)
54         .addAll(SYNTAX);
55            
56     protected UnicodeSet whiteSpace = WHITESPACE;
57     protected UnicodeSet syntax = SYNTAX;
58     private UnicodeSet non_string = NON_STRING;
59
60     private void fixSets() {
61         if (syntax.containsSome(QUOTERS) || syntax.containsSome(whiteSpace)) {
62             syntax = ((UnicodeSet)syntax.clone()).removeAll(QUOTERS).removeAll(whiteSpace);
63         }
64         if (whiteSpace.containsSome(QUOTERS)) {
65             whiteSpace = ((UnicodeSet)whiteSpace.clone()).removeAll(QUOTERS);
66         }
67         non_string = new UnicodeSet(syntax)
68             .addAll(whiteSpace);
69     }
70     
71     public Tokenizer setSource(String source) {
72         this.source = source;
73         this.index = 0;
74         return this; // for chaining
75     }
76     
77     public Tokenizer setIndex(int index) {
78         this.index = index;
79         return this; // for chaining
80     }
81     
82     public static final int 
83         DONE = -1, 
84         NUMBER = -2, 
85         STRING = -3, 
86         UNICODESET = -4, 
87         UNTERMINATED_QUOTE = -5,
88         BACKEDUP_TOO_FAR = -6;
89         
90     private static final int
91         //FIRST = 0,
92         //IN_NUMBER = 1,
93         //IN_SPACE = 2,
94         AFTER_QUOTE = 3,    // warning: order is important for switch statement
95         IN_STRING = 4, 
96         AFTER_BSLASH = 5, 
97         IN_QUOTE = 6;
98    
99     public String toString(int type, boolean backedupBefore) {
100         String s = backedup ? "@" : "*";
101         switch(type) {
102             case DONE: 
103                 return s+"Done"+s;
104             case BACKEDUP_TOO_FAR:
105                 return s+"Illegal Backup"+s;
106             case UNTERMINATED_QUOTE: 
107                 return s+"Unterminated Quote=" + getString() + s;
108             case STRING:
109                 return s+"s=" + getString() + s;
110             case NUMBER:
111                 return s+"n=" + getNumber() + s;
112             case UNICODESET:
113                 return s+"n=" + getUnicodeSet() + s;           
114             default:
115                 return s+"c=" + usf.getName(type,true) + s;
116         }
117     }
118     
119     private static final BagFormatter usf = new BagFormatter();
120     
121     public void backup() {
122         if (backedup) throw new IllegalArgumentException("backup too far");
123         backedup = true;
124         nextIndex = index;
125         index = lastIndex;
126     }
127     
128     /*
129     public int next2() {
130         boolean backedupBefore = backedup;
131         int result = next();
132         System.out.println(toString(result, backedupBefore));
133         return result;
134     }    
135     */
136     
137     public int next() {
138         if (backedup) {
139             backedup = false;
140             index = nextIndex;
141             return lastValue;
142         }
143         int cp = 0;
144         boolean inComment = false;
145         // clean off any leading whitespace or comments
146         while (true) {
147             if (index >= source.length()) return lastValue = DONE;
148             cp = nextChar();
149             if (inComment) {
150                 if (NEWLINE.contains(cp)) inComment = false;
151             } else {
152                 if (cp == '#') inComment = true;
153                 else if (!whiteSpace.contains(cp)) break;
154             }
155         }
156         // record the last index in case we have to backup
157         lastIndex = index;
158         
159         if (cp == '[') {
160             ParsePosition pos = new ParsePosition(index-1);
161             unicodeSet = new UnicodeSet(source,pos,symbolTable);
162             index = pos.getIndex();
163             return lastValue = UNICODESET;
164         }
165         // get syntax character
166         if (syntax.contains(cp)) return lastValue = cp;
167         
168         // get number, if there is one
169         if (UCharacter.getType(cp) == Character.DECIMAL_DIGIT_NUMBER) {
170             number = UCharacter.getNumericValue(cp);
171             while (index < source.length()) {
172                 cp = nextChar();
173                 if (UCharacter.getType(cp) != Character.DECIMAL_DIGIT_NUMBER) {
174                     index -= UTF16.getCharCount(cp); // BACKUP!
175                     break;
176                 }
177                 number *= 10;
178                 number += UCharacter.getNumericValue(cp);
179             }
180             return lastValue =  NUMBER;
181         }
182         buffer.setLength(0);
183         int status = IN_STRING;
184         main:
185         while (true) {
186             switch (status) {
187                 case AFTER_QUOTE: // check for double ''?
188                     if (cp == QUOTE) {
189                         UTF16.append(buffer, QUOTE);
190                         status = IN_QUOTE;
191                         break;
192                     }
193                     // OTHERWISE FALL THROUGH!!!
194                 case IN_STRING: 
195                     if (cp == QUOTE) status = IN_QUOTE;
196                     else if (cp == BSLASH) status = AFTER_BSLASH;
197                     else if (non_string.contains(cp)) {
198                         index -= UTF16.getCharCount(cp); // BACKUP!
199                         break main;
200                     } else UTF16.append(buffer,cp);
201                     break;
202                 case IN_QUOTE:
203                     if (cp == QUOTE) status = AFTER_QUOTE;
204                     else UTF16.append(buffer,cp);
205                     break;
206                 case AFTER_BSLASH:
207                     switch(cp) {
208                         case 'n': cp = '\n'; break;
209                         case 'r': cp = '\r'; break;
210                         case 't': cp = '\t'; break;
211                     }
212                     UTF16.append(buffer,cp);
213                     status = IN_STRING;
214                     break;
215                 default: throw new IllegalArgumentException("Internal Error");
216             }
217             if (index >= source.length()) break;
218             cp = nextChar();
219         }
220         if (status > IN_STRING) return lastValue = UNTERMINATED_QUOTE;
221         return lastValue =  STRING;
222     }
223     
224     public String getString() {
225         return buffer.toString();
226     }
227     
228     public String toString() {
229         return source.substring(0,index) + "$$$" + source.substring(index);
230     }
231     
232     public long getNumber() {
233         return number;
234     }
235     
236     public UnicodeSet getUnicodeSet() {
237         return unicodeSet;
238     }
239     
240     private int nextChar() {
241         int cp = UTF16.charAt(source,index);
242         index += UTF16.getCharCount(cp);
243         return cp;
244     }
245     public int getIndex() {
246         return index;
247     }
248     public String getSource() {
249         return source;
250     }
251     public UnicodeSet getSyntax() {
252         return syntax;
253     }
254     public UnicodeSet getWhiteSpace() {
255         return whiteSpace;
256     }
257     public void setSyntax(UnicodeSet set) {
258         syntax = set;
259         fixSets();
260     }
261     public void setWhiteSpace(UnicodeSet set) {
262         whiteSpace = set;
263         fixSets();
264     }
265     
266     public Set getLookedUpItems() {
267         return symbolTable.itemsLookedUp;
268     }
269     
270     public void addSymbol(String var, String value, int start, int limit) {
271         // the limit is after the ';', so remove it
272         --limit;
273         char[] body = new char[limit - start];
274         value.getChars(start, limit, body, 0);
275         symbolTable.add(var, body);
276     }
277     
278     public class TokenSymbolTable implements SymbolTable {
279         Map contents = new HashMap();
280         Set itemsLookedUp = new HashSet();
281             
282         public void add(String var, char[] body) {
283             // start from 1 to avoid the $
284             contents.put(var.substring(1), body);
285         }
286             
287         /* (non-Javadoc)
288          * @see com.ibm.icu.text.SymbolTable#lookup(java.lang.String)
289          */
290         public char[] lookup(String s) {
291             itemsLookedUp.add('$' + s);
292             return (char[])contents.get(s);
293         }
294     
295         /* (non-Javadoc)
296          * @see com.ibm.icu.text.SymbolTable#lookupMatcher(int)
297          */
298         public UnicodeMatcher lookupMatcher(int ch) {
299             // TODO Auto-generated method stub
300             return null;
301         }
302     
303         /* (non-Javadoc)
304          * @see com.ibm.icu.text.SymbolTable#parseReference(java.lang.String, java.text.ParsePosition, int)
305          */
306         public String parseReference(String text, ParsePosition pos, int limit) {
307             int cp;
308             int start = pos.getIndex();
309             int i;
310             for (i = start; i < limit; i += UTF16.getCharCount(cp)) {
311                 cp = UTF16.charAt(text, i);
312                 if (!com.ibm.icu.lang.UCharacter.isUnicodeIdentifierPart(cp)) {
313                     break;
314                 }
315             }
316             pos.setIndex(i);
317             return text.substring(start,i);
318         }
319         
320     }
321 }
322
323 //#endif