diff --git a/include/PEGKit/PKParser.h b/include/PEGKit/PKParser.h index 1b84a9f..7cb0520 100644 --- a/include/PEGKit/PKParser.h +++ b/include/PEGKit/PKParser.h @@ -56,9 +56,47 @@ enum { TOKEN_KIND_BUILTIN_ANY = 13, }; + +@class PKParser; +@protocol PKParserDelegate + +@optional + +/** + * Called just before a grammar rule will be matched. + * + * @param rule The name of the rule that will be matched (in sentence case, to match the willMatchFoo callback). + */ +-(void)parser:(PKParser *)parser willMatch:(NSString *)rule; + +/** + * Called after a grammar rule has been matched. + * + * @param rule The name of the rule that has been matched (in sentence case, to match the didMatchFoo callback). + */ +-(void)parser:(PKParser *)parser didMatch:(NSString *)rule; + +/** + * Called when the parse fails to match anything. + */ +-(void)parser:(PKParser *)parser didFailToMatch:(PKAssembly *)assembly; + +@end + + @interface PKParser : NSObject -- (instancetype)initWithDelegate:(id)d; // designated initializer +/** + * Designated initializer. + * + * @param d This will receive calls to -parser:willMatchFoo: and parser:didMatchFoo: + * where Foo is the name of the grammar rule that is being matched. These calls + * will receive self and self.assembly as parameters. This delegate may optionally + * also implement PKParserDelegate and receive calls to -parser:willMatch: and + * -parser:didMatch:. All these calls are optional and so the delegate need not + * implement all of them. + */ +- (instancetype)initWithDelegate:(id)d; - (id)parseString:(NSString *)input error:(NSError **)outErr; - (id)parseStream:(NSInputStream *)input error:(NSError **)outErr; diff --git a/src/PKParser.m b/src/PKParser.m index 8b0b410..d94ab48 100644 --- a/src/PKParser.m +++ b/src/PKParser.m @@ -40,10 +40,6 @@ NSString * const PEGKitRecognitionTokenMatchFailed = @"Failed to match next input token"; NSString * const PEGKitRecognitionPredicateFailed = @"Predicate failed"; -@interface NSObject () -- (void)parser:(PKParser *)p didFailToMatch:(PKAssembly *)a; -@end - @interface PKAssembly () - (void)consume:(PKToken *)tok; @property (nonatomic, readwrite, retain) NSMutableArray *stack; @@ -399,14 +395,29 @@ - (void)discard { - (void)fireDelegateSelector:(SEL)sel { - if (self.isSpeculating) return; - - if (_delegate && [_delegate respondsToSelector:sel]) { + if (self.isSpeculating || _delegate == nil) return; + + [self fireDelegateMatchRule:sel delegateSelector:@selector(parser:willMatch:)]; + [self fireDelegateMatchRule:sel delegateSelector:@selector(parser:didMatch:)]; + + if ([_delegate respondsToSelector:sel]) { [_delegate performSelector:sel withObject:self withObject:_assembly]; } } +- (void)fireDelegateMatchRule:(SEL)sel delegateSelector:(SEL)delegateSelector { + NSString * selStr = NSStringFromSelector(sel); + NSString * prefix = NSStringFromSelector(delegateSelector); + prefix = [prefix substringToIndex:prefix.length - 1]; + + if ([selStr hasPrefix:prefix] && [_delegate respondsToSelector:delegateSelector]) { + NSString * rule = [selStr substringWithRange:NSMakeRange(prefix.length, selStr.length - prefix.length - 1)]; + [_delegate performSelector:delegateSelector withObject:self withObject:rule]; + } +} + + - (void)fireSyntaxSelector:(SEL)sel withRuleName:(NSString *)ruleName { if (self.isSpeculating) return;