Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(183)

Side by Side Diff: class-dump/src/CDTypeParser.m

Issue 7793008: Add the 3.3.3 sources for class-dump. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/
Patch Set: Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « class-dump/src/CDTypeParser.h ('k') | class-dump/src/CDUnitTests-Info.plist » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // -*- mode: ObjC -*-
2
3 // This file is part of class-dump, a utility for examining the Objective-C seg ment of Mach-O files.
4 // Copyright (C) 1997-1998, 2000-2001, 2004-2010 Steve Nygard.
5
6 #import "CDTypeParser.h"
7
8 #include <assert.h>
9 #import "CDMethodType.h"
10 #import "CDType.h"
11 #import "CDTypeName.h"
12 #import "CDTypeLexer.h"
13 #import "NSString-Extensions.h"
14
15 NSString *CDSyntaxError = @"Syntax Error";
16 NSString *CDTypeParserErrorDomain = @"CDTypeParserErrorDomain";
17
18 static BOOL debug = NO;
19
20 static NSString *CDTokenDescription(int token)
21 {
22 if (token < 128)
23 return [NSString stringWithFormat:@"%d(%c)", token, token];
24
25 return [NSString stringWithFormat:@"%d", token];
26 }
27
28 @implementation CDTypeParser
29
30 - (id)initWithType:(NSString *)aType;
31 {
32 NSMutableString *str;
33
34 if ([super init] == nil)
35 return nil;
36
37 // Do some preprocessing first: Replace "<unnamed>::" with just "unnamed::".
38 str = [aType mutableCopy];
39 [str replaceOccurrencesOfString:@"<unnamed>::" withString:@"unnamed::" optio ns:0 range:NSMakeRange(0, [aType length])];
40
41 lexer = [[CDTypeLexer alloc] initWithString:str];
42 lookahead = 0;
43
44 [str release];
45
46 return self;
47 }
48
49 - (void)dealloc;
50 {
51 [lexer release];
52
53 [super dealloc];
54 }
55
56 - (CDTypeLexer *)lexer;
57 {
58 return lexer;
59 }
60
61 - (NSArray *)parseMethodType:(NSError **)error;
62 {
63 NSArray *result;
64
65 *error = nil;
66
67 @try {
68 lookahead = [lexer scanNextToken];
69 result = [self _parseMethodType];
70 }
71 @catch (NSException *exception) {
72 NSDictionary *userInfo;
73 int code;
74
75 // Obviously I need to figure out a sane method of dealing with errors h ere. This is not.
76 if ([[exception name] isEqual:CDSyntaxError]) {
77 code = CDTypeParserCodeSyntaxError;
78 userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:@"Syntax Err or", @"reason",
79 [NSString stringWithFormat:@"Syntax Error, %@:\n\t type: %@\n\tremaining: %@",
80 [exception reason], [lexe r string], [lexer remainingString]], @"explanation",
81 [lexer string], @"type",
82 [lexer remainingString], @"remainin g string",
83 nil];
84 } else {
85 code = CDTypeParserCodeDefault;
86 userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:[exception r eason], @"reason",
87 [lexer string], @"type",
88 [lexer remainingString], @"remainin g string",
89 nil];
90 }
91 *error = [NSError errorWithDomain:CDTypeParserErrorDomain code:code user Info:userInfo];
92 [userInfo release];
93
94 result = nil;
95 }
96
97 return result;
98 }
99
100 - (CDType *)parseType:(NSError **)error;
101 {
102 CDType *result;
103
104 *error = nil;
105
106 @try {
107 lookahead = [lexer scanNextToken];
108 result = [self _parseType];
109 }
110 @catch (NSException *exception) {
111 NSDictionary *userInfo;
112 int code;
113
114 // Obviously I need to figure out a sane method of dealing with errors h ere. This is not.
115 if ([[exception name] isEqual:CDSyntaxError]) {
116 code = CDTypeParserCodeSyntaxError;
117 userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:@"Syntax Err or", @"reason",
118 [NSString stringWithFormat:@"%@:\n\ t type: %@\n\tremaining: %@",
119 [exception reason], [lexe r string], [lexer remainingString]], @"explanation",
120 [lexer string], @"type",
121 [lexer remainingString], @"remainin g string",
122 nil];
123 } else {
124 code = CDTypeParserCodeDefault;
125 userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:[exception r eason], @"reason",
126 [lexer string], @"type",
127 [lexer remainingString], @"remainin g string",
128 nil];
129 }
130 *error = [NSError errorWithDomain:CDTypeParserErrorDomain code:code user Info:userInfo];
131 [userInfo release];
132
133 result = nil;
134 }
135
136 return result;
137 }
138
139 @end
140
141 @implementation CDTypeParser (Private)
142
143 - (void)match:(int)token;
144 {
145 [self match:token enterState:[lexer state]];
146 }
147
148 - (void)match:(int)token enterState:(int)newState;
149 {
150 if (lookahead == token) {
151 if (debug) NSLog(@"matched %@", CDTokenDescription(token));
152 [lexer setState:newState];
153 lookahead = [lexer scanNextToken];
154 } else {
155 [NSException raise:CDSyntaxError format:@"expected token %@, got %@",
156 CDTokenDescription(token),
157 CDTokenDescription(lookahead)];
158 }
159 }
160
161 - (void)error:(NSString *)errorString;
162 {
163 [NSException raise:CDSyntaxError format:@"%@", errorString];
164 }
165
166 - (NSArray *)_parseMethodType;
167 {
168 NSMutableArray *methodTypes;
169 CDMethodType *aMethodType;
170 CDType *type;
171 NSString *number;
172
173 methodTypes = [NSMutableArray array];
174
175 // Has to have at least one pair for the return type;
176 // Probably needs at least two more, for object and selector
177 // So it must be <type><number><type><number><type><number>. Three pairs at a minimum.
178
179 do {
180 type = [self _parseType];
181 number = [self parseNumber];
182
183 aMethodType = [[CDMethodType alloc] initWithType:type offset:number];
184 [methodTypes addObject:aMethodType];
185 [aMethodType release];
186 } while ([self isTokenInTypeStartSet:lookahead]);
187
188 return methodTypes;
189 }
190
191 // Plain object types can be:
192 // @ - plain id type
193 // @"NSObject" - NSObject *
194 // @"<MyProtocol>" - id <MyProtocol>
195 // But these can also be part of a structure, with the field name in quotes befo re the type:
196 // "foo"i"bar"i - int foo, int bar
197 // "foo"@"bar"i - id foo, int bar
198 // "foo"@"Foo""bar"i - Foo *foo, int bar
199 // So this is where we need to be careful.
200 //
201 // I'm going to make a simplifying assumption: Either the structure/union has m ember names,
202 // or is doesn't, it can't have some names and be missing others.
203 // The two key tests are:
204 // {my_struct3="field1"@"field2"i}
205 // {my_struct4="field1"@"NSObject""field2"i}
206
207 - (CDType *)_parseType;
208 {
209 return [self _parseTypeInStruct:NO];
210 }
211
212 - (CDType *)_parseTypeInStruct:(BOOL)isInStruct;
213 {
214 CDType *result;
215
216 if (lookahead == 'r'
217 || lookahead == 'n'
218 || lookahead == 'N'
219 || lookahead == 'o'
220 || lookahead == 'O'
221 || lookahead == 'R'
222 || lookahead == 'V') { // modifiers
223 int modifier;
224 CDType *unmodifiedType;
225 modifier = lookahead;
226 [self match:modifier];
227
228 if ([self isTokenInTypeStartSet:lookahead])
229 unmodifiedType = [self _parseTypeInStruct:isInStruct];
230 else
231 unmodifiedType = nil;
232 result = [[CDType alloc] initModifier:modifier type:unmodifiedType];
233 } else if (lookahead == '^') { // pointer
234 CDType *type;
235
236 [self match:'^'];
237 if (lookahead == TK_QUOTED_STRING || lookahead == '}' || lookahead == ') ') {
238 type = [[CDType alloc] initSimpleType:'v'];
239 // Safari on 10.5 has: "m_function"{?="__pfn"^"__delta"i}
240 result = [[CDType alloc] initPointerType:type];
241 [type release];
242 } else {
243 type = [self _parseTypeInStruct:isInStruct];
244 result = [[CDType alloc] initPointerType:type];
245 }
246 } else if (lookahead == 'b') { // bitfield
247 NSString *number;
248
249 [self match:'b'];
250 number = [self parseNumber];
251 result = [[CDType alloc] initBitfieldType:number];
252 } else if (lookahead == '@') { // id
253 [self match:'@'];
254 #if 0
255 if (lookahead == TK_QUOTED_STRING) {
256 NSLog(@"%s, quoted string ahead, shouldCheckFieldNames: %d, end: %d" ,
257 _cmd, shouldCheckFieldNames, [[lexer scanner] isAtEnd]);
258 if ([[lexer scanner] isAtEnd] == NO)
259 NSLog(@"next character: %d (%c), isInTypeStartSet: %d", [lexer p eekChar], [lexer peekChar], [self isTokenInTypeStartSet:[lexer peekChar]]);
260 }
261 #endif
262 if (lookahead == TK_QUOTED_STRING && (isInStruct == NO || [[lexer lexTex t] isFirstLetterUppercase] || [self isTokenInTypeStartSet:[lexer peekChar]] == N O)) {
263 NSString *str;
264 CDTypeName *typeName;
265
266 str = [lexer lexText];
267 if ([str hasPrefix:@"<"] && [str hasSuffix:@">"]) {
268 str = [str substringWithRange:NSMakeRange(1, [str length] - 2)];
269 result = [[CDType alloc] initIDTypeWithProtocols:[str components SeparatedByString:@","]];
270 } else {
271 typeName = [[CDTypeName alloc] init];
272 [typeName setName:str];
273 result = [[CDType alloc] initIDType:typeName];
274 [typeName release];
275 }
276
277 [self match:TK_QUOTED_STRING];
278 } else {
279 result = [[CDType alloc] initIDType:nil];
280 }
281 } else if (lookahead == '{') { // structure
282 CDTypeName *typeName;
283 NSArray *optionalMembers;
284 CDTypeLexerState savedState;
285
286 savedState = [lexer state];
287 [self match:'{' enterState:CDTypeLexerStateIdentifier];
288 typeName = [self parseTypeName];
289 optionalMembers = [self parseOptionalMembers];
290 [self match:'}' enterState:savedState];
291
292 result = [[CDType alloc] initStructType:typeName members:optionalMembers ];
293 } else if (lookahead == '(') { // union
294 CDTypeLexerState savedState;
295
296 savedState = [lexer state];
297 [self match:'(' enterState:CDTypeLexerStateIdentifier];
298 if (lookahead == TK_IDENTIFIER) {
299 CDTypeName *typeName;
300 NSArray *optionalMembers;
301
302 typeName = [self parseTypeName];
303 optionalMembers = [self parseOptionalMembers];
304 [self match:')' enterState:savedState];
305
306 result = [[CDType alloc] initUnionType:typeName members:optionalMemb ers];
307 } else {
308 NSArray *unionTypes;
309
310 unionTypes = [self parseUnionTypes];
311 [self match:')' enterState:savedState];
312
313 result = [[CDType alloc] initUnionType:nil members:unionTypes];
314 }
315 } else if (lookahead == '[') { // array
316 NSString *number;
317 CDType *type;
318
319 [self match:'['];
320 number = [self parseNumber];
321 type = [self _parseType];
322 [self match:']'];
323
324 result = [[CDType alloc] initArrayType:type count:number];
325 } else if ([self isTokenInSimpleTypeSet:lookahead]) { // simple type
326 int simpleType;
327
328 simpleType = lookahead;
329 [self match:simpleType];
330 result = [[CDType alloc] initSimpleType:simpleType];
331 } else {
332 result = nil;
333 [NSException raise:CDSyntaxError format:@"expected (many things), got %@ ", CDTokenDescription(lookahead)];
334 }
335
336 return [result autorelease];
337 }
338
339 // This seems to be used in method types -- no names
340 - (NSArray *)parseUnionTypes;
341 {
342 NSMutableArray *members;
343
344 members = [NSMutableArray array];
345
346 while ([self isTokenInTypeSet:lookahead]) {
347 CDType *aType;
348
349 aType = [self _parseType];
350 //[aType setVariableName:@"___"];
351 [members addObject:aType];
352 }
353
354 return members;
355 }
356
357 - (NSArray *)parseOptionalMembers;
358 {
359 NSArray *result;
360
361 if (lookahead == '=') {
362 [self match:'='];
363 result = [self parseMemberList];
364 } else
365 result = nil;
366
367 return result;
368 }
369
370 - (NSArray *)parseMemberList;
371 {
372 NSMutableArray *result;
373
374 //NSLog(@" > %s", _cmd);
375
376 result = [NSMutableArray array];
377
378 while (lookahead == TK_QUOTED_STRING || [self isTokenInTypeSet:lookahead])
379 [result addObject:[self parseMember]];
380
381 //NSLog(@"< %s", _cmd);
382
383 return result;
384 }
385
386 - (CDType *)parseMember;
387 {
388 CDType *result;
389
390 //NSLog(@" > %s", _cmd);
391
392 if (lookahead == TK_QUOTED_STRING) {
393 NSString *identifier = nil;
394
395 while (lookahead == TK_QUOTED_STRING) {
396 if (identifier == nil)
397 identifier = [lexer lexText];
398 else {
399 // TextMate 1.5.4 has structures like... "storage""stack"{etc} - - two quoted strings next to each other.
400 identifier = [NSString stringWithFormat:@"%@__%@", identifier, [ lexer lexText]];
401 }
402 [self match:TK_QUOTED_STRING];
403 }
404
405 //NSLog(@"got identifier: %@", identifier);
406 result = [self _parseTypeInStruct:YES];
407 [result setVariableName:identifier];
408 //NSLog(@"And parsed struct type.");
409 } else {
410 result = [self _parseTypeInStruct:YES];
411 }
412
413 //NSLog(@"< %s", _cmd);
414 return result;
415 }
416
417 - (CDTypeName *)parseTypeName;
418 {
419 CDTypeName *typeName;
420
421 typeName = [[[CDTypeName alloc] init] autorelease];
422 [typeName setName:[self parseIdentifier]];
423
424 if (lookahead == '<') {
425 CDTypeLexerState savedState;
426
427 savedState = [lexer state];
428 [self match:'<' enterState:CDTypeLexerStateTemplateTypes];
429 [typeName addTemplateType:[self parseTypeName]];
430 while (lookahead == ',') {
431 [self match:','];
432 [typeName addTemplateType:[self parseTypeName]];
433 }
434 [self match:'>' enterState:savedState];
435
436 if ([lexer state] == CDTypeLexerStateTemplateTypes) {
437 if (lookahead == TK_IDENTIFIER) {
438 NSString *suffix = [lexer lexText];
439
440 [self match:TK_IDENTIFIER];
441 [typeName setSuffix:suffix];
442 }
443 }
444 }
445
446 #if 0
447 // This breaks a bunch of the unit tests... need to figure out what's up wit h that first.
448 // We'll treat "?" as no name, returning nil here instead of testing the typ e name for this later.
449 if ([[typeName name] isEqualToString:@"?"] && [typeName isTemplateType] == N O)
450 typeName = nil;
451 #endif
452
453 return typeName;
454 }
455
456 - (NSString *)parseIdentifier;
457 {
458 NSString *result = nil;
459
460 if (lookahead == TK_IDENTIFIER) {
461 result = [lexer lexText];
462 [self match:TK_IDENTIFIER];
463 }
464
465 return result;
466 }
467
468 - (NSString *)parseNumber;
469 {
470 if (lookahead == TK_NUMBER) {
471 NSString *result;
472
473 result = [lexer lexText];
474 [self match:TK_NUMBER];
475 return result;
476 }
477
478 return nil;
479 }
480
481 - (BOOL)isTokenInModifierSet:(int)aToken;
482 {
483 if (aToken == 'r'
484 || aToken == 'n'
485 || aToken == 'N'
486 || aToken == 'o'
487 || aToken == 'O'
488 || aToken == 'R'
489 || aToken == 'V')
490 return YES;
491
492 return NO;
493 }
494
495 - (BOOL)isTokenInSimpleTypeSet:(int)aToken;
496 {
497 if (aToken == 'c'
498 || aToken == 'i'
499 || aToken == 's'
500 || aToken == 'l'
501 || aToken == 'q'
502 || aToken == 'C'
503 || aToken == 'I'
504 || aToken == 'S'
505 || aToken == 'L'
506 || aToken == 'Q'
507 || aToken == 'f'
508 || aToken == 'd'
509 || aToken == 'B'
510 || aToken == 'v'
511 || aToken == '*'
512 || aToken == '#'
513 || aToken == ':'
514 || aToken == '%'
515 || aToken == '?')
516 return YES;
517
518 return NO;
519 }
520
521 - (BOOL)isTokenInTypeSet:(int)aToken;
522 {
523 if ([self isTokenInModifierSet:aToken]
524 || [self isTokenInSimpleTypeSet:aToken]
525 || aToken == '^'
526 || aToken == 'b'
527 || aToken == '@'
528 || aToken == '{'
529 || aToken == '('
530 || aToken == '[')
531 return YES;
532
533 return NO;
534 }
535
536 - (BOOL)isTokenInTypeStartSet:(int)aToken;
537 {
538 if (aToken == 'r'
539 || aToken == 'n'
540 || aToken == 'N'
541 || aToken == 'o'
542 || aToken == 'O'
543 || aToken == 'R'
544 || aToken == 'V'
545 || aToken == '^'
546 || aToken == 'b'
547 || aToken == '@'
548 || aToken == '{'
549 || aToken == '('
550 || aToken == '['
551 || [self isTokenInSimpleTypeSet:aToken])
552 return YES;
553
554 return NO;
555 }
556
557 @end
OLDNEW
« no previous file with comments | « class-dump/src/CDTypeParser.h ('k') | class-dump/src/CDUnitTests-Info.plist » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698