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 "DebugEventSocketProxy.h"
     28 #import "Token+DebuggerSupport.h"
     29 #include <string.h>
     30 
     31 static NSData *newlineData = nil;
     32 static unsigned lengthOfUTF8Ack = 0;
     33 
     34 @implementation DebugEventSocketProxy
     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 /* Java stuff
     70 public void handshake() throws IOException {
     71     if ( serverSocket==nil ) {
     72         serverSocket = new ServerSocket(port);
     73         socket = serverSocket.accept();
     74         socket.setTcpNoDelay(true);
     75         OutputStream os = socket.getOutputStream();
     76         OutputStreamWriter osw = new OutputStreamWriter(os, "UTF8");
     77         out = new PrintWriter(new BufferedWriter(osw));
     78         InputStream is = socket.getInputStream();
     79         InputStreamReader isr = new InputStreamReader(is, "UTF8");
     80         in = new BufferedReader(isr);
     81         out.println("ANTLR "+ DebugEventListener.PROTOCOL_VERSION);
     82         out.println("grammar \""+ grammarFileName);
     83         out.flush();
     84         ack();
     85     }
     86 }
     87 
     88 - (void) commence
     89 {
     90     // don't bother sending event; listener will trigger upon connection
     91 }
     92 
     93 - (void) terminate
     94 {
     95     [self transmit:@"terminate";
     96     [out close];
     97     try {
     98         [socket close];
     99     }
    100     catch (IOException *ioe) {
    101         ioe.printStackTrace(System.err);
    102     }
    103 }
    104 
    105 - (void) ack
    106 {
    107     try {
    108         in.readLine();
    109     }
    110     catch (IOException ioe) {
    111         ioe.printStackTrace(System.err);
    112     }
    113 }
    114 
    115 protected void transmit(String event) {
    116     out.println(event);
    117     out.flush();
    118     ack();
    119 }
    120 */
    121 
    122 - (void) waitForDebuggerConnection
    123 {
    124 	if (serverSocket == -1) {
    125 		serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    126 		
    127 		NSAssert1(serverSocket != -1, @"Failed to create debugger socket. %s", strerror(errno));
    128 		
    129 		int yes = 1;
    130 		setsockopt(serverSocket, SOL_SOCKET, SO_KEEPALIVE|SO_REUSEPORT|SO_REUSEADDR|TCP_NODELAY, (void *)&yes, sizeof(NSInteger));
    131 
    132 		struct sockaddr_in server_addr;
    133 		bzero(&server_addr, sizeof(struct sockaddr_in));
    134 		server_addr.sin_family = AF_INET;
    135 		server_addr.sin_port = htons([self debuggerPort]);
    136 		server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    137 		NSAssert1( bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) != -1, @"bind(2) failed. %s", strerror(errno));
    138 
    139 		NSAssert1(listen(serverSocket,50) == 0, @"listen(2) failed. %s", strerror(errno));
    140 		
    141 		NSLog(@"ANTLR waiting for debugger attach (grammar %@)", [self grammarName]);
    142 		
    143 		debuggerSocket = accept(serverSocket, &debugger_sockaddr, &debugger_socklen);
    144 		NSAssert1( debuggerSocket != -1, @"accept(2) failed. %s", strerror(errno));
    145 		
    146 		debuggerFH = [[NSFileHandle alloc] initWithFileDescriptor:debuggerSocket];
    147 		[self sendToDebugger:[NSString stringWithFormat:@"ANTLR %d", DebugProtocolVersion] waitForResponse:NO];
    148 		[self sendToDebugger:[NSString stringWithFormat:@"grammar \"%@", [self grammarName]] waitForResponse:NO];
    149 	}
    150 }
    151 
    152 - (void) waitForAck
    153 {
    154 	NSString *response;
    155 	@try {
    156 		NSData *newLine = [debuggerFH readDataOfLength:lengthOfUTF8Ack];
    157 		response = [[NSString alloc] initWithData:newLine encoding:NSUTF8StringEncoding];
    158 		if (![response isEqualToString:@"ack\n"]) @throw [NSException exceptionWithName:@"DebugEventSocketProxy" reason:@"illegal response from debugger" userInfo:nil];
    159 	}
    160 	@catch (NSException *e) {
    161 		NSLog(@"socket died or debugger misbehaved: %@ read <%@>", e, response);
    162 	}
    163 	@finally {
    164 		[response release];
    165 	}
    166 }
    167 
    168 - (void) sendToDebugger:(NSString *)message
    169 {
    170 	[self sendToDebugger:message waitForResponse:YES];
    171 }
    172 
    173 - (void) sendToDebugger:(NSString *)message waitForResponse:(BOOL)wait
    174 {
    175 	if (! debuggerFH ) return;
    176 	[debuggerFH writeData:[message dataUsingEncoding:NSUTF8StringEncoding]];
    177 	[debuggerFH writeData:newlineData];
    178 	if (wait) [self waitForAck];
    179 }
    180 
    181 - (NSInteger) serverSocket
    182 {
    183     return serverSocket;
    184 }
    185 
    186 - (void) setServerSocket: (NSInteger) aServerSocket
    187 {
    188     serverSocket = aServerSocket;
    189 }
    190 
    191 - (NSInteger) debuggerSocket
    192 {
    193     return debuggerSocket;
    194 }
    195 
    196 - (void) setDebuggerSocket: (NSInteger) aDebuggerSocket
    197 {
    198     debuggerSocket = aDebuggerSocket;
    199 }
    200 
    201 - (NSString *) grammarName
    202 {
    203     return grammarName; 
    204 }
    205 
    206 - (void) setGrammarName: (NSString *) aGrammarName
    207 {
    208     if (grammarName != aGrammarName) {
    209         [aGrammarName retain];
    210         [grammarName release];
    211         grammarName = aGrammarName;
    212     }
    213 }
    214 
    215 - (NSInteger) debuggerPort
    216 {
    217     return debuggerPort;
    218 }
    219 
    220 - (void) setDebuggerPort: (NSInteger) aDebuggerPort
    221 {
    222     debuggerPort = aDebuggerPort;
    223 }
    224 
    225 - (NSString *) escapeNewlines:(NSString *)aString
    226 {
    227 	NSMutableString *escapedText;
    228 	if (aString) {
    229 		escapedText = [NSMutableString stringWithString:aString];
    230 		NSRange wholeString = NSMakeRange(0,[escapedText length]);
    231 		[escapedText replaceOccurrencesOfString:@"%" withString:@"%25" options:0 range:wholeString];
    232 		[escapedText replaceOccurrencesOfString:@"\n" withString:@"%0A" options:0 range:wholeString];
    233 		[escapedText replaceOccurrencesOfString:@"\r" withString:@"%0D" options:0 range:wholeString];
    234 	} else {
    235 		escapedText = [NSMutableString stringWithString:@""];
    236 	}
    237 	return escapedText;
    238 }
    239 
    240 #pragma mark -
    241 
    242 #pragma mark DebugEventListener Protocol
    243 - (void) enterRule:(NSString *)ruleName
    244 {
    245 	[self sendToDebugger:[NSString stringWithFormat:@"enterRule %@", ruleName]];
    246 }
    247 
    248 - (void) enterAlt:(NSInteger)alt
    249 {
    250 	[self sendToDebugger:[NSString stringWithFormat:@"enterAlt %d", alt]]; 
    251 }
    252 
    253 - (void) exitRule:(NSString *)ruleName
    254 {
    255 	[self sendToDebugger:[NSString stringWithFormat:@"exitRule %@", ruleName]];
    256 }
    257 
    258 - (void) enterSubRule:(NSInteger)decisionNumber
    259 {
    260 	[self sendToDebugger:[NSString stringWithFormat:@"enterSubRule %d", decisionNumber]];
    261 }
    262 
    263 - (void) exitSubRule:(NSInteger)decisionNumber
    264 {
    265 	[self sendToDebugger:[NSString stringWithFormat:@"exitSubRule %d", decisionNumber]];
    266 }
    267 
    268 - (void) enterDecision:(NSInteger)decisionNumber
    269 {
    270 	[self sendToDebugger:[NSString stringWithFormat:@"enterDecision %d", decisionNumber]];
    271 }
    272 
    273 - (void) exitDecision:(NSInteger)decisionNumber
    274 {
    275 	[self sendToDebugger:[NSString stringWithFormat:@"exitDecision %d", decisionNumber]];
    276 }
    277 
    278 - (void) consumeToken:(id<Token>)t
    279 {
    280 	[self sendToDebugger:[NSString stringWithFormat:@"consumeToken %@", [self escapeNewlines:[t description]]]];
    281 }
    282 
    283 - (void) consumeHiddenToken:(id<Token>)t
    284 {
    285 	[self sendToDebugger:[NSString stringWithFormat:@"consumeHiddenToken %@", [self escapeNewlines:[t description]]]];
    286 }
    287 
    288 - (void) LT:(NSInteger)i foundToken:(id<Token>)t
    289 {
    290 	[self sendToDebugger:[NSString stringWithFormat:@"LT %d %@", i, [self escapeNewlines:[t description]]]];
    291 }
    292 
    293 - (void) mark:(NSInteger)marker
    294 {
    295 	[self sendToDebugger:[NSString stringWithFormat:@"mark %d", marker]];
    296 }
    297 - (void) rewind:(NSInteger)marker
    298 {
    299 	[self sendToDebugger:[NSString stringWithFormat:@"rewind %d", marker]];
    300 }
    301 
    302 - (void) rewind
    303 {
    304 	[self sendToDebugger:@"rewind"];
    305 }
    306 
    307 - (void) beginBacktrack:(NSInteger)level
    308 {
    309 	[self sendToDebugger:[NSString stringWithFormat:@"beginBacktrack %d", level]];
    310 }
    311 
    312 - (void) endBacktrack:(NSInteger)level wasSuccessful:(BOOL)successful
    313 {
    314 	[self sendToDebugger:[NSString stringWithFormat:@"endBacktrack %d %d", level, successful ? 1 : 0]];
    315 }
    316 
    317 - (void) locationLine:(NSInteger)line column:(NSInteger)pos
    318 {
    319 	[self sendToDebugger:[NSString stringWithFormat:@"location %d %d", line, pos]];
    320 }
    321 
    322 - (void) recognitionException:(RecognitionException *)e
    323 {
    324 #warning TODO: recognition exceptions
    325 	// these must use the names of the corresponding Java exception classes, because ANTLRWorks recreates the exception
    326 	// objects on the Java side.
    327 	// Write categories for Objective-C exceptions to provide those names
    328 }
    329 
    330 - (void) beginResync
    331 {
    332 	[self sendToDebugger:@"beginResync"];
    333 }
    334 	
    335 - (void) endResync
    336 {
    337 	[self sendToDebugger:@"endResync"];
    338 }
    339 
    340 - (void) semanticPredicate:(NSString *)predicate matched:(BOOL)result
    341 {
    342 	[self sendToDebugger:[NSString stringWithFormat:@"semanticPredicate %d %@", result?1:0, [self escapeNewlines:predicate]]];
    343 }
    344 
    345 - (void) commence
    346 {
    347 	// no need to send event
    348 }
    349 
    350 - (void) terminate
    351 {
    352 	[self sendToDebugger:@"terminate"];
    353 	@try {
    354 		[debuggerFH closeFile];
    355 	}
    356 	@finally {
    357 #warning TODO: make socket handling robust. too lazy now...
    358 		shutdown(serverSocket,SHUT_RDWR);
    359 		serverSocket = -1;
    360 	}
    361 }
    362 
    363 
    364 #pragma mark Tree Parsing
    365 - (void) consumeNode:(unsigned)nodeHash ofType:(NSInteger)type text:(NSString *)text
    366 {
    367 	[self sendToDebugger:[NSString stringWithFormat:@"consumeNode %u %d %@",
    368 		nodeHash,
    369 		type,
    370 		[self escapeNewlines:text]
    371 		]];
    372 }
    373 
    374 - (void) LT:(NSInteger)i foundNode:(unsigned)nodeHash ofType:(NSInteger)type text:(NSString *)text
    375 {
    376 	[self sendToDebugger:[NSString stringWithFormat:@"LN %d %u %d %@",
    377 		i,
    378 		nodeHash,
    379 		type,
    380 		[self escapeNewlines:text]
    381 		]];
    382 }
    383 
    384 
    385 #pragma mark AST Events
    386 
    387 - (void) createNilNode:(unsigned)hash
    388 {
    389 	[self sendToDebugger:[NSString stringWithFormat:@"nilNode %u", hash]];
    390 }
    391 
    392 - (void) createNode:(unsigned)hash text:(NSString *)text type:(NSInteger)type
    393 {
    394 	[self sendToDebugger:[NSString stringWithFormat:@"createNodeFromToken %u %d %@", 
    395 		hash,
    396 		type,
    397 		[self escapeNewlines:text]
    398 		]];
    399 }
    400 
    401 - (void) createNode:(unsigned)hash fromTokenAtIndex:(NSInteger)tokenIndex
    402 {
    403 	[self sendToDebugger:[NSString stringWithFormat:@"createNode %u %d", hash, tokenIndex]];
    404 }
    405 
    406 - (void) becomeRoot:(unsigned)newRootHash old:(unsigned)oldRootHash
    407 {
    408 	[self sendToDebugger:[NSString stringWithFormat:@"becomeRoot %u %u", newRootHash, oldRootHash]];
    409 }
    410 
    411 - (void) addChild:(unsigned)childHash toTree:(unsigned)treeHash
    412 {
    413 	[self sendToDebugger:[NSString stringWithFormat:@"addChild %u %u", treeHash, childHash]];
    414 }
    415 
    416 - (void) setTokenBoundariesForTree:(unsigned)nodeHash From:(NSInteger)tokenStartIndex To:(NSInteger)tokenStopIndex
    417 {
    418 	[self sendToDebugger:[NSString stringWithFormat:@"setTokenBoundaries %u %d %d", nodeHash, tokenStartIndex, tokenStopIndex]];
    419 }
    420 
    421 
    422 
    423 @end
    424