summaryrefslogtreecommitdiff
path: root/mcs/tools/csharp/repl.cs
diff options
context:
space:
mode:
Diffstat (limited to 'mcs/tools/csharp/repl.cs')
-rw-r--r--mcs/tools/csharp/repl.cs236
1 files changed, 179 insertions, 57 deletions
diff --git a/mcs/tools/csharp/repl.cs b/mcs/tools/csharp/repl.cs
index abdaed2d13..1d8738bce7 100644
--- a/mcs/tools/csharp/repl.cs
+++ b/mcs/tools/csharp/repl.cs
@@ -8,6 +8,7 @@
//
// Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
// Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
+// Copyright 2011-2013 Xamarin Inc
//
//
// TODO:
@@ -34,6 +35,8 @@ namespace Mono {
public class Driver {
public static string StartupEvalExpression;
static int? attach;
+ static string target_host;
+ static int target_port;
static string agent;
static int Main (string [] args)
@@ -73,15 +76,17 @@ namespace Mono {
CSharpShell shell;
#if !ON_DOTNET
if (attach.HasValue) {
- shell = new ClientCSharpShell (eval, attach.Value);
+ shell = new ClientCSharpShell_v1 (eval, attach.Value);
} else if (agent != null) {
new CSharpAgent (eval, agent, agent_stderr).Run (startup_files);
return 0;
} else
#endif
- {
+ if (target_host != null)
+ shell = new ClientCSharpShell (eval, target_host, target_port);
+ else
shell = new CSharpShell (eval);
- }
+
return shell.Run (startup_files);
}
@@ -101,6 +106,26 @@ namespace Mono {
}
break;
default:
+ if (args [pos].StartsWith ("--server=")){
+ var hostport = args [pos].Substring (9);
+ int p = hostport.IndexOf (':');
+ if (p == -1){
+ target_host = hostport;
+ target_port = 10000;
+ } else {
+ target_host = hostport.Substring (0,p);
+ if (!int.TryParse (hostport.Substring (p), out target_port)){
+ Console.Error.WriteLine ("Usage is: --server[=host[:port]");
+ Environment.Exit (1);
+ }
+ }
+ return pos + 1;
+ }
+ if (args [pos].StartsWith ("--client")){
+ target_host = "localhost";
+ target_port = 10000;
+ return pos + 1;
+ }
if (args [pos].StartsWith ("--agent:")) {
agent = args[pos];
return pos + 1;
@@ -513,6 +538,154 @@ namespace Mono {
}
+ //
+ // Stream helper extension methods
+ //
+ public static class StreamHelper {
+ static DataConverter converter = DataConverter.LittleEndian;
+
+ static void GetBuffer (this Stream stream, byte [] b)
+ {
+ int n, offset = 0;
+ int len = b.Length;
+
+ do {
+ n = stream.Read (b, offset, len);
+ if (n == 0)
+ throw new IOException ("End reached");
+
+ offset += n;
+ len -= n;
+ } while (len > 0);
+ }
+
+ public static int GetInt (this Stream stream)
+ {
+ byte [] b = new byte [4];
+ stream.GetBuffer (b);
+ return converter.GetInt32 (b, 0);
+ }
+
+ public static string GetString (this Stream stream)
+ {
+ int len = stream.GetInt ();
+ if (len == 0)
+ return "";
+
+ byte [] b = new byte [len];
+ stream.GetBuffer (b);
+
+ return Encoding.UTF8.GetString (b);
+ }
+
+ public static void WriteInt (this Stream stream, int n)
+ {
+ byte [] bytes = converter.GetBytes (n);
+ stream.Write (bytes, 0, bytes.Length);
+ }
+
+ public static void WriteString (this Stream stream, string s)
+ {
+ stream.WriteInt (s.Length);
+ byte [] bytes = Encoding.UTF8.GetBytes (s);
+ stream.Write (bytes, 0, bytes.Length);
+ }
+ }
+
+ public enum AgentStatus : byte {
+ // Received partial input, complete
+ PARTIAL_INPUT = 1,
+
+ // The result was set, expect the string with the result
+ RESULT_SET = 2,
+
+ // No result was set, complete
+ RESULT_NOT_SET = 3,
+
+ // Errors and warnings string follows
+ ERROR = 4,
+ }
+
+ class ClientCSharpShell : CSharpShell {
+ string target_host;
+ int target_port;
+
+ public ClientCSharpShell (Evaluator evaluator, string target_host, int target_port) : base (evaluator)
+ {
+ this.target_port = target_port;
+ this.target_host = target_host;
+ }
+
+ T ConnectServer<T> (Func<NetworkStream,T> callback, Action<Exception> error)
+ {
+ try {
+ var client = new TcpClient (target_host, target_port);
+ var ns = client.GetStream ();
+ T ret = callback (ns);
+ ns.Flush ();
+ ns.Close ();
+ client.Close ();
+ return ret;
+ } catch (Exception e){
+ error (e);
+ return default(T);
+ }
+ }
+
+ protected override string Evaluate (string input)
+ {
+ return ConnectServer<string> ((ns)=> {
+ try {
+ ns.WriteString ("EVALTXT");
+ ns.WriteString (input);
+
+ while (true) {
+ AgentStatus s = (AgentStatus) ns.ReadByte ();
+
+ switch (s){
+ case AgentStatus.PARTIAL_INPUT:
+ return input;
+
+ case AgentStatus.ERROR:
+ string err = ns.GetString ();
+ Console.Error.WriteLine (err);
+ break;
+
+ case AgentStatus.RESULT_NOT_SET:
+ return null;
+
+ case AgentStatus.RESULT_SET:
+ string res = ns.GetString ();
+ Console.WriteLine (res);
+ return null;
+ }
+ }
+ } catch (Exception e){
+ Console.Error.WriteLine ("Error evaluating expression, exception: {0}", e);
+ }
+ return null;
+ }, (e) => {
+ Console.Error.WriteLine ("Error communicating with server {0}", e);
+ });
+ }
+
+ public override int Run (string [] startup_files)
+ {
+ // The difference is that we do not call Evaluator.Init, that is done on the target
+ this.startup_files = startup_files;
+ return ReadEvalPrintLoop ();
+ }
+
+ protected override void ConsoleInterrupt (object sender, ConsoleCancelEventArgs a)
+ {
+ ConnectServer<int> ((ns)=> {
+ ns.WriteString ("INTERRUPT");
+ return 0;
+ }, (e) => { });
+ }
+
+ }
+
#if !ON_DOTNET
//
// A shell connected to a CSharpAgent running in a remote process.
@@ -520,10 +693,10 @@ namespace Mono {
// - Support Gtk and Winforms main loops if detected, this should
// probably be done as a separate agent in a separate place.
//
- class ClientCSharpShell : CSharpShell {
+ class ClientCSharpShell_v1 : CSharpShell {
NetworkStream ns, interrupt_stream;
- public ClientCSharpShell (Evaluator evaluator, int pid)
+ public ClientCSharpShell_v1 (Evaluator evaluator, int pid)
: base (evaluator)
{
// Create a server socket we listen on whose address is passed to the agent
@@ -548,7 +721,7 @@ namespace Mono {
Console.WriteLine ("Connected.");
}
-
+
//
// A remote version of Evaluate
//
@@ -599,57 +772,6 @@ namespace Mono {
}
//
- // Stream helper extension methods
- //
- public static class StreamHelper {
- static DataConverter converter = DataConverter.LittleEndian;
-
- public static int GetInt (this Stream stream)
- {
- byte [] b = new byte [4];
- if (stream.Read (b, 0, 4) != 4)
- throw new IOException ("End reached");
- return converter.GetInt32 (b, 0);
- }
-
- public static string GetString (this Stream stream)
- {
- int len = stream.GetInt ();
- byte [] b = new byte [len];
- if (stream.Read (b, 0, len) != len)
- throw new IOException ("End reached");
- return Encoding.UTF8.GetString (b);
- }
-
- public static void WriteInt (this Stream stream, int n)
- {
- byte [] bytes = converter.GetBytes (n);
- stream.Write (bytes, 0, bytes.Length);
- }
-
- public static void WriteString (this Stream stream, string s)
- {
- stream.WriteInt (s.Length);
- byte [] bytes = Encoding.UTF8.GetBytes (s);
- stream.Write (bytes, 0, bytes.Length);
- }
- }
-
- public enum AgentStatus : byte {
- // Received partial input, complete
- PARTIAL_INPUT = 1,
-
- // The result was set, expect the string with the result
- RESULT_SET = 2,
-
- // No result was set, complete
- RESULT_NOT_SET = 3,
-
- // Errors and warnings string follows
- ERROR = 4,
- }
-
- //
// This is the agent loaded into the target process when using --attach.
//
class CSharpAgent