Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion include/PEGKit/PKParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,47 @@ enum {
TOKEN_KIND_BUILTIN_ANY = 13,
};


@class PKParser;
@protocol PKParserDelegate <NSObject>

@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 <PKTokenizerDelegate>

- (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;
Expand Down
25 changes: 18 additions & 7 deletions src/PKParser.m
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down