Просмотр исходного кода

Refecator debugger to allow alternate implementations

Hugh Sanderson 13 лет назад
Родитель
Сommit
a03444ffd7
4 измененных файлов с 734 добавлено и 533 удалено
  1. 590 0
      std/cpp/vm/DebugBase.hx
  2. 81 0
      std/cpp/vm/DebugSocket.hx
  3. 56 533
      std/cpp/vm/DebugStdio.hx
  4. 7 0
      std/cpp/vm/Debugger.hx

+ 590 - 0
std/cpp/vm/DebugBase.hx

@@ -0,0 +1,590 @@
+package cpp.vm;
+
+import haxe.Stack;
+
+enum DebugToken
+{
+   IDENT(name:String);
+   CONST(value:Dynamic);
+   DOT;
+   LPAREN;
+   RPAREN;
+   COMMA;
+   EQUALS;
+   LARRAY;
+   RARRAY;
+}
+
+enum DebugExpr
+{
+   EXPR_VALUE(value:Dynamic);
+   EXPR_FIELD_REF(obj:Dynamic,member:String);
+   EXPR_ARRAY_REF(obj:Dynamic,index:Int);
+   EXPR_STACK_REF(name:String);
+}
+
+
+
+class DebugBase
+{
+   var threadStopped:Bool;
+   var stillDebugging:Bool;
+   var inputThread:Thread;
+   var debugQueue:Deque<Dynamic>;
+   var files:Array<String>;
+	var frame:Int;
+	var stack:Array<StackItem>;
+	var vars:Array<String>;
+   
+
+   public function new()
+   {
+		frame = -1;
+		files = Debugger.getFiles();
+		stillDebugging = true;
+      threadStopped = false;
+		Debugger.setThread();
+      Debugger.setHandler(onDebug);
+      debugQueue= new Deque<Dynamic>();
+      inputThread = Thread.create(inputLoop);
+   }
+
+   function onDebug()
+   {
+      threadStopped = true;
+      onStopped();
+      while(threadStopped && stillDebugging)
+      {
+         var job = debugQueue.pop(true);
+         job();
+      }
+   }
+
+   function onHelp() { }
+
+   function waitDebugger(inSendResult:Bool=true)
+   {
+      debugQueue.add( function() inputThread.sendMessage("ok")  );
+      var result = Thread.readMessage(true);
+		if (inSendResult)
+		{
+			if (result!="ok")
+				onResult("Debugger out of sync");
+			else
+				onResult("ok");
+		}
+   }
+
+	function onStopped() { }
+
+	function onRunning() { }
+
+   function showWhere() { }
+
+   function showFiles() { }
+
+   function showBreakpoints() { }
+
+	function onPrint(result:Dynamic) { }
+
+   function getNextCommand() : String { return "bye"; }
+
+   function onResult(inResult:String) { }
+
+   function addBreakpoint(inFile:String, inLine:String)
+	{
+		var id = Std.parseInt(inFile);
+		if (id==null)
+		{
+			for(idx in 0...files.length)
+				if (files[idx]==inFile)
+				{
+					id = idx;
+					break;
+				}
+		}
+
+ 		if (id==null)
+         onResult("Could not find file for " + inFile );
+		else
+		{
+			Debugger.addBreakpoint(id,Std.parseInt(inLine));
+			onResult("ok");
+		}
+			
+	}
+
+   static var dot:Int = ".".charCodeAt(0);
+   static var quote:Int = "\"".charCodeAt(0);
+   static var comma:Int = ",".charCodeAt(0);
+   static var equals:Int = "=".charCodeAt(0);
+   static var minus:Int = "-".charCodeAt(0);
+   static var a_code:Int = "a".charCodeAt(0);
+   static var z_code:Int = "z".charCodeAt(0);
+   static var A_code:Int = "A".charCodeAt(0);
+   static var Z_code:Int = "Z".charCodeAt(0);
+   static var __code:Int = "_".charCodeAt(0);
+   static var num0_code:Int = "0".charCodeAt(0);
+   static var num9_code:Int = "9".charCodeAt(0);
+   static var space_code:Int = " ".charCodeAt(0);
+   static var lparent:Int = "(".charCodeAt(0);
+   static var rparent:Int = ")".charCodeAt(0);
+   static var larray:Int = "[".charCodeAt(0);
+   static var rarray:Int = "]".charCodeAt(0);
+
+
+   function tokenize(inString:String) : Array<DebugToken>
+   {
+      var len = inString.length;
+      var result = new Array<DebugToken>();
+
+      var idx = 0;
+		while(idx<len)
+		{
+			var code = inString.charCodeAt(idx);
+
+         // Identifier ...
+         if ( (code>=a_code && code<=z_code) || (code>=A_code && code<=Z_code) || code==__code )
+         {
+            var start = idx++;
+				while(idx<len)
+            {
+			      code = inString.charCodeAt(idx);
+               if ( (code>=a_code && code<=z_code) || (code>=A_code && code<=Z_code) || code==__code ||
+                    (code>=num0_code && code<num9_code) )
+						idx++;
+					else
+						break;
+            }
+            result.push( IDENT( inString.substr(start, idx-start) ) );
+         }
+			else if (code==minus || (code>=num0_code && code<=num9_code) )
+         {
+            var start = idx++;
+				while(idx<len)
+            {
+			      code = inString.charCodeAt(idx);
+               if (code==dot || (code>=num0_code && code<=num9_code) )
+						idx++;
+					else
+						break;
+            }
+            var val = inString.substr(start, idx-start);
+            var num = Std.parseFloat(val);
+				if (!Math.isFinite(num))
+					throw ("Bad constant '" + val + "'");
+            result.push( CONST(num) );
+ 
+         }
+			else if (code==quote)
+			{
+            var start = ++idx;
+				while(idx<len)
+            {
+			      code = inString.charCodeAt(idx);
+               if (code==quote)
+                  break;
+               idx++;
+            }
+            var val = inString.substr(start, idx-start);
+            result.push( CONST(val) );
+            idx++;
+			}
+         else
+         {
+         	switch(code)
+				{
+					case space_code : // do nothing
+					case lparent : result.push( LPAREN );
+					case rparent : result.push( RPAREN );
+					case larray : result.push( LARRAY );
+					case rarray : result.push( RARRAY );
+					case dot : result.push( DOT );
+					case comma : result.push( COMMA );
+					case equals : result.push( EQUALS );
+				}
+				idx++;
+			}
+		}
+
+      return result;
+   }
+
+   function resolve(inName:String) : DebugExpr
+	{
+		if (vars!=null)
+		{
+			for(v in vars)
+				if (v==inName)
+					return EXPR_STACK_REF(inName);
+		}
+		var cls = Type.resolveClass(inName);
+      if (cls!=null)
+         return EXPR_VALUE(cls);
+
+      return null;
+   }
+
+
+   function getExpression(inTokens:Array<DebugToken>) : DebugExpr
+   {
+      var classPath = "";
+      var expr:Dynamic = null;
+
+      var tok = 0;
+      var len = inTokens.length;
+      while(tok < len)
+      {
+			switch(inTokens[tok])
+         {
+   			case IDENT(name):
+					if (expr!=null)
+						throw "Misplaced '" + name + "'";
+					expr = resolve(name);
+					if (expr==null)
+						classPath = name;
+					tok++;
+
+   			case CONST(value):
+					if (expr!=null || classPath!="")
+						throw "Misplaced '" + value + "'";
+					expr = EXPR_VALUE(value);
+					tok++;
+
+   			case DOT:
+					if (expr==null && classPath=="")
+						throw "Bad '.' after null value";
+					tok++;
+					switch(inTokens[tok])
+					{
+						case IDENT(name):
+							if (expr!=null)
+								expr = EXPR_FIELD_REF(exprToDynamic(expr),name);
+							else
+							{
+								var qname = classPath + "." + name;
+								expr = resolve(qname);
+								classPath = (expr==null) ? qname : "";
+							}
+							tok++;
+						default: throw "Expected field after '.'";
+					}
+
+   			case LPAREN:
+						var args = new Array<Dynamic>();
+                  var lastComma = tok;
+						var start = ++tok;
+                  var parenOpen = 1;
+                  var arrayOpen = 0;
+						while(tok<len && (parenOpen!=0 || arrayOpen!=0) )
+						{
+					      switch(inTokens[tok])
+					      {
+   							case LPAREN: parenOpen++;
+   							case RPAREN: parenOpen--;
+   							case LARRAY: arrayOpen++;
+   							case RARRAY: arrayOpen--;
+   							case COMMA: 
+									if (arrayOpen==0 && parenOpen==1 && expr!=null)
+									{
+										args.push( getValue( inTokens.slice(lastComma+1,tok) ) );
+										lastComma = tok;
+									}
+								default:
+ 							}
+							tok++;
+						}
+						if (parenOpen!=0  || arrayOpen!=0)
+							throw "Mismatched '(' "+parenOpen+"/"+arrayOpen;
+						// Not function call...
+						if (classPath!="")
+							throw "Unresolved " + classPath;
+						if (expr==null)
+                  {
+							expr = EXPR_VALUE(getValue( inTokens.slice(start,tok-1) ));
+                  }
+						else
+						{
+                     if (lastComma+1 < tok-1)
+								args.push( getValue( inTokens.slice(lastComma+1,tok-1) ) );
+							expr = EXPR_VALUE( untyped expr.__Run( args ) );
+						}
+
+   			case LARRAY:
+						var start = ++tok;
+                  var parenOpen = 0;
+                  var arrayOpen = 1;
+						while(tok<len && (parenOpen!=0 || arrayOpen!=0) )
+						{
+					      switch(inTokens[tok])
+					      {
+   							case LPAREN: parenOpen++;
+   							case RPAREN: parenOpen--;
+   							case LARRAY: arrayOpen++;
+   							case RARRAY: arrayOpen--;
+								default:
+ 							}
+							tok++;
+						}
+						if (parenOpen!=0  || arrayOpen!=0)
+							throw "Mismatched '['";
+						if (classPath!=null)
+							throw "Unresolved " + classPath;
+						if (expr==null)
+							throw "Error taking index of null object";
+						var val:Dynamic = getValue( inTokens.slice(start,tok) );
+						if ( !Std.is(val,Int) )
+							throw "Bad array index: " + val;
+						expr = EXPR_ARRAY_REF(exprToDynamic(expr), Std.int(val));
+
+   			case RPAREN: throw "Misplaced ')'";
+   			case COMMA:  throw "Misplaced ','";
+   			case EQUALS: throw("Misplaced '='");
+   			case RARRAY: throw "Misplaced ']'";
+         }
+      }
+		if (classPath!="")
+			throw "Unresolved " + classPath;
+
+      return expr==null ? EXPR_VALUE(null) : expr;
+   }
+
+   function exprToDynamic(inExpr:DebugExpr)
+   {
+      switch(inExpr)
+      {
+         case EXPR_VALUE(value): return value;
+         case EXPR_FIELD_REF(obj,member): return Reflect.getProperty(obj,member);
+         case EXPR_ARRAY_REF(obj,index): return obj[index];
+         case EXPR_STACK_REF(name): return Debugger.getStackVar(frame,name);
+      }
+   }
+
+   function getValue(inTokens:Array<DebugToken>) : Dynamic
+   {
+      return exprToDynamic(getExpression(inTokens));
+   }
+
+
+   function print(inString:String)
+   {
+      var tokens:Array<DebugToken> = null;
+		try
+      {
+         tokens = tokenize(inString);
+         var result = getValue(tokens);
+         onPrint(result);
+			onResult("ok");
+      }
+      catch (e:Dynamic)
+      {
+         onResult("Error while printing : " + e);//+ ( tokens==null ? "" : " : " + tokens) );
+      }
+   }
+
+   function set(inString:String)
+   {
+      var tokens:Array<DebugToken> = null;
+		try
+      {
+         tokens = tokenize(inString);
+
+         var equals_pos = -1;
+         for(i in 0...tokens.length)
+         {
+            if (tokens[i]==EQUALS)
+            {
+               if (equals_pos>=0)
+                  throw "more than one '='";
+               equals_pos = i;
+            }
+         }
+         if (equals_pos<0)
+             throw "use a = b syntax";
+         if (equals_pos==0 || equals_pos==tokens.length-1)
+             throw "Misplaced '='";
+
+         var lhs = getExpression( tokens.slice(0,equals_pos) );
+         var rhs = getValue( tokens.slice(equals_pos+1, tokens.length) );
+
+         switch(lhs)
+         {
+            case EXPR_VALUE(value): throw "left hand side can't be set";
+            case EXPR_FIELD_REF(obj,member): Reflect.setProperty(obj,member,rhs);
+            case EXPR_ARRAY_REF(obj,index): obj[index] = rhs;
+            case EXPR_STACK_REF(name): Debugger.setStackVar(frame,name,rhs);
+         }
+      }
+      catch (e:Dynamic)
+      {
+         onResult("Error while setting : " + e);//+ ( tokens==null ? "" : " : " + tokens) );
+			return;
+      }
+		onResult("ok");
+   }
+
+
+   function setFrame(inFrame:Int)
+	{
+		if (stack!=null && inFrame>0 && inFrame <= stack.length )
+		{
+			frame = inFrame;
+         vars = Debugger.getStackVars(frame);
+		}
+	}
+
+   function getStack()
+	{
+      stack = haxe.Stack.callStack();
+		setFrame(1);
+	}
+
+   function checkStack()
+	{
+   	if (threadStopped && stack==null)
+		{
+          debugQueue.add( getStack );
+          waitDebugger(false);
+		}
+	}
+
+	function run()
+	{
+		stack = null;
+		vars = null;
+      debugQueue.add( function() { threadStopped = false; inputThread.sendMessage("running"); }  );
+      var result = Thread.readMessage(true);
+		onRunning();
+		onResult("ok");
+	}
+
+   function inputLoop()
+   {
+      while(stillDebugging)
+      {
+			checkStack();
+         var command = getNextCommand();
+         var words = command.split(" ");
+         switch(words[0])
+         {
+            case "":
+					onResult("");
+               // Do nothing
+
+            case "bye":
+					stillDebugging = false;
+      			debugQueue.add( function() { trace("bye"); }  );
+					onResult("ok");
+
+            case "exit","quit":
+					onResult("ok");
+               Debugger.exit();
+
+            case "break","b":
+					if (words.length==1)
+					{
+               	if (threadStopped)
+							onResult("already stopped.");
+               	else
+               	{
+                  	Debugger.setBreak(Debugger.BRK_ASAP);
+                  	waitDebugger();
+               	}
+					}
+					else if (words.length==3)
+					{
+						addBreakpoint(words[1],words[2]);
+					}
+					else
+						onResult("Usage: break [file line] - pause execution of one thread [when at certain point]");
+
+
+            case "cont","c":
+               if (!threadStopped)
+                  onResult("Already running.");
+               else
+						run();
+
+            case "vars","v":
+               if (!threadStopped || vars==null)
+                  onResult("Must break first.");
+               else
+               {
+						onPrint(vars);
+						onResult("ok");
+               }
+
+
+            case "frame","f":
+               if (!threadStopped || stack==null )
+                  onResult("Must break first.");
+               else
+               {
+						var f = Std.parseInt(words[1]);
+						if (f<1 || f>stack.length )
+							onResult("Stack out of range.");
+						else
+						{
+                  	debugQueue.add( function() setFrame(f) );
+                  	waitDebugger();
+						}
+               }
+              
+
+            case "where","w":
+               if (!threadStopped || stack==null)
+                  onResult("Must break first.");
+               else
+					{
+						showWhere();
+						onResult("ok");
+					}
+
+            case "print","p":
+					words.shift();
+					print(words.join(" "));
+
+            case "set","s":
+					words.shift();
+					set(words.join(" "));
+
+
+            case "files","fi":
+					{
+               	showFiles();
+						onResult("ok");
+					}
+
+            case "breakpoints","bp":
+					{
+               	showBreakpoints();
+						onResult("ok");
+					}
+
+            case "delete","d":
+               if (words[1]==null)
+					{
+						onResult("Usage : delete N");
+ 					}
+					else
+					{
+                  var i = Std.parseInt(words[1]);
+						Debugger.deleteBreakpoint(i);
+						onResult("ok");
+					}
+
+            case "help","h","?":
+					{
+						onHelp();
+						onResult("ok");
+					}
+              
+            default:
+               onResult("Unknown command:" + command);
+         }
+      }
+   }
+
+}
+
+

+ 81 - 0
std/cpp/vm/DebugSocket.hx

@@ -0,0 +1,81 @@
+package cpp.vm;
+
+import haxe.Stack;
+import cpp.vm.DebugBase;
+import cpp.net.Socket;
+
+
+class DebugSocket extends DebugStdio
+{
+ 	var socket:Socket;
+   var socketOut:haxe.io.Output;
+	var host:String;
+	var port:Int;
+
+
+   public function new(inHost:String, inPort:Int, inCreateStooped:Bool=false)
+   {
+		host = inHost;
+		port = inPort;
+		super(inCreateStooped);
+	}
+
+	override function init()
+	{
+      try
+      {
+         socket = new Socket();
+         trace("Connect " + host + ":" + port + "...");
+         try
+			{
+         	socket.connect( new cpp.net.Host(host), port );
+         } catch (e:Dynamic)
+			{
+             trace("Could not CONNECT!");
+             socket = null;
+         }
+
+         trace("connected.");
+			if (socket!=null)
+			{
+         	input = socket.input;
+         	socketOut = socket.output;
+			}
+      }
+      catch(e:Dynamic)
+      {
+         if (socket!=null)
+            socket.close();
+         socket = null;
+         trace("Socket error:" + e);
+      }
+
+		stillDebugging = socket!=null;
+   }
+
+	override function getNextCommand() : String
+	{
+		if (input==null)
+			return "bye";
+		try
+		{
+			return input.readLine();
+		}
+		catch(e:Dynamic)
+		{
+			trace("getNextCommand - socket closed");
+			input.close();
+			input = null;
+		}
+		return "bye";
+	}
+
+	override function sendOutput(inString:String)
+	{
+		// TODO
+		//Sys.println(inString);
+   }
+
+}
+
+

+ 56 - 533
std/cpp/vm/DebugStdio.hx

@@ -1,581 +1,104 @@
 package cpp.vm;
 
 import haxe.Stack;
-
-enum DebugToken
-{
-   IDENT(name:String);
-   CONST(value:Dynamic);
-   DOT;
-   LPAREN;
-   RPAREN;
-   COMMA;
-   EQUALS;
-   LARRAY;
-   RARRAY;
-}
-
-enum DebugExpr
-{
-   EXPR_VALUE(value:Dynamic);
-   EXPR_FIELD_REF(obj:Dynamic,member:String);
-   EXPR_ARRAY_REF(obj:Dynamic,index:Int);
-   EXPR_STACK_REF(name:String);
-}
-
+import cpp.vm.DebugBase;
 
 
-class DebugStdio
+class DebugStdio extends DebugBase
 {
-   var threadStopped:Bool;
-   var inputThread:Thread;
-   var debugQueue:Deque<Dynamic>;
-   var files:Array<String>;
-	var frame:Int;
-	var stack:Array<StackItem>;
-	var vars:Array<String>;
-   
-
-   public function new()
-   {
-		frame = -1;
-		files = Debugger.getFiles();
-      threadStopped = false;
-		Debugger.setThread();
-      Debugger.setHandler(onDebug);
-      debugQueue= new Deque<Dynamic>();
-      inputThread = Thread.create(inputLoop);
-   }
-
-   function onDebug()
-   {
-      Sys.println("stopped.");
-      threadStopped = true;
-      while(threadStopped)
-      {
-         var job = debugQueue.pop(true);
-         job();
-      }
-   }
-
-   
-   function waitDebugger(inPrint:Bool=true)
-   {
-      debugQueue.add( function() inputThread.sendMessage("Ok")  );
-      var result = Thread.readMessage(true);
-		if (inPrint)
-      	Sys.println(result);
-   }
-
-   function where()
-   {
-      var idx = 0;
-      for(item in stack)
-      {
-         idx++;
-         Sys.println((idx==frame ? "*" : " ") + idx + ":" + item);
-      }
-   }
+	var input:haxe.io.Input;
 
-   function showFiles()
+   public function new(inCreateStooped:Bool=false)
    {
- 		if (files!=null)
-			for(idx in 0...files.length)
-            Sys.println("file " + idx + " : " + files[idx] );
+		super();
+		init();
+		if (inCreateStooped && stillDebugging)
+			Debugger.breakBad();
    }
 
-   function showBreakpoints()
-   {
-      var bps = Debugger.getBreakpoints();
- 		if (bps!=null)
-			for(idx in 0...bps.length)
-            Sys.println("breakpoint " + idx + " : " + bps[idx] );
-   }
-
-
-   function addBreakpoint(inFile:String, inLine:String)
+	function init()
 	{
-		var id = Std.parseInt(inFile);
-		if (id==null)
-		{
-			for(idx in 0...files.length)
-				if (files[idx]==inFile)
-				{
-					id = idx;
-					break;
-				}
-		}
-
- 		if (id==null)
-         Sys.println("Could not find file for " + inFile );
-		else
-			Debugger.addBreakpoint(id,Std.parseInt(inLine));
-			
+		input = Sys.stdin();
 	}
 
-   static var dot:Int = ".".charCodeAt(0);
-   static var quote:Int = "\"".charCodeAt(0);
-   static var comma:Int = ",".charCodeAt(0);
-   static var equals:Int = "=".charCodeAt(0);
-   static var minus:Int = "-".charCodeAt(0);
-   static var a_code:Int = "a".charCodeAt(0);
-   static var z_code:Int = "z".charCodeAt(0);
-   static var A_code:Int = "A".charCodeAt(0);
-   static var Z_code:Int = "Z".charCodeAt(0);
-   static var __code:Int = "_".charCodeAt(0);
-   static var num0_code:Int = "0".charCodeAt(0);
-   static var num9_code:Int = "9".charCodeAt(0);
-   static var space_code:Int = " ".charCodeAt(0);
-   static var lparent:Int = "(".charCodeAt(0);
-   static var rparent:Int = ")".charCodeAt(0);
-   static var larray:Int = "[".charCodeAt(0);
-   static var rarray:Int = "]".charCodeAt(0);
 
+	override function getNextCommand() : String
+	{
+		Sys.print("debug>");
+		return input.readLine();
+	}
 
-   function tokenize(inString:String) : Array<DebugToken>
-   {
-      var len = inString.length;
-      var result = new Array<DebugToken>();
-
-      var idx = 0;
-		while(idx<len)
-		{
-			var code = inString.charCodeAt(idx);
-
-         // Identifier ...
-         if ( (code>=a_code && code<=z_code) || (code>=A_code && code<=Z_code) || code==__code )
-         {
-            var start = idx++;
-				while(idx<len)
-            {
-			      code = inString.charCodeAt(idx);
-               if ( (code>=a_code && code<=z_code) || (code>=A_code && code<=Z_code) || code==__code ||
-                    (code>=num0_code && code<num9_code) )
-						idx++;
-					else
-						break;
-            }
-            result.push( IDENT( inString.substr(start, idx-start) ) );
-         }
-			else if (code==minus || (code>=num0_code && code<=num9_code) )
-         {
-            var start = idx++;
-				while(idx<len)
-            {
-			      code = inString.charCodeAt(idx);
-               if (code==dot || (code>=num0_code && code<=num9_code) )
-						idx++;
-					else
-						break;
-            }
-            var val = inString.substr(start, idx-start);
-            var num = Std.parseFloat(val);
-				if (!Math.isFinite(num))
-					throw ("Bad constant '" + val + "'");
-            result.push( CONST(num) );
- 
-         }
-			else if (code==quote)
-			{
-            var start = ++idx;
-				while(idx<len)
-            {
-			      code = inString.charCodeAt(idx);
-               if (code==quote)
-                  break;
-               idx++;
-            }
-            var val = inString.substr(start, idx-start);
-            result.push( CONST(val) );
-            idx++;
-			}
-         else
-         {
-         	switch(code)
-				{
-					case space_code : // do nothing
-					case lparent : result.push( LPAREN );
-					case rparent : result.push( RPAREN );
-					case larray : result.push( LARRAY );
-					case rarray : result.push( RARRAY );
-					case dot : result.push( DOT );
-					case comma : result.push( COMMA );
-					case equals : result.push( EQUALS );
-				}
-				idx++;
-			}
-		}
 
-      return result;
+	function sendOutput(inString:String)
+	{
+		Sys.println(inString);
    }
 
-   function resolve(inName:String) : DebugExpr
+	function sendStatus(inString:String)
 	{
-		if (vars!=null)
-		{
-			for(v in vars)
-				if (v==inName)
-					return EXPR_STACK_REF(inName);
-		}
-		var cls = Type.resolveClass(inName);
-      if (cls!=null)
-         return EXPR_VALUE(cls);
-
-      return null;
+		sendOutput(inString);
    }
 
+	override function onRunning()
+	{
+		sendStatus("running");
+	}
 
-   function getExpression(inTokens:Array<DebugToken>) : DebugExpr
-   {
-      var classPath = "";
-      var expr:Dynamic = null;
-
-      var tok = 0;
-      var len = inTokens.length;
-      while(tok < len)
-      {
-			switch(inTokens[tok])
-         {
-   			case IDENT(name):
-					if (expr!=null)
-						throw "Misplaced '" + name + "'";
-					expr = resolve(name);
-					if (expr==null)
-						classPath = name;
-					tok++;
-
-   			case CONST(value):
-					if (expr!=null || classPath!="")
-						throw "Misplaced '" + value + "'";
-					expr = EXPR_VALUE(value);
-					tok++;
-
-   			case DOT:
-					if (expr==null && classPath=="")
-						throw "Bad '.' after null value";
-					tok++;
-					switch(inTokens[tok])
-					{
-						case IDENT(name):
-							if (expr!=null)
-								expr = EXPR_FIELD_REF(exprToDynamic(expr),name);
-							else
-							{
-								var qname = classPath + "." + name;
-								expr = resolve(qname);
-								classPath = (expr==null) ? qname : "";
-							}
-							tok++;
-						default: throw "Expected field after '.'";
-					}
-
-   			case LPAREN:
-						var args = new Array<Dynamic>();
-                  var lastComma = tok;
-						var start = ++tok;
-                  var parenOpen = 1;
-                  var arrayOpen = 0;
-						while(tok<len && (parenOpen!=0 || arrayOpen!=0) )
-						{
-					      switch(inTokens[tok])
-					      {
-   							case LPAREN: parenOpen++;
-   							case RPAREN: parenOpen--;
-   							case LARRAY: arrayOpen++;
-   							case RARRAY: arrayOpen--;
-   							case COMMA: 
-									if (arrayOpen==0 && parenOpen==1 && expr!=null)
-									{
-										args.push( getValue( inTokens.slice(lastComma+1,tok) ) );
-										lastComma = tok;
-									}
-								default:
- 							}
-							tok++;
-						}
-						if (parenOpen!=0  || arrayOpen!=0)
-							throw "Mismatched '(' "+parenOpen+"/"+arrayOpen;
-						// Not function call...
-						if (classPath!="")
-							throw "Unresolved " + classPath;
-						if (expr==null)
-                  {
-							expr = EXPR_VALUE(getValue( inTokens.slice(start,tok-1) ));
-                  }
-						else
-						{
-                     if (lastComma+1 < tok-1)
-								args.push( getValue( inTokens.slice(lastComma+1,tok-1) ) );
-							expr = EXPR_VALUE( untyped expr.__Run( args ) );
-						}
-
-   			case LARRAY:
-						var start = ++tok;
-                  var parenOpen = 0;
-                  var arrayOpen = 1;
-						while(tok<len && (parenOpen!=0 || arrayOpen!=0) )
-						{
-					      switch(inTokens[tok])
-					      {
-   							case LPAREN: parenOpen++;
-   							case RPAREN: parenOpen--;
-   							case LARRAY: arrayOpen++;
-   							case RARRAY: arrayOpen--;
-								default:
- 							}
-							tok++;
-						}
-						if (parenOpen!=0  || arrayOpen!=0)
-							throw "Mismatched '['";
-						if (classPath!=null)
-							throw "Unresolved " + classPath;
-						if (expr==null)
-							throw "Error taking index of null object";
-						var val:Dynamic = getValue( inTokens.slice(start,tok) );
-						if ( !Std.is(val,Int) )
-							throw "Bad array index: " + val;
-						expr = EXPR_ARRAY_REF(exprToDynamic(expr), Std.int(val));
-
-   			case RPAREN: throw "Misplaced ')'";
-   			case COMMA:  throw "Misplaced ','";
-   			case EQUALS: throw("Misplaced '='");
-   			case RARRAY: throw "Misplaced ']'";
-         }
-      }
-		if (classPath!="")
-			throw "Unresolved " + classPath;
 
-      return expr==null ? EXPR_VALUE(null) : expr;
+   override function onStopped()
+   {
+      sendStatus("stopped.");
    }
 
-   function exprToDynamic(inExpr:DebugExpr)
+   override function showWhere()
    {
-      switch(inExpr)
+      var idx = 0;
+      for(item in stack)
       {
-         case EXPR_VALUE(value): return value;
-         case EXPR_FIELD_REF(obj,member): return Reflect.getProperty(obj,member);
-         case EXPR_ARRAY_REF(obj,index): return obj[index];
-         case EXPR_STACK_REF(name): return Debugger.getStackVar(frame,name);
+         idx++;
+         sendOutput((idx==frame ? "*" : " ") + idx + ":" + item);
       }
    }
 
-   function getValue(inTokens:Array<DebugToken>) : Dynamic
-   {
-      return exprToDynamic(getExpression(inTokens));
-   }
-
-
-	function printResult(result:String)
-	{
-		Sys.println(result);
-	}
-
-
-   function print(inString:String)
+   override function showFiles()
    {
-      var tokens:Array<DebugToken> = null;
-		try
-      {
-         tokens = tokenize(inString);
-         var result = getValue(tokens);
-         printResult(result);
-      }
-      catch (e:Dynamic)
-      {
-         Sys.println("Error while printing : " + e);//+ ( tokens==null ? "" : " : " + tokens) );
-      }
+ 		if (files!=null)
+			for(idx in 0...files.length)
+            sendOutput("file " + idx + " : " + files[idx] );
    }
 
-   function set(inString:String)
+   override function showBreakpoints()
    {
-      var tokens:Array<DebugToken> = null;
-		try
-      {
-         tokens = tokenize(inString);
-
-         var equals_pos = -1;
-         for(i in 0...tokens.length)
-         {
-            if (tokens[i]==EQUALS)
-            {
-               if (equals_pos>=0)
-                  throw "more than one '='";
-               equals_pos = i;
-            }
-         }
-         if (equals_pos<0)
-             throw "use a = b syntax";
-         if (equals_pos==0 || equals_pos==tokens.length-1)
-             throw "Misplaced '='";
-
-         var lhs = getExpression( tokens.slice(0,equals_pos) );
-         var rhs = getValue( tokens.slice(equals_pos+1, tokens.length) );
-
-         switch(lhs)
-         {
-            case EXPR_VALUE(value): throw "left hand side can't be set";
-            case EXPR_FIELD_REF(obj,member): Reflect.setProperty(obj,member,rhs);
-            case EXPR_ARRAY_REF(obj,index): obj[index] = rhs;
-            case EXPR_STACK_REF(name): Debugger.setStackVar(frame,name,rhs);
-         }
-      }
-      catch (e:Dynamic)
-      {
-         Sys.println("Error while setting : " + e);//+ ( tokens==null ? "" : " : " + tokens) );
-      }
+      var bps = Debugger.getBreakpoints();
+ 		if (bps!=null)
+			for(idx in 0...bps.length)
+            sendOutput("breakpoint " + idx + " : " + bps[idx] );
    }
 
-
-   function setFrame(inFrame:Int)
+	override function onPrint(result:String)
 	{
-		if (stack!=null && inFrame>0 && inFrame <= stack.length )
-		{
-			frame = inFrame;
-         vars = Debugger.getStackVars(frame);
-		}
+		sendOutput(result);
 	}
 
-   function getStack()
+	override function onResult(inResult:String)
 	{
-      stack = haxe.Stack.callStack();
-		setFrame(1);
+		sendOutput(inResult);
 	}
 
-   function checkStack()
+	override function onHelp()
 	{
-   	if (threadStopped && stack==null)
-		{
-          debugQueue.add( getStack );
-          waitDebugger(false);
-		}
+ 		sendOutput("help  - print this message");
+      sendOutput("break [file line] - pause execution of one thread [when at certain point]");
+      sendOutput("breakpoints - list breakpoints");
+      sendOutput("delete N - delete breakpoint N");
+      sendOutput("cont  - continue execution");
+      sendOutput("where - print call stack");
+      sendOutput("files - print file list that may be used with breakpoints");
+      sendOutput("vars - print local vars for frame");
+      sendOutput("exit  - exit programme");
+      sendOutput("bye  - stop debugging, keep running");
 	}
 
-	function run()
-	{
-		stack = null;
-		vars = null;
-      debugQueue.add( function() { threadStopped = false; inputThread.sendMessage("running"); }  );
-      var result = Thread.readMessage(true);
-		Sys.println(result);
-	}
-
-   function inputLoop()
-   {
-      var input = Sys.stdin();
-      while(true)
-      {
-         Sys.print("debug >");
-			checkStack();
-         var command = input.readLine();
-         var words = command.split(" ");
-         switch(words[0])
-         {
-            case "":
-               // Do nothing
-
-            case "exit","quit":
-               Debugger.exit();
-
-            case "break","b":
-					if (words.length==1)
-					{
-               	if (threadStopped)
-                  	Sys.println("already stopped.");
-               	else
-               	{
-                  	Debugger.setBreak(Debugger.BRK_ASAP);
-                  	waitDebugger();
-               	}
-					}
-					else if (words.length==3)
-					{
-						addBreakpoint(words[1],words[2]);
-					}
-					else
-						Sys.println("Usage: break [file line] - pause execution of one thread [when at certain point]");
-
-
-            case "cont","c":
-               if (!threadStopped)
-                  Sys.println("Already running.");
-               else
-						run();
-
-            case "vars","v":
-               if (!threadStopped || vars==null)
-                  Sys.println("Must break first.");
-               else
-               {
-						Sys.println(vars);
-               }
-
-
-            case "frame","f":
-               if (!threadStopped || stack==null )
-                  Sys.println("Must break first.");
-               else
-               {
-						var f = Std.parseInt(words[1]);
-						if (f<1 || f>stack.length )
-							Sys.println("Stack out of range.");
-						else
-						{
-                  	debugQueue.add( function() setFrame(f) );
-                  	waitDebugger();
-						}
-               }
-              
-
-            case "where","w":
-               if (!threadStopped || stack==null)
-                  Sys.println("Must break first.");
-               else
-						where();
-
-            case "print","p":
-					words.shift();
-					print(words.join(" "));
-
-            case "set","s":
-					words.shift();
-					set(words.join(" "));
-
-
-            case "files","fi":
-               showFiles();
-
-            case "breakpoints","bp":
-               showBreakpoints();
-
-            case "delete","d":
-               if (words[1]==null)
-					{
-						Sys.println("Usage : delete N");
- 					}
-					else
-					{
-                  var i = Std.parseInt(words[1]);
-						Debugger.deleteBreakpoint(i);
-					}
-
-            case "help","h","?":
-               Sys.println("help  - print this message");
-               Sys.println("break [file line] - pause execution of one thread [when at certain point]");
-               Sys.println("breakpoints - list breakpoints");
-               Sys.println("delete N - delete breakpoint N");
-               Sys.println("cont  - continue execution");
-               Sys.println("where - print call stack");
-               Sys.println("files - print file list that may be used with breakpoints");
-               Sys.println("vars - print local vars for frame");
-               Sys.println("exit  - exit programme");
-
-
-            default:
-               Sys.println("Unknown command:" + words);
-         }
-      }
-   }
-
 }
 
 

+ 7 - 0
std/cpp/vm/Debugger.hx

@@ -4,6 +4,7 @@ import haxe.Stack;
 
 class Debugger
 {
+   public static inline var BRK_THIS      = -2;
    public static inline var BRK_TERMINATE = -1;
 
    public static inline var BRK_NONE  = 0;
@@ -33,6 +34,12 @@ class Debugger
    {
       untyped __global__.__hxcpp_dbg_set_break(BRK_TERMINATE);
    }
+   public static function breakBad()
+   {
+      untyped __global__.__hxcpp_dbg_set_break(BRK_THIS);
+   }
+
+
 
    // Breakpoint
    public static function addBreakpoint(inFileId:Int, inLine:Int)