Home | History | Annotate | Download | only in Framework
      1 // [The "BSD licence"]
      2 // Copyright (c) 2006-2007 Kay Roepke
      3 // All rights reserved.
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions
      7 // are met:
      8 // 1. Redistributions of source code must retain the above copyright
      9 //    notice, this list of conditions and the following disclaimer.
     10 // 2. Redistributions in binary form must reproduce the above copyright
     11 //    notice, this list of conditions and the following disclaimer in the
     12 //    documentation and/or other materials provided with the distribution.
     13 // 3. The name of the author may not be used to endorse or promote products
     14 //    derived from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19 // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21 // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 
     27 #import "ANTLRDebugEventProxy.h"
     28 #import "ANTLRToken+DebuggerSupport.h"
     29 #include <string.h>
     30 
     31 static NSData *newlineData = nil;
     32 static unsigned lengthOfUTF8Ack = 0;
     33 
     34 @implementation ANTLRDebugEventProxy
     35 
     36 + (void) initialize
     37 {
     38 	if (!newlineData) newlineData = [@"\n" dataUsingEncoding:NSUTF8StringEncoding];
     39 	if (!lengthOfUTF8Ack) lengthOfUTF8Ack = [[@"ack\n" dataUsingEncoding:NSUTF8StringEncoding] length];
     40 }
     41 
     42 - (id) init
     43 {
     44 	return [self initWithGrammarName:nil debuggerPort:DEFAULT_DEBUGGER_PORT];
     45 }
     46 
     47 - (id) initWithGrammarName:(NSString *)aGrammarName debuggerPort:(NSInteger)aPort
     48 {
     49 	self = [super init];
     50 	if (self) {
     51 		serverSocket = -1;
     52 		[self setGrammarName:aGrammarName];
     53 		if (aPort == -1) aPort = DEFAULT_DEBUGGER_PORT;
     54 		[self setDebuggerPort:aPort];
     55 	}
     56 	return self;
     57 }
     58 
     59 - (void) dealloc
     60 {
     61 	if (serverSocket != -1) 
     62 		shutdown(serverSocket,SHUT_RDWR);
     63 	serverSocket = -1;
     64 	[debuggerFH release];
     65     [self setGrammarName:nil];
     66     [super dealloc];
     67 }
     68 
     69 - (void) waitForDebuggerConnection
     70 {
     71 	if (serverSocket == -1) {
     72 		serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     73 		
     74 		NSAssert1(serverSocket != -1, @"Failed to create debugger socket. %s", strerror(errno));
     75 		
     76 		int yes = 1;
     77 		setsockopt(serverSocket, SOL_SOCKET, SO_KEEPALIVE|SO_REUSEPORT|SO_REUSEADDR|TCP_NODELAY, (void *)&yes, sizeof(NSInteger));
     78 
     79 		struct sockaddr_in server_addr;
     80 		bzero(&server_addr, sizeof(struct sockaddr_in));
     81 		server_addr.sin_family = AF_INET;
     82 		server_addr.sin_port = htons([self debuggerPort]);
     83 		server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
     84 		NSAssert1( bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) != -1, @"bind(2) failed. %s", strerror(errno));
     85 
     86 		NSAssert1(listen(serverSocket,50) == 0, @"listen(2) failed. %s", strerror(errno));
     87 		
     88 		NSLog(@"ANTLR waiting for debugger attach (grammar %@)", [self grammarName]);
     89 		
     90 		debuggerSocket = accept(serverSocket, &debugger_sockaddr, &debugger_socklen);
     91 		NSAssert1( debuggerSocket != -1, @"accept(2) failed. %s", strerror(errno));
     92 		
     93 		debuggerFH = [[NSFileHandle alloc] initWithFileDescriptor:debuggerSocket];
     94 		[self sendToDebugger:[NSString stringWithFormat:@"ANTLR %d", ANTLRDebugProtocolVersion] waitForResponse:NO];
     95 		[self sendToDebugger:[NSString stringWithFormat:@"grammar \"%@", [self grammarName]] waitForResponse:NO];
     96 	}
     97 }
     98 
     99 - (void) waitForAck
    100 {
    101 	NSString *response;
    102 	@try {
    103 		NSData *newLine = [debuggerFH readDataOfLength:lengthOfUTF8Ack];
    104 		response = [[NSString alloc] initWithData:newLine encoding:NSUTF8StringEncoding];
    105 		if (![response isEqualToString:@"ack\n"]) @throw [NSException exceptionWithName:@"ANTLRDebugEventProxy" reason:@"illegal response from debugger" userInfo:nil];
    106 	}
    107 	@catch (NSException *e) {
    108 		NSLog(@"socket died or debugger misbehaved: %@ read <%@>", e, response);
    109 	}
    110 	@finally {
    111 		[response release];
    112 	}
    113 }
    114 
    115 - (void) sendToDebugger:(NSString *)message
    116 {
    117 	[self sendToDebugger:message waitForResponse:YES];
    118 }
    119 
    120 - (void) sendToDebugger:(NSString *)message waitForResponse:(BOOL)wait
    121 {
    122 	if (! debuggerFH ) return;
    123 	[debuggerFH writeData:[message dataUsingEncoding:NSUTF8StringEncoding]];
    124 	[debuggerFH writeData:newlineData];
    125 	if (wait) [self waitForAck];
    126 }
    127 
    128 - (NSInteger) serverSocket
    129 {
    130     return serverSocket;
    131 }
    132 
    133 - (void) setServerSocket: (NSInteger) aServerSocket
    134 {
    135     serverSocket = aServerSocket;
    136 }
    137 
    138 - (NSInteger) debuggerSocket
    139 {
    140     return debuggerSocket;
    141 }
    142 
    143 - (void) setDebuggerSocket: (NSInteger) aDebuggerSocket
    144 {
    145     debuggerSocket = aDebuggerSocket;
    146 }
    147 
    148 - (NSString *) grammarName
    149 {
    150     return grammarName; 
    151 }
    152 
    153 - (void) setGrammarName: (NSString *) aGrammarName
    154 {
    155     if (grammarName != aGrammarName) {
    156         [aGrammarName retain];
    157         [grammarName release];
    158         grammarName = aGrammarName;
    159     }
    160 }
    161 
    162 - (NSInteger) debuggerPort
    163 {
    164     return debuggerPort;
    165 }
    166 
    167 - (void) setDebuggerPort: (NSInteger) aDebuggerPort
    168 {
    169     debuggerPort = aDebuggerPort;
    170 }
    171 
    172 - (NSString *) escapeNewlines:(NSString *)aString
    173 {
    174 	NSMutableString *escapedText;
    175 	if (aString) {
    176 		escapedText = [NSMutableString stringWithString:aString];
    177 		NSRange wholeString = NSMakeRange(0,[escapedText length]);
    178 		[escapedText replaceOccurrencesOfString:@"%" withString:@"%25" options:0 range:wholeString];
    179 		[escapedText replaceOccurrencesOfString:@"\n" withString:@"%0A" options:0 range:wholeString];
    180 		[escapedText replaceOccurrencesOfString:@"\r" withString:@"%0D" options:0 range:wholeString];
    181 	} else {
    182 		escapedText = [NSMutableString stringWithString:@""];
    183 	}
    184 	return escapedText;
    185 }
    186 
    187 #pragma mark -
    188 
    189 #pragma mark DebugEventListener Protocol
    190 - (void) enterRule:(NSString *)ruleName
    191 {
    192 	[self sendToDebugger:[NSString stringWithFormat:@"enterRule %@", ruleName]];
    193 }
    194 
    195 - (void) enterAlt:(NSInteger)alt
    196 {
    197 	[self sendToDebugger:[NSString stringWithFormat:@"enterAlt %d", alt]]; 
    198 }
    199 
    200 - (void) exitRule:(NSString *)ruleName
    201 {
    202 	[self sendToDebugger:[NSString stringWithFormat:@"exitRule %@", ruleName]];
    203 }
    204 
    205 - (void) enterSubRule:(NSInteger)decisionNumber
    206 {
    207 	[self sendToDebugger:[NSString stringWithFormat:@"enterSubRule %d", decisionNumber]];
    208 }
    209 
    210 - (void) exitSubRule:(NSInteger)decisionNumber
    211 {
    212 	[self sendToDebugger:[NSString stringWithFormat:@"exitSubRule %d", decisionNumber]];
    213 }
    214 
    215 - (void) enterDecision:(NSInteger)decisionNumber
    216 {
    217 	[self sendToDebugger:[NSString stringWithFormat:@"enterDecision %d", decisionNumber]];
    218 }
    219 
    220 - (void) exitDecision:(NSInteger)decisionNumber
    221 {
    222 	[self sendToDebugger:[NSString stringWithFormat:@"exitDecision %d", decisionNumber]];
    223 }
    224 
    225 - (void) consumeToken:(id<ANTLRToken>)t
    226 {
    227 	[self sendToDebugger:[NSString stringWithFormat:@"consumeToken %@", [self escapeNewlines:[t description]]]];
    228 }
    229 
    230 - (void) consumeHiddenToken:(id<ANTLRToken>)t
    231 {
    232 	[self sendToDebugger:[NSString stringWithFormat:@"consumeHiddenToken %@", [self escapeNewlines:[t description]]]];
    233 }
    234 
    235 - (void) LT:(NSInteger)i foundToken:(id<ANTLRToken>)t
    236 {
    237 	[self sendToDebugger:[NSString stringWithFormat:@"LT %d %@", i, [self escapeNewlines:[t description]]]];
    238 }
    239 
    240 - (void) mark:(NSInteger)marker
    241 {
    242 	[self sendToDebugger:[NSString stringWithFormat:@"mark %d", marker]];
    243 }
    244 - (void) rewind:(NSInteger)marker
    245 {
    246 	[self sendToDebugger:[NSString stringWithFormat:@"rewind %d", marker]];
    247 }
    248 
    249 - (void) rewind
    250 {
    251 	[self sendToDebugger:@"rewind"];
    252 }
    253 
    254 - (void) beginBacktrack:(NSInteger)level
    255 {
    256 	[self sendToDebugger:[NSString stringWithFormat:@"beginBacktrack %d", level]];
    257 }
    258 
    259 - (void) endBacktrack:(NSInteger)level wasSuccessful:(BOOL)successful
    260 {
    261 	[self sendToDebugger:[NSString stringWithFormat:@"endBacktrack %d %d", level, successful ? 1 : 0]];
    262 }
    263 
    264 - (void) locationLine:(NSInteger)line column:(NSInteger)pos
    265 {
    266 	[self sendToDebugger:[NSString stringWithFormat:@"location %d %d", line, pos]];
    267 }
    268 
    269 - (void) recognitionException:(ANTLRRecognitionException *)e
    270 {
    271 #warning TODO: recognition exceptions
    272 	// these must use the names of the corresponding Java exception classes, because ANTLRWorks recreates the exception
    273 	// objects on the Java side.
    274 	// Write categories for Objective-C exceptions to provide those names
    275 }
    276 
    277 - (void) beginResync
    278 {
    279 	[self sendToDebugger:@"beginResync"];
    280 }
    281 	
    282 - (void) endResync
    283 {
    284 	[self sendToDebugger:@"endResync"];
    285 }
    286 
    287 - (void) semanticPredicate:(NSString *)predicate matched:(BOOL)result
    288 {
    289 	[self sendToDebugger:[NSString stringWithFormat:@"semanticPredicate %d %@", result?1:0, [self escapeNewlines:predicate]]];
    290 }
    291 
    292 - (void) commence
    293 {
    294 	// no need to send event
    295 }
    296 
    297 - (void) terminate
    298 {
    299 	[self sendToDebugger:@"terminate"];
    300 	@try {
    301 		[debuggerFH closeFile];
    302 	}
    303 	@finally {
    304 #warning TODO: make socket handling robust. too lazy now...
    305 		shutdown(serverSocket,SHUT_RDWR);
    306 		serverSocket = -1;
    307 	}
    308 }
    309 
    310 
    311 #pragma mark Tree Parsing
    312 - (void) consumeNode:(unsigned)nodeHash ofType:(NSInteger)type text:(NSString *)text
    313 {
    314 	[self sendToDebugger:[NSString stringWithFormat:@"consumeNode %u %d %@",
    315 		nodeHash,
    316 		type,
    317 		[self escapeNewlines:text]
    318 		]];
    319 }
    320 
    321 - (void) LT:(NSInteger)i foundNode:(unsigned)nodeHash ofType:(NSInteger)type text:(NSString *)text
    322 {
    323 	[self sendToDebugger:[NSString stringWithFormat:@"LN %d %u %d %@",
    324 		i,
    325 		nodeHash,
    326 		type,
    327 		[self escapeNewlines:text]
    328 		]];
    329 }
    330 
    331 
    332 #pragma mark AST Events
    333 
    334 - (void) createNilNode:(unsigned)hash
    335 {
    336 	[self sendToDebugger:[NSString stringWithFormat:@"nilNode %u", hash]];
    337 }
    338 
    339 - (void) createNode:(unsigned)hash text:(NSString *)text type:(NSInteger)type
    340 {
    341 	[self sendToDebugger:[NSString stringWithFormat:@"createNodeFromToken %u %d %@", 
    342 		hash,
    343 		type,
    344 		[self escapeNewlines:text]
    345 		]];
    346 }
    347 
    348 - (void) createNode:(unsigned)hash fromTokenAtIndex:(NSInteger)tokenIndex
    349 {
    350 	[self sendToDebugger:[NSString stringWithFormat:@"createNode %u %d", hash, tokenIndex]];
    351 }
    352 
    353 - (void) becomeRoot:(unsigned)newRootHash old:(unsigned)oldRootHash
    354 {
    355 	[self sendToDebugger:[NSString stringWithFormat:@"becomeRoot %u %u", newRootHash, oldRootHash]];
    356 }
    357 
    358 - (void) addChild:(unsigned)childHash toTree:(unsigned)treeHash
    359 {
    360 	[self sendToDebugger:[NSString stringWithFormat:@"addChild %u %u", treeHash, childHash]];
    361 }
    362 
    363 - (void) setTokenBoundariesForTree:(unsigned)nodeHash From:(NSInteger)tokenStartIndex To:(NSInteger)tokenStopIndex
    364 {
    365 	[self sendToDebugger:[NSString stringWithFormat:@"setTokenBoundaries %u %d %d", nodeHash, tokenStartIndex, tokenStopIndex]];
    366 }
    367 
    368 
    369 
    370 @end
    371