1/* 2 * Note to JL: Refactored extension methods 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 Antlr.Runtime.JavaExtensions; 37 using BaseTree = Antlr.Runtime.Tree.BaseTree; 38 using Console = System.Console; 39 using Exception = System.Exception; 40 using IOException = System.IO.IOException; 41 using ITree = Antlr.Runtime.Tree.ITree; 42 using Socket = System.Net.Sockets.Socket; 43 using SocketException = System.Net.Sockets.SocketException; 44 using TextReader = System.IO.TextReader; 45 using TextWriter = System.IO.TextWriter; 46 47 public class RemoteDebugEventSocketListener { 48 const int MAX_EVENT_ELEMENTS = 8; 49 IDebugEventListener listener; 50 string machine; 51 int port; 52 Socket channel = null; 53 TextWriter @out; 54 TextReader @in; 55 string @event; 56 /** <summary>Version of ANTLR (dictates events)</summary> */ 57 public string version; 58 public string grammarFileName; 59 /** <summary> 60 * Track the last token index we saw during a consume. If same, then 61 * set a flag that we have a problem. 62 * </summary> 63 */ 64 int previousTokenIndex = -1; 65 bool tokenIndexesInvalid = false; 66 67 public class ProxyToken : IToken { 68 int index; 69 int type; 70 int channel; 71 int line; 72 int charPos; 73 string text; 74 public ProxyToken(int index) { 75 this.index = index; 76 } 77 public ProxyToken(int index, int type, int channel, 78 int line, int charPos, string text) { 79 this.index = index; 80 this.type = type; 81 this.channel = channel; 82 this.line = line; 83 this.charPos = charPos; 84 this.text = text; 85 } 86 87 #region IToken Members 88 public string Text { 89 get { 90 return text; 91 } 92 set { 93 text = value; 94 } 95 } 96 97 public int Type { 98 get { 99 return type; 100 } 101 set { 102 type = value; 103 } 104 } 105 106 public int Line { 107 get { 108 return line; 109 } 110 set { 111 line = value; 112 } 113 } 114 115 public int CharPositionInLine { 116 get { 117 return charPos; 118 } 119 set { 120 charPos = value; 121 } 122 } 123 124 public int Channel { 125 get { 126 return channel; 127 } 128 set { 129 channel = value; 130 } 131 } 132 133 public int StartIndex { 134 get { 135 return -1; 136 } 137 set { 138 } 139 } 140 141 public int StopIndex { 142 get { 143 return -1; 144 } 145 set { 146 } 147 } 148 149 public int TokenIndex { 150 get { 151 return index; 152 } 153 set { 154 index = value; 155 } 156 } 157 158 public ICharStream InputStream { 159 get { 160 return null; 161 } 162 set { 163 } 164 } 165 166 #endregion 167 168 public override string ToString() { 169 string channelStr = ""; 170 if (channel != TokenChannels.Default) { 171 channelStr = ",channel=" + channel; 172 } 173 return "[" + Text + "/<" + type + ">" + channelStr + "," + line + ":" + CharPositionInLine + ",@" + index + "]"; 174 } 175 } 176 177 public class ProxyTree : BaseTree { 178 public int ID; 179 int type; 180 int line = 0; 181 public int charPos = -1; 182 public int tokenIndex = -1; 183 string text; 184 185 public ProxyTree(int ID, int type, int line, int charPos, int tokenIndex, string text) { 186 this.ID = ID; 187 this.type = type; 188 this.line = line; 189 this.charPos = charPos; 190 this.tokenIndex = tokenIndex; 191 this.text = text; 192 } 193 194 public ProxyTree(int ID) { 195 this.ID = ID; 196 } 197 198 #region Properties 199 public override string Text { 200 get { 201 return text; 202 } 203 set { 204 } 205 } 206 public override int TokenStartIndex { 207 get { 208 return tokenIndex; 209 } 210 set { 211 } 212 } 213 public override int TokenStopIndex { 214 get { 215 return 0; 216 } 217 set { 218 } 219 } 220 public override int Type { 221 get { 222 return type; 223 } 224 set { 225 } 226 } 227 #endregion 228 229 public override ITree DupNode() { 230 return null; 231 } 232 233 public override string ToString() { 234 return "fix this"; 235 } 236 } 237 238 public RemoteDebugEventSocketListener(IDebugEventListener listener, 239 string machine, 240 int port) { 241 this.listener = listener; 242 this.machine = machine; 243 this.port = port; 244 245 if (!OpenConnection()) { 246 throw new SocketException(); 247 } 248 } 249 250 protected virtual void EventHandler() { 251 try { 252 Handshake(); 253 @event = @in.ReadLine(); 254 while (@event != null) { 255 Dispatch(@event); 256 Ack(); 257 @event = @in.ReadLine(); 258 } 259 } catch (Exception e) { 260 Console.Error.WriteLine(e); 261 ExceptionExtensions.PrintStackTrace(e, Console.Error); 262 } finally { 263 CloseConnection(); 264 } 265 } 266 267 protected virtual bool OpenConnection() { 268 bool success = false; 269 try { 270 throw new System.NotImplementedException(); 271 //channel = new Socket( machine, port ); 272 //channel.setTcpNoDelay( true ); 273 //OutputStream os = channel.getOutputStream(); 274 //OutputStreamWriter osw = new OutputStreamWriter( os, "UTF8" ); 275 //@out = new PrintWriter( new BufferedWriter( osw ) ); 276 //InputStream @is = channel.getInputStream(); 277 //InputStreamReader isr = new InputStreamReader( @is, "UTF8" ); 278 //@in = new BufferedReader( isr ); 279 //success = true; 280 } catch (Exception e) { 281 Console.Error.WriteLine(e); 282 } 283 return success; 284 } 285 286 protected virtual void CloseConnection() { 287 try { 288 @in.Close(); 289 @in = null; 290 @out.Close(); 291 @out = null; 292 channel.Close(); 293 channel = null; 294 } catch (Exception e) { 295 Console.Error.WriteLine(e); 296 ExceptionExtensions.PrintStackTrace(e, Console.Error); 297 } finally { 298 if (@in != null) { 299 try { 300 @in.Close(); 301 } catch (IOException ioe) { 302 Console.Error.WriteLine(ioe); 303 } 304 } 305 if (@out != null) { 306 @out.Close(); 307 } 308 if (channel != null) { 309 try { 310 channel.Close(); 311 } catch (IOException ioe) { 312 Console.Error.WriteLine(ioe); 313 } 314 } 315 } 316 317 } 318 319 protected virtual void Handshake() { 320 string antlrLine = @in.ReadLine(); 321 string[] antlrElements = GetEventElements(antlrLine); 322 version = antlrElements[1]; 323 string grammarLine = @in.ReadLine(); 324 string[] grammarElements = GetEventElements(grammarLine); 325 grammarFileName = grammarElements[1]; 326 Ack(); 327 listener.Commence(); // inform listener after handshake 328 } 329 330 protected virtual void Ack() { 331 @out.WriteLine("ack"); 332 @out.Flush(); 333 } 334 335 protected virtual void Dispatch(string line) { 336 //JSystem.@out.println( "event: " + line ); 337 string[] elements = GetEventElements(line); 338 if (elements == null || elements[0] == null) { 339 Console.Error.WriteLine("unknown debug event: " + line); 340 return; 341 } 342 if (elements[0].Equals("enterRule")) { 343 listener.EnterRule(elements[1], elements[2]); 344 } else if (elements[0].Equals("exitRule")) { 345 listener.ExitRule(elements[1], elements[2]); 346 } else if (elements[0].Equals("enterAlt")) { 347 listener.EnterAlt(int.Parse(elements[1])); 348 } else if (elements[0].Equals("enterSubRule")) { 349 listener.EnterSubRule(int.Parse(elements[1])); 350 } else if (elements[0].Equals("exitSubRule")) { 351 listener.ExitSubRule(int.Parse(elements[1])); 352 } else if (elements[0].Equals("enterDecision")) { 353 listener.EnterDecision(int.Parse(elements[1]), elements[2].Equals("true")); 354 } else if (elements[0].Equals("exitDecision")) { 355 listener.ExitDecision(int.Parse(elements[1])); 356 } else if (elements[0].Equals("location")) { 357 listener.Location(int.Parse(elements[1]), 358 int.Parse(elements[2])); 359 } else if (elements[0].Equals("consumeToken")) { 360 ProxyToken t = DeserializeToken(elements, 1); 361 if (t.TokenIndex == previousTokenIndex) { 362 tokenIndexesInvalid = true; 363 } 364 previousTokenIndex = t.TokenIndex; 365 listener.ConsumeToken(t); 366 } else if (elements[0].Equals("consumeHiddenToken")) { 367 ProxyToken t = DeserializeToken(elements, 1); 368 if (t.TokenIndex == previousTokenIndex) { 369 tokenIndexesInvalid = true; 370 } 371 previousTokenIndex = t.TokenIndex; 372 listener.ConsumeHiddenToken(t); 373 } else if (elements[0].Equals("LT")) { 374 IToken t = DeserializeToken(elements, 2); 375 listener.LT(int.Parse(elements[1]), t); 376 } else if (elements[0].Equals("mark")) { 377 listener.Mark(int.Parse(elements[1])); 378 } else if (elements[0].Equals("rewind")) { 379 if (elements[1] != null) { 380 listener.Rewind(int.Parse(elements[1])); 381 } else { 382 listener.Rewind(); 383 } 384 } else if (elements[0].Equals("beginBacktrack")) { 385 listener.BeginBacktrack(int.Parse(elements[1])); 386 } else if (elements[0].Equals("endBacktrack")) { 387 int level = int.Parse(elements[1]); 388 int successI = int.Parse(elements[2]); 389 listener.EndBacktrack(level, successI == DebugEventListenerConstants.True); 390 } else if (elements[0].Equals("exception")) { 391#if true 392 throw new System.NotImplementedException(); 393#else 394 string excName = elements[1]; 395 string indexS = elements[2]; 396 string lineS = elements[3]; 397 string posS = elements[4]; 398 Class excClass = null; 399 try 400 { 401 excClass = Class.forName( excName ); 402 RecognitionException e = 403 (RecognitionException)excClass.newInstance(); 404 e.index = int.Parse( indexS ); 405 e.line = int.Parse( lineS ); 406 e.charPositionInLine = int.Parse( posS ); 407 listener.recognitionException( e ); 408 } 409 catch ( ClassNotFoundException cnfe ) 410 { 411 Console.Error.println( "can't find class " + cnfe ); 412 cnfe.printStackTrace( Console.Error ); 413 } 414 catch ( InstantiationException ie ) 415 { 416 Console.Error.println( "can't instantiate class " + ie ); 417 ie.printStackTrace( Console.Error ); 418 } 419 catch ( IllegalAccessException iae ) 420 { 421 Console.Error.println( "can't access class " + iae ); 422 iae.printStackTrace( Console.Error ); 423 } 424#endif 425 } else if (elements[0].Equals("beginResync")) { 426 listener.BeginResync(); 427 } else if (elements[0].Equals("endResync")) { 428 listener.EndResync(); 429 } else if (elements[0].Equals("terminate")) { 430 listener.Terminate(); 431 } else if (elements[0].Equals("semanticPredicate")) { 432 bool result = bool.Parse(elements[1]); 433 string predicateText = elements[2]; 434 predicateText = UnEscapeNewlines(predicateText); 435 listener.SemanticPredicate(result, 436 predicateText); 437 } else if (elements[0].Equals("consumeNode")) { 438 ProxyTree node = DeserializeNode(elements, 1); 439 listener.ConsumeNode(node); 440 } else if (elements[0].Equals("LN")) { 441 int i = int.Parse(elements[1]); 442 ProxyTree node = DeserializeNode(elements, 2); 443 listener.LT(i, node); 444 } else if (elements[0].Equals("createNodeFromTokenElements")) { 445 int ID = int.Parse(elements[1]); 446 int type = int.Parse(elements[2]); 447 string text = elements[3]; 448 text = UnEscapeNewlines(text); 449 ProxyTree node = new ProxyTree(ID, type, -1, -1, -1, text); 450 listener.CreateNode(node); 451 } else if (elements[0].Equals("createNode")) { 452 int ID = int.Parse(elements[1]); 453 int tokenIndex = int.Parse(elements[2]); 454 // create dummy node/token filled with ID, tokenIndex 455 ProxyTree node = new ProxyTree(ID); 456 ProxyToken token = new ProxyToken(tokenIndex); 457 listener.CreateNode(node, token); 458 } else if (elements[0].Equals("nilNode")) { 459 int ID = int.Parse(elements[1]); 460 ProxyTree node = new ProxyTree(ID); 461 listener.NilNode(node); 462 } else if (elements[0].Equals("errorNode")) { 463 // TODO: do we need a special tree here? 464 int ID = int.Parse(elements[1]); 465 int type = int.Parse(elements[2]); 466 string text = elements[3]; 467 text = UnEscapeNewlines(text); 468 ProxyTree node = new ProxyTree(ID, type, -1, -1, -1, text); 469 listener.ErrorNode(node); 470 } else if (elements[0].Equals("becomeRoot")) { 471 int newRootID = int.Parse(elements[1]); 472 int oldRootID = int.Parse(elements[2]); 473 ProxyTree newRoot = new ProxyTree(newRootID); 474 ProxyTree oldRoot = new ProxyTree(oldRootID); 475 listener.BecomeRoot(newRoot, oldRoot); 476 } else if (elements[0].Equals("addChild")) { 477 int rootID = int.Parse(elements[1]); 478 int childID = int.Parse(elements[2]); 479 ProxyTree root = new ProxyTree(rootID); 480 ProxyTree child = new ProxyTree(childID); 481 listener.AddChild(root, child); 482 } else if (elements[0].Equals("setTokenBoundaries")) { 483 int ID = int.Parse(elements[1]); 484 ProxyTree node = new ProxyTree(ID); 485 listener.SetTokenBoundaries( 486 node, 487 int.Parse(elements[2]), 488 int.Parse(elements[3])); 489 } else { 490 Console.Error.WriteLine("unknown debug event: " + line); 491 } 492 } 493 494 protected virtual ProxyTree DeserializeNode(string[] elements, int offset) { 495 int ID = int.Parse(elements[offset + 0]); 496 int type = int.Parse(elements[offset + 1]); 497 int tokenLine = int.Parse(elements[offset + 2]); 498 int charPositionInLine = int.Parse(elements[offset + 3]); 499 int tokenIndex = int.Parse(elements[offset + 4]); 500 string text = elements[offset + 5]; 501 text = UnEscapeNewlines(text); 502 return new ProxyTree(ID, type, tokenLine, charPositionInLine, tokenIndex, text); 503 } 504 505 protected virtual ProxyToken DeserializeToken(string[] elements, 506 int offset) { 507 string indexS = elements[offset + 0]; 508 string typeS = elements[offset + 1]; 509 string channelS = elements[offset + 2]; 510 string lineS = elements[offset + 3]; 511 string posS = elements[offset + 4]; 512 string text = elements[offset + 5]; 513 text = UnEscapeNewlines(text); 514 int index = int.Parse(indexS); 515 ProxyToken t = 516 new ProxyToken(index, 517 int.Parse(typeS), 518 int.Parse(channelS), 519 int.Parse(lineS), 520 int.Parse(posS), 521 text); 522 return t; 523 } 524 525 /** <summary>Create a thread to listen to the remote running recognizer</summary> */ 526 public virtual void Start() { 527 System.Threading.Thread t = new System.Threading.Thread(Run); 528 t.Start(); 529 } 530 531 public virtual void Run() { 532 EventHandler(); 533 } 534 535 #region Misc 536 537 public virtual string[] GetEventElements(string @event) { 538 if (@event == null) { 539 return null; 540 } 541 string[] elements = new string[MAX_EVENT_ELEMENTS]; 542 string str = null; // a string element if present (must be last) 543 try { 544 int firstQuoteIndex = @event.IndexOf('"'); 545 if (firstQuoteIndex >= 0) { 546 // treat specially; has a string argument like "a comment\n 547 // Note that the string is terminated by \n not end quote. 548 // Easier to parse that way. 549 string eventWithoutString = @event.Substring(0, firstQuoteIndex); 550 str = @event.Substring(firstQuoteIndex + 1); 551 @event = eventWithoutString; 552 } 553 StringTokenizer st = new StringTokenizer(@event, "\t", false); 554 int i = 0; 555 while (st.hasMoreTokens()) { 556 if (i >= MAX_EVENT_ELEMENTS) { 557 // ErrorManager.internalError("event has more than "+MAX_EVENT_ELEMENTS+" args: "+event); 558 return elements; 559 } 560 elements[i] = st.nextToken(); 561 i++; 562 } 563 if (str != null) { 564 elements[i] = str; 565 } 566 } catch (Exception e) { 567 ExceptionExtensions.PrintStackTrace(e, Console.Error); 568 } 569 return elements; 570 } 571 572 protected virtual string UnEscapeNewlines(string txt) { 573 // this unescape is slow but easy to understand 574 txt = StringExtensions.replaceAll(txt, "%0A", "\n"); // unescape \n 575 txt = StringExtensions.replaceAll(txt, "%0D", "\r"); // unescape \r 576 txt = StringExtensions.replaceAll(txt, "%25", "%"); // undo escaped escape chars 577 return txt; 578 } 579 580 public virtual bool TokenIndexesAreInvalid() { 581 return false; 582 //return tokenIndexesInvalid; 583 } 584 585 #endregion 586 587 } 588} 589