Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added support for termination macros for method declaration and prope…

…rties declaration
  • Loading branch information...
commit 3d2d2a8801126638df34751eed61d1a382ee74bd 1 parent a80da63
@groue groue authored
View
42 Model/GBMethodData.m
@@ -9,6 +9,7 @@
#import "GRMustache.h"
#import "GBMethodArgument.h"
#import "GBMethodData.h"
+#import "RegexKitLite.h"
@interface GBMethodData ()
@@ -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];
}
View
51 Parsing/GBObjectiveCParser.m
@@ -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;
@@ -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];
@@ -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];
@@ -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.
View
10 Parsing/GBTokenizer.h
@@ -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.
View
17 Parsing/GBTokenizer.m
@@ -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];
Please sign in to comment.
Something went wrong with that request. Please try again.