• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
31static NSData *newlineData = nil;
32static 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