1/*
2 * Note to JL: Removed extension call syntax
3 *
4 * [The "BSD licence"]
5 * Copyright (c) 2005-2008 Terence Parr
6 * All rights reserved.
7 *
8 * Conversion to C#:
9 * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. The name of the author may not be used to endorse or promote products
21 *    derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35namespace Antlr.Runtime.Debug {
36    using System;
37    using Antlr.Runtime.JavaExtensions;
38
39    using IOException = System.IO.IOException;
40    using ITreeAdaptor = Antlr.Runtime.Tree.ITreeAdaptor;
41    using Socket = System.Net.Sockets.Socket;
42    using StringBuilder = System.Text.StringBuilder;
43    using TcpListener = System.Net.Sockets.TcpListener;
44
45    /** <summary>
46     *  A proxy debug event listener that forwards events over a socket to
47     *  a debugger (or any other listener) using a simple text-based protocol;
48     *  one event per line.  ANTLRWorks listens on server socket with a
49     *  RemoteDebugEventSocketListener instance.  These two objects must therefore
50     *  be kept in sync.  New events must be handled on both sides of socket.
51     *  </summary>
52     */
53    public class DebugEventSocketProxy : BlankDebugEventListener {
54        public const int DefaultDebuggerPort = 49100;
55        protected int port = DefaultDebuggerPort;
56        protected TcpListener serverSocket;
57        protected Socket socket;
58        protected string grammarFileName;
59        //protected PrintWriter @out;
60        //protected BufferedReader @in;
61
62        /** <summary>Who am i debugging?</summary> */
63        protected BaseRecognizer recognizer;
64
65        /** <summary>
66         *  Almost certainly the recognizer will have adaptor set, but
67         *  we don't know how to cast it (Parser or TreeParser) to get
68         *  the adaptor field.  Must be set with a constructor. :(
69         *  </summary>
70         */
71        protected ITreeAdaptor adaptor;
72
73        public DebugEventSocketProxy(BaseRecognizer recognizer, ITreeAdaptor adaptor) :
74            this(recognizer, DefaultDebuggerPort, adaptor) {
75        }
76
77        public DebugEventSocketProxy(BaseRecognizer recognizer, int port, ITreeAdaptor adaptor) {
78            this.grammarFileName = recognizer.GrammarFileName;
79            this.adaptor = adaptor;
80            this.port = port;
81        }
82
83        #region Properties
84        public virtual ITreeAdaptor TreeAdaptor {
85            get {
86                return adaptor;
87            }
88            set {
89                adaptor = value;
90            }
91        }
92        #endregion
93
94        public virtual void Handshake() {
95            if (serverSocket == null) {
96                System.Net.IPHostEntry hostInfo = System.Net.Dns.GetHostEntry("localhost");
97                System.Net.IPAddress ipAddress = hostInfo.AddressList[0];
98                serverSocket = new TcpListener(ipAddress, port);
99                socket = serverSocket.AcceptSocket();
100                socket.NoDelay = true;
101
102                System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
103                socket.Send(encoding.GetBytes("ANTLR " + DebugEventListenerConstants.ProtocolVersion + "\n"));
104                socket.Send(encoding.GetBytes("grammar \"" + grammarFileName + "\n"));
105                Ack();
106
107                //serverSocket = new ServerSocket( port );
108                //socket = serverSocket.accept();
109                //socket.setTcpNoDelay( true );
110                //OutputStream os = socket.getOutputStream();
111                //OutputStreamWriter osw = new OutputStreamWriter( os, "UTF8" );
112                //@out = new PrintWriter( new BufferedWriter( osw ) );
113                //InputStream @is = socket.getInputStream();
114                //InputStreamReader isr = new InputStreamReader( @is, "UTF8" );
115                //@in = new BufferedReader( isr );
116                //@out.println( "ANTLR " + DebugEventListenerConstants.PROTOCOL_VERSION );
117                //@out.println( "grammar \"" + grammarFileName );
118                //@out.flush();
119                //ack();
120            }
121        }
122
123        public override void Commence() {
124            // don't bother sending event; listener will trigger upon connection
125        }
126
127        public override void Terminate() {
128            Transmit("terminate");
129            //@out.close();
130            try {
131                socket.Close();
132            } catch (IOException ioe) {
133                ExceptionExtensions.PrintStackTrace(ioe, Console.Error);
134            }
135        }
136
137        protected virtual void Ack() {
138            try {
139                throw new NotImplementedException();
140                //@in.readLine();
141            } catch (IOException ioe) {
142                ExceptionExtensions.PrintStackTrace(ioe, Console.Error);
143            }
144        }
145
146        protected virtual void Transmit(string @event) {
147            socket.Send(new System.Text.UTF8Encoding().GetBytes(@event + "\n"));
148            //@out.println( @event );
149            //@out.flush();
150            Ack();
151        }
152
153        public override void EnterRule(string grammarFileName, string ruleName) {
154            Transmit("enterRule\t" + grammarFileName + "\t" + ruleName);
155        }
156
157        public override void EnterAlt(int alt) {
158            Transmit("enterAlt\t" + alt);
159        }
160
161        public override void ExitRule(string grammarFileName, string ruleName) {
162            Transmit("exitRule\t" + grammarFileName + "\t" + ruleName);
163        }
164
165        public override void EnterSubRule(int decisionNumber) {
166            Transmit("enterSubRule\t" + decisionNumber);
167        }
168
169        public override void ExitSubRule(int decisionNumber) {
170            Transmit("exitSubRule\t" + decisionNumber);
171        }
172
173        public override void EnterDecision(int decisionNumber, bool couldBacktrack) {
174            Transmit("enterDecision\t" + decisionNumber);
175        }
176
177        public override void ExitDecision(int decisionNumber) {
178            Transmit("exitDecision\t" + decisionNumber);
179        }
180
181        public override void ConsumeToken(IToken t) {
182            string buf = SerializeToken(t);
183            Transmit("consumeToken\t" + buf);
184        }
185
186        public override void ConsumeHiddenToken(IToken t) {
187            string buf = SerializeToken(t);
188            Transmit("consumeHiddenToken\t" + buf);
189        }
190
191        public override void LT(int i, IToken t) {
192            if (t != null)
193                Transmit("LT\t" + i + "\t" + SerializeToken(t));
194        }
195
196        public override void Mark(int i) {
197            Transmit("mark\t" + i);
198        }
199
200        public override void Rewind(int i) {
201            Transmit("rewind\t" + i);
202        }
203
204        public override void Rewind() {
205            Transmit("rewind");
206        }
207
208        public override void BeginBacktrack(int level) {
209            Transmit("beginBacktrack\t" + level);
210        }
211
212        public override void EndBacktrack(int level, bool successful) {
213            Transmit("endBacktrack\t" + level + "\t" + (successful ? DebugEventListenerConstants.True : DebugEventListenerConstants.False));
214        }
215
216        public override void Location(int line, int pos) {
217            Transmit("location\t" + line + "\t" + pos);
218        }
219
220        public override void RecognitionException(RecognitionException e) {
221            StringBuilder buf = new StringBuilder(50);
222            buf.Append("exception\t");
223            buf.Append(e.GetType().Name);
224            // dump only the data common to all exceptions for now
225            buf.Append("\t");
226            buf.Append(e.Index);
227            buf.Append("\t");
228            buf.Append(e.Line);
229            buf.Append("\t");
230            buf.Append(e.CharPositionInLine);
231            Transmit(buf.ToString());
232        }
233
234        public override void BeginResync() {
235            Transmit("beginResync");
236        }
237
238        public override void EndResync() {
239            Transmit("endResync");
240        }
241
242        public override void SemanticPredicate(bool result, string predicate) {
243            StringBuilder buf = new StringBuilder(50);
244            buf.Append("semanticPredicate\t");
245            buf.Append(result);
246            SerializeText(buf, predicate);
247            Transmit(buf.ToString());
248        }
249
250        #region AST Parsing Events
251
252        public override void ConsumeNode(object t) {
253            StringBuilder buf = new StringBuilder(50);
254            buf.Append("consumeNode");
255            SerializeNode(buf, t);
256            Transmit(buf.ToString());
257        }
258
259        public override void LT(int i, object t) {
260            int ID = adaptor.GetUniqueID(t);
261            string text = adaptor.GetText(t);
262            int type = adaptor.GetType(t);
263            StringBuilder buf = new StringBuilder(50);
264            buf.Append("LN\t"); // lookahead node; distinguish from LT in protocol
265            buf.Append(i);
266            SerializeNode(buf, t);
267            Transmit(buf.ToString());
268        }
269
270        protected virtual void SerializeNode(StringBuilder buf, object t) {
271            int ID = adaptor.GetUniqueID(t);
272            string text = adaptor.GetText(t);
273            int type = adaptor.GetType(t);
274            buf.Append("\t");
275            buf.Append(ID);
276            buf.Append("\t");
277            buf.Append(type);
278            IToken token = adaptor.GetToken(t);
279            int line = -1;
280            int pos = -1;
281            if (token != null) {
282                line = token.Line;
283                pos = token.CharPositionInLine;
284            }
285            buf.Append("\t");
286            buf.Append(line);
287            buf.Append("\t");
288            buf.Append(pos);
289            int tokenIndex = adaptor.GetTokenStartIndex(t);
290            buf.Append("\t");
291            buf.Append(tokenIndex);
292            SerializeText(buf, text);
293        }
294
295        #endregion
296
297
298        #region AST Events
299
300        public override void NilNode(object t) {
301            int ID = adaptor.GetUniqueID(t);
302            Transmit("nilNode\t" + ID);
303        }
304
305        public override void ErrorNode(object t) {
306            int ID = adaptor.GetUniqueID(t);
307            string text = t.ToString();
308            StringBuilder buf = new StringBuilder(50);
309            buf.Append("errorNode\t");
310            buf.Append(ID);
311            buf.Append("\t");
312            buf.Append(TokenTypes.Invalid);
313            SerializeText(buf, text);
314            Transmit(buf.ToString());
315        }
316
317        public override void CreateNode(object t) {
318            int ID = adaptor.GetUniqueID(t);
319            string text = adaptor.GetText(t);
320            int type = adaptor.GetType(t);
321            StringBuilder buf = new StringBuilder(50);
322            buf.Append("createNodeFromTokenElements\t");
323            buf.Append(ID);
324            buf.Append("\t");
325            buf.Append(type);
326            SerializeText(buf, text);
327            Transmit(buf.ToString());
328        }
329
330        public override void CreateNode(object node, IToken token) {
331            int ID = adaptor.GetUniqueID(node);
332            int tokenIndex = token.TokenIndex;
333            Transmit("createNode\t" + ID + "\t" + tokenIndex);
334        }
335
336        public override void BecomeRoot(object newRoot, object oldRoot) {
337            int newRootID = adaptor.GetUniqueID(newRoot);
338            int oldRootID = adaptor.GetUniqueID(oldRoot);
339            Transmit("becomeRoot\t" + newRootID + "\t" + oldRootID);
340        }
341
342        public override void AddChild(object root, object child) {
343            int rootID = adaptor.GetUniqueID(root);
344            int childID = adaptor.GetUniqueID(child);
345            Transmit("addChild\t" + rootID + "\t" + childID);
346        }
347
348        public override void SetTokenBoundaries(object t, int tokenStartIndex, int tokenStopIndex) {
349            int ID = adaptor.GetUniqueID(t);
350            Transmit("setTokenBoundaries\t" + ID + "\t" + tokenStartIndex + "\t" + tokenStopIndex);
351        }
352
353        #endregion
354
355
356        #region Support
357
358        protected virtual string SerializeToken(IToken t) {
359            StringBuilder buf = new StringBuilder(50);
360            buf.Append(t.TokenIndex);
361            buf.Append('\t');
362            buf.Append(t.Type);
363            buf.Append('\t');
364            buf.Append(t.Channel);
365            buf.Append('\t');
366            buf.Append(t.Line);
367            buf.Append('\t');
368            buf.Append(t.CharPositionInLine);
369            SerializeText(buf, t.Text);
370            return buf.ToString();
371        }
372
373        protected virtual void SerializeText(StringBuilder buf, string text) {
374            buf.Append("\t\"");
375            if (text == null) {
376                text = "";
377            }
378            // escape \n and \r all text for token appears to exist on one line
379            // this escape is slow but easy to understand
380            text = EscapeNewlines(text);
381            buf.Append(text);
382        }
383
384        protected virtual string EscapeNewlines(string txt) {
385            txt = StringExtensions.replaceAll(txt, "%", "%25");   // escape all escape char ;)
386            txt = StringExtensions.replaceAll(txt, "\n", "%0A");  // escape \n
387            txt = StringExtensions.replaceAll(txt, "\r", "%0D");  // escape \r
388            return txt;
389        }
390
391        #endregion
392    }
393}
394