You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

239 lines
6.1 KiB

// [The "BSD licence"]
// Copyright (c) 2006-2007 Kay Roepke
// 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 "TreeAdaptor.h"
#import "TreeException.h"
#import "BaseTree.h"
@implementation TreeAdaptor
+ (id) newEmptyTree
{
return [TreeAdaptor newTreeWithToken:nil];
}
+ (id) newAdaptor
{
return [[TreeAdaptor alloc] init];
}
- (id) init
{
self = [super init];
return self;
}
- (id) initWithPayload:(id<Token>)payload
{
self = [super init];
return self;
}
#pragma mark Rewrite Rules
/** Create a tree node from Token object; for CommonTree type trees,
* then the token just becomes the payload. This is the most
* common create call.
*
* Override if you want another kind of node to be built.
*/
- (id) create:(id<Token>) payload
{
return nil;
}
/** Create a new node derived from a token, with a new token type.
* This is invoked from an imaginary node ref on right side of a
* rewrite rule as IMAG[$tokenLabel].
*
* This should invoke createToken(Token).
*/
- (id) createTree:(NSInteger)tokenType fromToken:(id<Token>)fromToken
{
id<Token> newToken = [self createToken:fromToken];
[newToken setType:tokenType];
id newTree = [self create:newToken];
[newToken release];
return newTree;
}
/** Create a new node derived from a token, with a new token type.
* This is invoked from an imaginary node ref on right side of a
* rewrite rule as IMAG[$tokenLabel].
*
* This should invoke createToken(Token).
*/
- (id) createTree:(NSInteger)tokenType fromToken:(id<Token>)fromToken text:(NSString *)tokenText
{
id<Token> newToken = [self createToken:fromToken];
[newToken setText:tokenText];
id newTree = [self create:newToken];
[newToken release];
return newTree;
}
/** Create a new node derived from a token, with a new token type.
* This is invoked from an imaginary node ref on right side of a
* rewrite rule as IMAG["IMAG"].
*
* This should invoke createToken(int,String).
*/
- (id) createTree:(NSInteger)tokenType text:(NSString *)tokenText
{
id<Token> newToken = [self createToken:tokenType text:tokenText];
id newTree = [self create:newToken];
[newToken release];
return newTree;
}
- (id) copyNode:(id)aNode
{
return [aNode copyWithZone:nil]; // not -copy: to silence warnings
}
- (id) copyTree:(id)aTree
{
return [aTree deepCopy];
}
- (void) addChild:(id)child toTree:(id)aTree
{
[aTree addChild:child];
}
- (id) makeNode:(id)newRoot parentOf:(id)oldRoot
{
id newRootNode = newRoot;
if (oldRoot == nil)
return newRootNode;
// handles ^(nil real-node) case
if ([newRootNode isNil]) {
if ([newRootNode getChildCount] > 1) {
#warning TODO: Find a way to the current input stream here!
@throw [TreeException exceptionWithOldRoot:oldRoot newRoot:newRootNode stream:nil];
}
#warning TODO: double check memory management with respect to code generation
// remove the empty node, placing its sole child in its role.
id tmpRootNode = [[newRootNode childAtIndex:0] retain];
[newRootNode release];
newRootNode = tmpRootNode;
}
// the handling of an empty node at the root of oldRoot happens in addChild:
[newRootNode addChild:oldRoot];
// this release relies on the fact that the ANTLR code generator always assigns the return value of this method
// to the variable originally holding oldRoot. If we don't release we leak the reference.
// FIXME: this is totally non-obvious. maybe do it in calling code by comparing pointers and conditionally releasing
// the old object
[oldRoot release];
// what happens to newRootNode's retain count? Should we be autoreleasing this one? Probably.
return [newRootNode retain];
}
- (id) postProcessTree:(id)aTree
{
id processedNode = aTree;
if (aTree != nil && [aTree isNil] != NO && [aTree getChildCount] == 1) {
processedNode = [aTree childAtIndex:0];
}
return processedNode;
}
- (NSUInteger) uniqueIdForTree:(id)aNode
{
// TODO: is hash appropriate here?
return [aNode hash];
}
#pragma mark Content
- (NSInteger) tokenTypeForNode:(id)aNode
{
return [aNode getType];
}
- (void) setTokenType:(NSInteger)tokenType forNode:(id)aNode
{
// currently unimplemented
}
- (NSString *) textForNode:(id)aNode
{
return [aNode getText];
}
- (void) setText:(NSString *)tokenText forNode:(id)aNode
{
// currently unimplemented
}
#pragma mark Navigation / Tree Parsing
- (id) childForNode:(id) aNode atIndex:(NSInteger) i
{
// currently unimplemented
return nil;
}
- (NSInteger) childCountForTree:(id) aTree
{
// currently unimplemented
return 0;
}
#pragma mark Subclass Responsibilties
- (void) setBoundariesForTree:(id)aTree fromToken:(id<Token>)startToken toToken:(id<Token>)stopToken
{
// subclass responsibility
}
- (NSInteger) tokenStartIndexForTree:(id)aTree
{
// subclass responsibility
return 0;
}
- (NSInteger) tokenStopIndexForTree:(id)aTree
{
// subclass responsibility
return 0;
}
@end