001 /* Copyright 2000, 2001, Compaq Computer Corporation */ 002 003 /* ========================================================================= 004 * DescriptorParser.java 005 * ========================================================================= */ 006 007 package javafe.reader; 008 009 import java.util.*; 010 011 import javafe.ast.*; 012 import javafe.util.*; 013 014 /* ------------------------------------------------------------------------- 015 * DescriptorParser 016 * ------------------------------------------------------------------------- */ 017 018 /** 019 * Parses various kinds of class-file-format descriptor strings into 020 * abstract syntax. 021 */ 022 023 class DescriptorParser 024 { 025 /* -- package class methods ---------------------------------------------- */ 026 027 /** 028 * Return a type name for a given class-file class-name string. 029 * @param s the class name to parse 030 * @return the type name encoded by s 031 */ 032 //@ ensures \result != null; 033 static TypeName parseClass(/*@ non_null @*/ String s) 034 throws ClassFormatError 035 { 036 // tokenize the string into a sequence of identifiers delimited by slashes 037 // check syntax of identifiers? ??? 038 039 StringTokenizer tokenizer = new StringTokenizer(s, "/$"); 040 041 int count = tokenizer.countTokens(); 042 javafe.util.Assert.notFalse(count>0); //@ nowarn Pre; 043 044 Identifier[] identifiers = new Identifier[count]; 045 int[] locations1 = new int[count]; 046 int[] locations2 = new int[count-1]; 047 048 for (int i = 0; tokenizer.hasMoreTokens(); i++) 049 { 050 identifiers[i] = Identifier.intern(tokenizer.nextToken()); 051 //@ assert identifiers[i] != null; 052 locations1[i] = classLocation; 053 054 if (i<count-1) 055 locations2[i] = classLocation; 056 } 057 //@ assume \nonnullelements(identifiers); 058 /*@ assume (\forall int i; (0<=i && i<locations1.length) 059 ==> locations1[i] != Location.NULL); */ 060 /*@ assume (\forall int i; (0<=i && i<locations2.length) 061 ==> locations2[i] != Location.NULL); */ 062 063 return TypeName.make(Name.make(locations1, locations2, 064 IdentifierVec.make(identifiers))); 065 } 066 067 /** 068 * Return a type for a given class-file field descriptor string. 069 * @param s the field descriptor to parse 070 * @return the type encoded by s 071 */ 072 //@ requires s != null; 073 //@ ensures \result != null; 074 //@ ensures \result.syntax; 075 static Type parseField(String s) 076 throws ClassFormatError 077 { 078 // parse the descriptor as a type and make sure it's only a type 079 080 StringScanner scanner = new StringScanner(s); 081 Type type = parseType(scanner); 082 083 if (scanner.index<s.length()) 084 throw new ClassFormatError("junk after field descriptor"); 085 086 return type; 087 } 088 089 /** 090 * Return a method signature for a given class-file method descriptor string. 091 * @param s the method descriptor to parse 092 * @return the method signature encoded by s 093 */ 094 //@ requires s != null; 095 //@ ensures \result != null; 096 static MethodSignature parseMethod(String s) 097 throws ClassFormatError 098 { 099 // check the format of the method descriptor and construct a string scanner 100 101 int length = s.length(); 102 103 if (length<3) 104 throw new ClassFormatError("incomplete method descriptor"); 105 106 if (s.charAt(0) != '(') 107 throw new ClassFormatError("invalid method descriptor"); 108 109 StringScanner scanner = new StringScanner(s); 110 111 scanner.index++; 112 113 // parse the parameter types in the method descriptor and accumulate them 114 // in a method signature 115 116 MethodSignature signature = new MethodSignature(classLocation); 117 118 while (s.charAt(scanner.index) != ')') 119 { 120 signature.appendParameter(parseType(scanner)); 121 122 if (scanner.index>=length) 123 throw new ClassFormatError("incomplete method descriptor"); 124 } 125 126 scanner.index++; 127 128 // parse the return type of the method descriptor and store it in the 129 // method signature 130 131 signature.setReturn(parseReturn(scanner)); 132 133 if (scanner.index<length) 134 throw new ClassFormatError("junk after method descriptor"); 135 136 return signature; 137 } 138 139 /* -- package class variables -------------------------------------------- */ 140 141 /** 142 * A dummy location representing the class being parsed. 143 * Should be set externally. 144 */ 145 //@ invariant classLocation != Location.NULL; 146 static int classLocation = Location.createFakeLoc("[unknown]"); 147 148 /* -- private class methods ---------------------------------------------- */ 149 150 /** 151 * Parse a type from a given class-file field descriptor string. 152 * @param scanner the string scanner to parse from (modified to point to 153 * the next character after the parsed type) 154 * @return the type encoded by scanner 155 */ 156 //@ requires scanner != null; 157 //@ ensures \result != null; 158 //@ ensures \result.syntax; 159 private static Type parseType(StringScanner scanner) 160 throws ClassFormatError 161 { 162 // parse the type according to the leading character 163 // it would be more efficient to share primitive types ??? 164 165 String s = scanner.s; 166 int index = scanner.index; 167 168 if (index>=s.length()) 169 throw new ClassFormatError("empty type descriptor"); 170 171 switch (s.charAt(index)) 172 { 173 case 'B': 174 scanner.index++; 175 return PrimitiveType.make(TagConstants.BYTETYPE, classLocation); 176 177 case 'C': 178 scanner.index++; 179 return PrimitiveType.make(TagConstants.CHARTYPE, classLocation); 180 181 case 'D': 182 scanner.index++; 183 return PrimitiveType.make(TagConstants.DOUBLETYPE, classLocation); 184 185 case 'F': 186 scanner.index++; 187 return PrimitiveType.make(TagConstants.FLOATTYPE, classLocation); 188 189 case 'I': 190 scanner.index++; 191 return PrimitiveType.make(TagConstants.INTTYPE, classLocation); 192 193 case 'J': 194 scanner.index++; 195 return PrimitiveType.make(TagConstants.LONGTYPE, classLocation); 196 197 case 'L': 198 { 199 // extract the class name and parse it 200 201 int start = index+1, stop = s.indexOf(';', start); 202 203 if (stop<0) 204 throw new ClassFormatError("unterminated type name"); 205 206 scanner.index = stop+1; 207 208 return parseClass(s.substring(start, stop)); 209 } 210 211 case 'S': 212 scanner.index++; 213 return PrimitiveType.make(TagConstants.SHORTTYPE, classLocation); 214 215 case 'Z': 216 scanner.index++; 217 return PrimitiveType.make(TagConstants.BOOLEANTYPE, classLocation); 218 219 case '[': 220 // parse the element type and construct an array type from it 221 222 scanner.index++; 223 224 return ArrayType.make(parseType(scanner), classLocation); 225 226 default: 227 throw new ClassFormatError("unknown type character"); 228 } 229 } 230 231 /** 232 * Parse a type from a given class-file return descriptor string. 233 * @param scanner the string scanner to parse from (modified to point to 234 * the next character after the parsed type) 235 * @return the type encoded by scanner 236 */ 237 //@ requires scanner != null; 238 //@ ensures \result != null; 239 //@ ensures \result.syntax; 240 private static Type parseReturn(StringScanner scanner) 241 throws ClassFormatError 242 { 243 // look for the void return descriptor 244 245 String s = scanner.s; 246 int index = scanner.index; 247 248 if (index>=s.length()) 249 throw new ClassFormatError("empty return descriptor"); 250 251 if (s.charAt(index)=='V') 252 { 253 scanner.index++; 254 return PrimitiveType.make(TagConstants.VOIDTYPE, classLocation); 255 } 256 257 return parseType(scanner); 258 } 259 260 } 261 262 /* ------------------------------------------------------------------------- 263 * StringScanner 264 * ------------------------------------------------------------------------- */ 265 266 /** 267 * A string and the index of the next character to scan from it. 268 */ 269 270 class StringScanner { 271 272 /* -- package instance methods ------------------------------------------- */ 273 274 /** 275 * Construct a new string scanner from a given string. 276 * @param s the string 277 */ 278 //@ requires s != null; 279 StringScanner(String s) 280 { 281 this.s = s; 282 } 283 284 /* -- package instance variables ----------------------------------------- */ 285 286 /** 287 * The string to be scanned. 288 * Initialized by constructor. 289 */ 290 //@ invariant s != null; 291 String s; 292 293 /** 294 * The index of the next character to scan. 295 */ 296 int index = 0; 297 298 } 299