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