Skip to content

Commit

Permalink
Implemented class declaration parsing and renamed GBTokenizer consume…
Browse files Browse the repository at this point in the history
… with block quit parameter to stop.
  • Loading branch information
tomaz committed Jul 27, 2010
1 parent 851f785 commit 8bebbe8
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 75 deletions.
212 changes: 152 additions & 60 deletions Parsing/GBObjectiveCParser.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ - (PKTokenizer *)tokenizerWithInputString:(NSString *)input;

@end

@interface GBObjectiveCParser (ClassDefinitionParsing)
@interface GBObjectiveCParser (DefinitionParsing)

- (void)matchClassDefinition;
- (void)matchCategoryDefinition;
Expand All @@ -34,13 +34,25 @@ - (void)matchIvarsForProvider:(GBIvarsProvider *)provider;
- (void)matchMethodDefinitionsForProvider:(GBMethodsProvider *)provider;
- (BOOL)matchMethodDefinitionForProvider:(GBMethodsProvider *)provider;
- (BOOL)matchPropertyDefinitionForProvider:(GBMethodsProvider *)provider;
- (BOOL)matchMethodDataForProvider:(GBMethodsProvider *)provider from:(NSString *)start to:(NSString *)end;

@end

@interface GBObjectiveCParser (DeclarationsParsing)

- (void)matchClassDeclaration;
- (void)matchCategoryDeclaration;
- (void)matchMethodDeclarationsForProvider:(GBMethodsProvider *)provider;
- (BOOL)matchMethodDeclarationForProvider:(GBMethodsProvider *)provider;
- (void)consumeMethodBody;

@end

@interface GBObjectiveCParser (CommonParsing)

- (BOOL)matchNextObject;
- (BOOL)matchObjectDefinition;
- (BOOL)matchObjectDeclaration;
- (BOOL)matchMethodDataForProvider:(GBMethodsProvider *)provider from:(NSString *)start to:(NSString *)end;

@end

Expand Down Expand Up @@ -97,7 +109,7 @@ - (PKTokenizer *)tokenizerWithInputString:(NSString *)input {

#pragma mark -

@implementation GBObjectiveCParser (ClassDefinitionParsing)
@implementation GBObjectiveCParser (DefinitionParsing)

- (void)matchClassDefinition {
// @interface CLASSNAME
Expand Down Expand Up @@ -148,21 +160,21 @@ - (void)matchSuperclassForClass:(GBClassData *)class {
}

- (void)matchAdoptedProtocolForProvider:(GBAdoptedProtocolsProvider *)provider {
[self.tokenizer consumeFrom:@"<" to:@">" usingBlock:^(PKToken *token, BOOL *consume, BOOL *quit) {
[self.tokenizer consumeFrom:@"<" to:@">" usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
if ([token matches:@","]) return;
GBProtocolData *protocol = [[GBProtocolData alloc] initWithName:[token stringValue]];
[provider registerProtocol:protocol];
}];
}

- (void)matchIvarsForProvider:(GBIvarsProvider *)provider {
[self.tokenizer consumeFrom:@"{" to:@"}" usingBlock:^(PKToken *token, BOOL *consume, BOOL *quit) {
[self.tokenizer consumeFrom:@"{" to:@"}" usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
if ([token matches:@"@private"]) return;
if ([token matches:@"@protected"]) return;
if ([token matches:@"@public"]) return;

NSMutableArray *components = [NSMutableArray array];
[self.tokenizer consumeTo:@";" usingBlock:^(PKToken *token, BOOL *consume, BOOL *quit) {
[self.tokenizer consumeTo:@";" usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
[components addObject:[token stringValue]];
}];

Expand All @@ -173,7 +185,7 @@ - (void)matchIvarsForProvider:(GBIvarsProvider *)provider {
}

- (void)matchMethodDefinitionsForProvider:(GBMethodsProvider *)provider {
[self.tokenizer consumeTo:@"@end" usingBlock:^(PKToken *token, BOOL *consume, BOOL *quit) {
[self.tokenizer consumeTo:@"@end" usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
if ([self matchMethodDefinitionForProvider:provider] || [self matchPropertyDefinitionForProvider:provider]) {
*consume = NO;
}
Expand All @@ -188,44 +200,167 @@ - (BOOL)matchMethodDefinitionForProvider:(GBMethodsProvider *)provider {

- (BOOL)matchPropertyDefinitionForProvider:(GBMethodsProvider *)provider {
__block BOOL result = NO;
[self.tokenizer consumeFrom:@"@property" to:@";" usingBlock:^(PKToken *token, BOOL *consume, BOOL *quit) {
[self.tokenizer consumeFrom:@"@property" to:@";" usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
// Get attributes.
NSMutableArray *propertyAttributes = [NSMutableArray array];
[self.tokenizer consumeFrom:@"(" to:@")" usingBlock:^(PKToken *token, BOOL *consume, BOOL *quit) {
[self.tokenizer consumeFrom:@"(" to:@")" usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
if ([token matches:@","]) return;
[propertyAttributes addObject:[token stringValue]];
}];

// Get property types and name.
NSMutableArray *propertyComponents = [NSMutableArray array];
[self.tokenizer consumeTo:@";" usingBlock:^(PKToken *token, BOOL *consume, BOOL *quit) {
[self.tokenizer consumeTo:@";" usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
[propertyComponents addObject:[token stringValue]];
}];

// Register property.
GBMethodData *propertyData = [GBMethodData propertyDataWithAttributes:propertyAttributes components:propertyComponents];
[provider registerMethod:propertyData];
*consume = NO;
*quit = YES;
*stop = YES;
result = YES;
}];
return result;
}

@end

#pragma mark -

@implementation GBObjectiveCParser (DeclarationsParsing)

- (void)matchClassDeclaration {
// @implementation CLASSNAME
NSString *className = [[self.tokenizer lookahead:1] stringValue];
GBClassData *class = [GBClassData classDataWithName:className];
[self.store registerClass:class];
[self.tokenizer consume:2];
[self matchMethodDeclarationsForProvider:class.methods];
}

- (void)matchCategoryDeclaration {
}

- (void)matchMethodDeclarationsForProvider:(GBMethodsProvider *)provider {
[self.tokenizer consumeTo:@"@end" usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
if ([self matchMethodDeclarationForProvider:provider]) {
*consume = NO;
}
}];
}

- (BOOL)matchMethodDeclarationForProvider:(GBMethodsProvider *)provider {
if ([self matchMethodDataForProvider:provider from:@"+" to:@"{"]) {
[self consumeMethodBody];
return YES;
}
if ([self matchMethodDataForProvider:provider from:@"-" to:@"{"]) {
[self consumeMethodBody];
return YES;
}
return NO;
}

- (void)consumeMethodBody {
// This method assumes we're currently pointing to the first token after method's opening brace!
__block NSUInteger braceLevel = 1;
[self.tokenizer consumeTo:@"@end" usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
if ([token matches:@"{"]) {
braceLevel++;
return;
}
if ([token matches:@"}"]) {
if (--braceLevel == 0) *stop = YES;
return;
}
}];
}

@end

#pragma mark -

@implementation GBObjectiveCParser (CommonParsing)

- (BOOL)matchNextObject {
if ([self matchObjectDefinition]) return YES;
if ([self matchObjectDeclaration]) return YES;
return NO;
}

- (BOOL)matchObjectDefinition {
// Get data needed for distinguishing between class, category and extension definition.
BOOL isInterface = [[self.tokenizer currentToken] matches:@"@interface"];
BOOL isOpenParenthesis = [[self.tokenizer lookahead:2] matches:@"("];
BOOL isCloseParenthesis = [[self.tokenizer lookahead:3] matches:@")"];

// Found class extension definition.
if (isInterface && isOpenParenthesis && isCloseParenthesis) {
[self matchExtensionDefinition];
return YES;
}

// Found category definition.
if (isInterface && isOpenParenthesis) {
[self matchCategoryDefinition];
return YES;
}

// Found class definition.
if (isInterface) {
[self matchClassDefinition];
return YES;
}

// Get data needed for distinguishing between protocol definition and directive.
BOOL isProtocol = [[self.tokenizer currentToken] matches:@"@protocol"];
BOOL isDirective = [[self.tokenizer lookahead:2] matches:@";"] || [[self.tokenizer lookahead:2] matches:@","];

// Found protocol definition.
if (isProtocol && !isDirective) {
[self matchProtocolDefinition];
return YES;
}

return NO;
}

- (BOOL)matchObjectDeclaration {
// Get data needed for distinguishing between class and category declaration.
BOOL isImplementation = [[self.tokenizer currentToken] matches:@"@implementation"];
BOOL isOpenParenthesis = [[self.tokenizer lookahead:2] matches:@"("];

// Found category declaration.
if (isImplementation && isOpenParenthesis) {
// [self matchCategoryDeclaration];
// return YES;
return NO;
}

// Found class declaration.
if (isImplementation) {
[self matchClassDeclaration];
return YES;
}

return NO;
}

- (BOOL)matchMethodDataForProvider:(GBMethodsProvider *)provider from:(NSString *)start to:(NSString *)end {
// This method only matches class or instance methods, not properties!
__block BOOL result = NO;
GBMethodType methodType = [start isEqualToString:@"-"] ? GBMethodTypeInstance : GBMethodTypeClass;
[self.tokenizer consumeFrom:start to:end usingBlock:^(PKToken *token, BOOL *consume, BOOL *quit) {
[self.tokenizer consumeFrom:start to:end usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
// Get result types.
NSMutableArray *methodResult = [NSMutableArray array];
[self.tokenizer consumeFrom:@"(" to:@")" usingBlock:^(PKToken *token, BOOL *consume, BOOL *quit) {
[self.tokenizer consumeFrom:@"(" to:@")" usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
[methodResult addObject:[token stringValue]];
}];

// Get all arguments.
__block NSMutableArray *methodArgs = [NSMutableArray array];
[self.tokenizer consumeTo:end usingBlock:^(PKToken *token, BOOL *consume, BOOL *quit) {
[self.tokenizer consumeTo:end usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
// Get argument name.
NSString *argumentName = [token stringValue];
[self.tokenizer consume:1];
Expand All @@ -236,12 +371,12 @@ - (BOOL)matchMethodDataForProvider:(GBMethodsProvider *)provider from:(NSString
[self.tokenizer consume:1];

// Get argument types.
[self.tokenizer consumeFrom:@"(" to:@")" usingBlock:^(PKToken *token, BOOL *consume, BOOL *quit) {
[self.tokenizer consumeFrom:@"(" to:@")" usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
[argumentTypes addObject:[token stringValue]];
}];

// Get argument variable name.
if (![[self.tokenizer currentToken] matches:@";"]) {
if (![[self.tokenizer currentToken] matches:end]) {
argumentVar = [[self.tokenizer currentToken] stringValue];
[self.tokenizer consume:1];
}
Expand All @@ -260,54 +395,11 @@ - (BOOL)matchMethodDataForProvider:(GBMethodsProvider *)provider from:(NSString
GBMethodData *methodData = [GBMethodData methodDataWithType:methodType result:methodResult arguments:methodArgs];
[provider registerMethod:methodData];
*consume = NO;
*quit = YES;
*stop = YES;
result = YES;
}];
return result;
}

@end

#pragma mark -

@implementation GBObjectiveCParser (CommonParsing)

- (BOOL)matchNextObject {
// Get data needed for distinguishing between class, category and extension definition.
BOOL isInterface = [[self.tokenizer currentToken] matches:@"@interface"];
BOOL isOpenParenthesis = [[self.tokenizer lookahead:2] matches:@"("];
BOOL isCloseParenthesis = [[self.tokenizer lookahead:3] matches:@")"];

// Found class extension definition.
if (isInterface && isOpenParenthesis && isCloseParenthesis) {
[self matchExtensionDefinition];
return YES;
}

// Found category definition.
if (isInterface && isOpenParenthesis) {
[self matchCategoryDefinition];
return YES;
}

// Found class definition.
if (isInterface) {
[self matchClassDefinition];
return YES;
}

// Get data needed for distinguishing between protocol definition and directive.
BOOL isProtocol = [[self.tokenizer currentToken] matches:@"@protocol"];
BOOL isDirective = [[self.tokenizer lookahead:2] matches:@";"] || [[self.tokenizer lookahead:2] matches:@","];

// Found protocol definition.
if (isProtocol && !isDirective) {
[self matchProtocolDefinition];
return YES;
}

return NO;
}

@end

4 changes: 2 additions & 2 deletions Parsing/GBTokenizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
@param block The block to be called for each token.
@exception NSException Thrown if the given end token is `nil`.
*/
- (void)consumeTo:(NSString *)end usingBlock:(void (^)(PKToken *token, BOOL *consume, BOOL *quit))block;
- (void)consumeTo:(NSString *)end usingBlock:(void (^)(PKToken *token, BOOL *consume, BOOL *stop))block;

/** Enumerates and consumes all tokens starting at current token up until the given end token is detected.
Expand All @@ -99,7 +99,7 @@
@param block The block to be called for each token.
@exception NSException Thrown if the given end token is `nil`.
*/
- (void)consumeFrom:(NSString *)start to:(NSString *)end usingBlock:(void (^)(PKToken *token, BOOL *consume, BOOL *quit))block;
- (void)consumeFrom:(NSString *)start to:(NSString *)end usingBlock:(void (^)(PKToken *token, BOOL *consume, BOOL *stop))block;

/** Specifies whether we're at EOF.
Expand Down
4 changes: 2 additions & 2 deletions Parsing/GBTokenizer.m
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ - (void)consume:(NSUInteger)count {
self.tokenIndex += count;
}

- (void)consumeTo:(NSString *)end usingBlock:(void (^)(PKToken *token, BOOL *consume, BOOL *quit))block {
- (void)consumeTo:(NSString *)end usingBlock:(void (^)(PKToken *token, BOOL *consume, BOOL *stop))block {
[self consumeFrom:nil to:end usingBlock:block];
}

- (void)consumeFrom:(NSString *)start to:(NSString *)end usingBlock:(void (^)(PKToken *token, BOOL *consume, BOOL *quit))block {
- (void)consumeFrom:(NSString *)start to:(NSString *)end usingBlock:(void (^)(PKToken *token, BOOL *consume, BOOL *stop))block {
// Skip starting token.
if (start) {
if (![[self currentToken] matches:start]) return;
Expand Down
Loading

0 comments on commit 8bebbe8

Please sign in to comment.