Skip to content

Commit

Permalink
Added support for termination macros for method declaration and prope…
Browse files Browse the repository at this point in the history
…rties declaration
  • Loading branch information
groue committed Oct 15, 2011
1 parent a80da63 commit 3d2d2a8
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 24 deletions.
42 changes: 39 additions & 3 deletions Model/GBMethodData.m
Expand Up @@ -9,6 +9,7 @@
#import "GRMustache.h"
#import "GBMethodArgument.h"
#import "GBMethodData.h"
#import "RegexKitLite.h"

@interface GBMethodData ()

Expand Down Expand Up @@ -40,9 +41,44 @@ + (id)methodDataWithType:(GBMethodType)type result:(NSArray *)result arguments:(

+ (id)propertyDataWithAttributes:(NSArray *)attributes components:(NSArray *)components {
NSParameterAssert([components count] >= 2); // At least one return and the name!
NSMutableArray *results = [NSMutableArray arrayWithArray:components];
[results removeLastObject]; // Remove ;
GBMethodArgument *argument = [GBMethodArgument methodArgumentWithName:[components lastObject]];

// extract return type and property name
NSString *propertyName = nil;
NSMutableArray *results = [NSMutableArray array];
BOOL nextComponentIsBlockPropertyName = NO;
BOOL nextComponentIsBlockReturnComponent = NO;
NSUInteger parenthesisLevel = 0;
for (NSString *component in components) {
if ([component isEqualToString:@"^"]) {
[results addObject:component];
nextComponentIsBlockPropertyName = YES;
} else if (nextComponentIsBlockPropertyName) {
propertyName = component;
nextComponentIsBlockPropertyName = NO;
nextComponentIsBlockReturnComponent = YES;
} else if (nextComponentIsBlockReturnComponent) {
if (parenthesisLevel > 0 || [component isEqualToString:@"("]) {
[results addObject:component];
}
} else if ([component isMatchedByRegex:@"^[_a-zA-Z][_a-zA-Z0-9]*$"]) {
if (results.count == 0) {
[results addObject:component];
} else if (propertyName == nil) {
propertyName = component;
} else {
// ignore termination macro
}
} else if (propertyName == nil) {
[results addObject:component];
}
if ([component isEqualToString:@"("]) {
++parenthesisLevel;
} else if ([component isEqualToString:@")"]) {
--parenthesisLevel;
}
}

GBMethodArgument *argument = [GBMethodArgument methodArgumentWithName:propertyName];
return [[[self alloc] initWithType:GBMethodTypeProperty attributes:attributes result:results arguments:[NSArray arrayWithObject:argument]] autorelease];
}

Expand Down
51 changes: 30 additions & 21 deletions Parsing/GBObjectiveCParser.m
Expand Up @@ -261,8 +261,6 @@ - (BOOL)matchPropertyDefinitionForProvider:(GBMethodsProvider *)provider require
NSMutableArray *propertyComponents = [NSMutableArray array];
__block BOOL parseAttribute = NO;
__block NSUInteger parenthesisDepth = 0;
__block BOOL parseBlockName = NO;
__block NSString *blockName = nil;
[self.tokenizer consumeTo:@";" usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
if ([token matches:@"__attribute__"]) {
parseAttribute = YES;
Expand All @@ -276,14 +274,8 @@ - (BOOL)matchPropertyDefinitionForProvider:(GBMethodsProvider *)provider require
}
} else {
[propertyComponents addObject:[token stringValue]];
if (parseBlockName) {
blockName = [token stringValue];
parseBlockName = NO;
}
if ([token matches:@"^"]) parseBlockName = YES;
}
}];
if (blockName) [propertyComponents addObject:blockName];

// Register property.
GBMethodData *propertyData = [GBMethodData propertyDataWithAttributes:propertyAttributes components:propertyComponents];
Expand Down Expand Up @@ -507,7 +499,6 @@ - (BOOL)matchMethodDataForProvider:(GBMethodsProvider *)provider from:(NSString
__block NSString *argumentVar = nil;
__block NSMutableArray *argumentTypes = [NSMutableArray array];
__block NSMutableArray *terminationMacros = [NSMutableArray array];
__block BOOL isVarArg = NO;
if ([[self.tokenizer currentToken] matches:@":"]) {
[self.tokenizer consume:1];

Expand All @@ -524,24 +515,42 @@ - (BOOL)matchMethodDataForProvider:(GBMethodsProvider *)provider from:(NSString

// If we have variable args block following, consume the rest of the tokens to get optional termination macros.
if ([[self.tokenizer lookahead:0] matches:@","] && [[self.tokenizer lookahead:1] matches:@"..."]) {
isVarArg = YES;
[self.tokenizer consume:2];
[self.tokenizer consumeTo:end usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
[terminationMacros addObject:[token stringValue]];
}];
*stop = YES; // Ignore the rest of parameters as vararg is the last and above block consumed end token which would confuse above block!
}
}

GBMethodArgument *argument = nil;
if ([argumentTypes count] == 0)
argument = [GBMethodArgument methodArgumentWithName:argumentName];
else if (!isVarArg)
argument = [GBMethodArgument methodArgumentWithName:argumentName types:argumentTypes var:argumentVar];
else
argument = [GBMethodArgument methodArgumentWithName:argumentName types:argumentTypes var:argumentVar terminationMacros:terminationMacros];
[methodArgs addObject:argument];
*consume = NO;

// If we have no more colon before end, consume the rest of the tokens to get optional termination macros.
__block BOOL hasColon = NO;
[self.tokenizer lookaheadTo:end usingBlock:^(PKToken *token, BOOL *stop) {
if ([token matches:@":"]) {
hasColon = YES;
*stop = YES;
}
}];
if (!hasColon) {
[self.tokenizer consumeTo:end usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
[terminationMacros addObject:[token stringValue]];
}];
*stop = YES; // Ignore the rest of parameters
}

if (terminationMacros.count == 0) {
terminationMacros = nil;
}
} else {
// remaining tokens are termination macros
[self.tokenizer consumeTo:end usingBlock:^(PKToken *token, BOOL *consume, BOOL *stop) {
[terminationMacros addObject:[token stringValue]];
}];
*stop = YES; // Ignore the rest of parameters
}

GBMethodArgument *argument = [GBMethodArgument methodArgumentWithName:argumentName types:argumentTypes var:argumentVar terminationMacros:terminationMacros];
[methodArgs addObject:argument];
*consume = NO;
}];

// Create method instance and register it.
Expand Down
10 changes: 10 additions & 0 deletions Parsing/GBTokenizer.h
Expand Up @@ -88,9 +88,19 @@
@param offset The offset from the current position.
@return Returns the token at the given offset or EOF token if offset point after EOF.
@see consume:
@see lookaheadTo:usingBlock:
*/
- (PKToken *)lookahead:(NSUInteger)offset;

/** Enumerates but does not consume all tokens starting at current token up until the given end token is detected.
For each token, the given block is called which gives client a chance to inspect and handle tokens. End token is not reported. Note that this method automatically skips any comment tokens and only enumerates actual language tokens.
@param end Ending token.
@see lookahead:
*/
- (void)lookaheadTo:(NSString *)end usingBlock:(void (^)(PKToken *token, BOOL *stop))block;

/** Consumes the given ammoun of tokens, starting at the current position.
This effectively "moves" `currentToken` to the new position. If EOF is reached before consuming the given ammount of tokens, consuming stops at the end of stream and `currentToken` returns EOF token. If comment tokens are detected while consuming, they are not counted and consuming count continues with actual language tokens. However if there is a comment just before the next current token (i.e. after the last consumed token), the comment data is saved and is available through `lastCommentString`. Otherwise last comment data is cleared, even if a comment was detected in between.
Expand Down
17 changes: 17 additions & 0 deletions Parsing/GBTokenizer.m
Expand Up @@ -87,6 +87,23 @@ - (PKToken *)lookahead:(NSUInteger)offset {
return [self.tokens objectAtIndex:self.tokenIndex + delta - 1];
}

- (void)lookaheadTo:(NSString *)end usingBlock:(void (^)(PKToken *token, BOOL *stop))block {
NSUInteger tokenCount = [self.tokens count];
BOOL quit = NO;
for (NSUInteger index = self.tokenIndex; index < tokenCount; ++index) {
PKToken *token = [self.tokens objectAtIndex:index];
if ([token isComment]) {
index++;
continue;
}
if ([token matches:end]) {
break;
}
block(token, &quit);
if (quit) break;
}
}

- (PKToken *)currentToken {
if ([self eof]) return [PKToken EOFToken];
return [self.tokens objectAtIndex:self.tokenIndex];
Expand Down

0 comments on commit 3d2d2a8

Please sign in to comment.