blob: 849543657659c88a5b44f0419f5aa7ba0a9fb4e5 [file] [log] [blame]
//
// ANTLRTreeRewriter.m
// ANTLR
//
// Created by Alan Condit on 6/17/10.
// [The "BSD licence"]
// Copyright (c) 2010 Alan Condit
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. The name of the author may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import "ANTLRTreeRewriter.h"
#import "ANTLRCommonTreeNodeStream.h"
#import "ANTLRTreeRuleReturnScope.h"
#import "ANTLRCommonTreeAdaptor.h"
#import "ANTLRTreeVisitor.h"
@implementation ANTLRfptr
+ (ANTLRfptr *)newANTLRfptrWithRule:(SEL)aRuleAction withObject:(id)anObject
{
return [[ANTLRfptr alloc] initWithRule:aRuleAction withObject:(id)anObject];
}
-initWithRule:(SEL)aRuleAction withObject:(id)anObject
{
if ((self = [super init]) != nil) {
actor = anObject;
ruleSEL = aRuleAction;
}
return self;
}
- (id)rule
{
if ( [actor respondsToSelector:ruleSEL] )
return [actor performSelector:ruleSEL];
else
@throw [ANTLRRuntimeException newException:@"Unknown Rewrite exception"];
return nil;
}
@synthesize actor;
@synthesize ruleSEL;
@end
@implementation ANTLRTreeRewriter
+ (ANTLRTreeRewriter *) newANTLRTreeRewriter:(id<ANTLRTreeNodeStream>)anInput
{
return [[ANTLRTreeRewriter alloc] initWithStream:anInput State:[ANTLRRecognizerSharedState newANTLRRecognizerSharedState]];
}
+ (ANTLRTreeRewriter *) newANTLRTreeRewriter:(id<ANTLRTreeNodeStream>)anInput State:(ANTLRRecognizerSharedState *)aState
{
return [[ANTLRTreeRewriter alloc] initWithStream:anInput State:aState];
}
- (id)initWithStream:(id<ANTLRTreeNodeStream>)anInput
{
SEL aRuleSel;
if ((self = [super initWithStream:anInput]) != nil) {
showTransformations = NO;
state = [[ANTLRRecognizerSharedState newANTLRRecognizerSharedState] retain];
originalAdaptor = [input getTreeAdaptor];
if ( originalAdaptor ) [originalAdaptor retain];
originalTokenStream = [input getTokenStream];
if ( originalTokenStream ) [originalTokenStream retain];
aRuleSel = @selector(topdown);
topdown_fptr = [ANTLRfptr newANTLRfptrWithRule:(SEL)aRuleSel withObject:self];
aRuleSel = @selector(bottomup);
bottomup_ftpr = [ANTLRfptr newANTLRfptrWithRule:(SEL)aRuleSel withObject:self];
}
return self;
}
- (id)initWithStream:(id<ANTLRTreeNodeStream>)anInput State:(ANTLRRecognizerSharedState *)aState
{
SEL aRuleSel;
if ((self = [super initWithStream:anInput]) != nil) {
showTransformations = NO;
state = aState;
if ( state ) [state retain];
originalAdaptor = [input getTreeAdaptor];
if ( originalAdaptor ) [originalAdaptor retain];
originalTokenStream = [input getTokenStream];
if ( originalTokenStream ) [originalTokenStream retain];
aRuleSel = @selector(topdown);
topdown_fptr = [ANTLRfptr newANTLRfptrWithRule:(SEL)aRuleSel withObject:self];
aRuleSel = @selector(bottomup);
bottomup_ftpr = [ANTLRfptr newANTLRfptrWithRule:(SEL)aRuleSel withObject:self];
}
return self;
}
- (void) dealloc
{
#ifdef DEBUG_DEALLOC
NSLog( @"called dealloc in ANTLRTreeRewriter" );
#endif
if ( state ) [state release];
if ( originalAdaptor ) [originalAdaptor release];
if ( originalTokenStream ) [originalTokenStream release];
[super dealloc];
}
- (id) applyOnce:(ANTLRCommonTree *)t Rule:(ANTLRfptr *)whichRule
{
if ( t == nil ) return nil;
@try {
// share TreeParser object but not parsing-related state
state = [ANTLRRecognizerSharedState newANTLRRecognizerSharedState];
input = [ANTLRCommonTreeNodeStream newANTLRCommonTreeNodeStream:(ANTLRCommonTreeAdaptor *)originalAdaptor Tree:t];
[(ANTLRCommonTreeNodeStream *)input setTokenStream:originalTokenStream];
[self setBacktrackingLevel:1];
ANTLRTreeRuleReturnScope *r = [(ANTLRfptr *)whichRule rule];
[self setBacktrackingLevel:0];
if ( [self getFailed] )
return t;
if ( showTransformations &&
r != nil && !(t == r.start) && r.start != nil ) {
[self reportTransformation:t Tree:r.start];
}
if ( r != nil && r.start != nil )
return r.start;
else
return t;
}
@catch (ANTLRRecognitionException *e) {
return t;
}
return t;
}
- (id) applyRepeatedly:(ANTLRCommonTree *)t Rule:(ANTLRfptr *)whichRule
{
BOOL treeChanged = true;
while ( treeChanged ) {
ANTLRTreeRewriter *u = [self applyOnce:t Rule:whichRule];
treeChanged = !(t == u);
t = u;
}
return t;
}
- (id) downup:(ANTLRCommonTree *)t
{
return [self downup:t XForm:NO];
}
- (id) pre:(ANTLRCommonTree *)t
{
return [self applyOnce:t Rule:topdown_fptr];
}
- (id)post:(ANTLRCommonTree *)t
{
return [self applyRepeatedly:t Rule:bottomup_ftpr];
}
#ifdef DONTUSENOMO
public Object downup(Object t, boolean showTransformations) {
this.showTransformations = showTransformations;
TreeVisitor v = new TreeVisitor(new CommonTreeAdaptor());
TreeVisitorAction actions = new TreeVisitorAction() {
public Object pre(Object t) { return applyOnce(t, topdown_fptr); }
public Object post(Object t) { return applyRepeatedly(t, bottomup_ftpr); }
};
t = v.visit(t, actions);
return t;
}
#endif
- (id) downup:(ANTLRCommonTree *)t XForm:(BOOL)aShowTransformations
{
showTransformations = aShowTransformations;
ANTLRTreeVisitor *v = [ANTLRTreeVisitor newANTLRTreeVisitor:[[originalAdaptor class] newTreeAdaptor]];
ANTLRTreeVisitorAction *actions = [ANTLRTreeVisitorAction newANTLRTreeVisitorAction];
{
//public Object pre(Object t) { return applyOnce(t, topdown_fptr); }
[self pre:t];
//public Object post(Object t) { return applyRepeatedly(t, bottomup_ftpr); }
[self post:t];
};
t = [v visit:t Action:actions];
return t;
}
/** Override this if you need transformation tracing to go somewhere
* other than stdout or if you're not using Tree-derived trees.
*/
- (void)reportTransformation:(ANTLRCommonTree *)oldTree Tree:(ANTLRCommonTree *)newTree
{
//System.out.println(((Tree)oldTree).toStringTree()+" -> "+ ((Tree)newTree).toStringTree());
}
- (id)topdown_fptr
{
return [self topdown];
}
- (id)bottomup_ftpr
{
return [self bottomup];
}
// methods the downup strategy uses to do the up and down rules.
// to override, just define tree grammar rule topdown and turn on
// filter=true.
- (id) topdown
// @throws RecognitionException
{
@throw [ANTLRRecognitionException newException:@"TopDown exception"];
return nil;
}
- (id) bottomup
//@throws RecognitionException
{
@throw [ANTLRRecognitionException newException:@"BottomUp exception"];
return nil;
}
@synthesize showTransformations;
@synthesize originalTokenStream;
@synthesize originalAdaptor;
@synthesize rule;
@end