Null constant cannot be used for ref/out variables
[mono.git] / mcs / tools / csharp / repl.cs
index 644a5ada16130ec356b43af3bdf5fcede9863b52..5137fcb4c4ad768a9b2ea9c3c8b468a0eb432df0 100644 (file)
@@ -25,19 +25,83 @@ using System.Reflection.Emit;
 using System.Threading;
 using System.Net;
 using System.Net.Sockets;
-using Mono.CSharp;
+using System.Collections.Generic;
 
-using Mono.Attach;
+using Mono.CSharp;
 
 namespace Mono {
 
-       public static class CSharpShell {
-               static bool isatty = true;
+       public class Driver {
                
-               static Mono.Terminal.LineEditor editor;
-               static bool dumb;
+               static int Main (string [] args)
+               {
+#if !ON_DOTNET
+                       if (args.Length > 0 && args [0] == "--attach") {
+                               new ClientCSharpShell (Int32.Parse (args [1])).Run (null);
+                               return 0;
+                       }
 
-               static void ConsoleInterrupt (object sender, ConsoleCancelEventArgs a)
+                       if (args.Length > 0 && args [0].StartsWith ("--agent:")) {
+                               new CSharpAgent (args [0]);
+                               return 0;
+                       }
+#endif
+                       return Startup(args);
+               }
+
+               static int Startup (string[] args)
+               {
+                       string[] startup_files;
+                       try {
+                               startup_files = Evaluator.InitAndGetStartupFiles (args);
+                               Evaluator.DescribeTypeExpressions = true;
+                               Evaluator.SetInteractiveBaseClass (typeof (InteractiveBaseShell));
+                       } catch {
+                               return 1;
+                       }
+
+                       return new CSharpShell ().Run (startup_files);
+               }
+       }
+
+       public class InteractiveBaseShell : InteractiveBase {
+               static bool tab_at_start_completes;
+               
+               static InteractiveBaseShell ()
+               {
+                       tab_at_start_completes = false;
+               }
+
+               internal static Mono.Terminal.LineEditor Editor;
+               
+               public static bool TabAtStartCompletes {
+                       get {
+                               return tab_at_start_completes;
+                       }
+
+                       set {
+                               tab_at_start_completes = value;
+                               if (Editor != null)
+                                       Editor.TabAtStartCompletes = value;
+                       }
+               }
+
+               public static new string help {
+                       get {
+                               return InteractiveBase.help +
+                                       "  TabAtStartCompletes - Whether tab will complete even on emtpy lines\n";
+                       }
+               }
+       }
+       
+       public class CSharpShell {
+               static bool isatty = true, is_unix = false;
+               string [] startup_files;
+               
+               Mono.Terminal.LineEditor editor;
+               bool dumb;
+
+               protected virtual void ConsoleInterrupt (object sender, ConsoleCancelEventArgs a)
                {
                        // Do not about our program
                        a.Cancel = true;
@@ -45,16 +109,50 @@ namespace Mono {
                        Mono.CSharp.Evaluator.Interrupt ();
                }
                
-               static void SetupConsole ()
+               void SetupConsole ()
                {
-                       string term = Environment.GetEnvironmentVariable ("TERM");
-                       dumb = term == "dumb" || term == null || isatty == false;
+                       if (is_unix){
+                               string term = Environment.GetEnvironmentVariable ("TERM");
+                               dumb = term == "dumb" || term == null || isatty == false;
+                       } else
+                               dumb = false;
                        
                        editor = new Mono.Terminal.LineEditor ("csharp", 300);
+                       InteractiveBaseShell.Editor = editor;
+
+                       editor.AutoCompleteEvent += delegate (string s, int pos){
+                               string prefix = null;
+
+                               string complete = s.Substring (0, pos);
+                               
+                               string [] completions = Evaluator.GetCompletions (complete, out prefix);
+                               
+                               return new Mono.Terminal.LineEditor.Completion (prefix, completions);
+                       };
+                       
+#if false
+                       //
+                       // This is a sample of how completions sould be implemented.
+                       //
+                       editor.AutoCompleteEvent += delegate (string s, int pos){
+
+                               // Single match: "Substring": Sub-string
+                               if (s.EndsWith ("Sub")){
+                                       return new string [] { "string" };
+                               }
+
+                               // Multiple matches: "ToString" and "ToLower"
+                               if (s.EndsWith ("T")){
+                                       return new string [] { "ToString", "ToLower" };
+                               }
+                               return null;
+                       };
+#endif
+                       
                        Console.CancelKeyPress += ConsoleInterrupt;
                }
 
-               static string GetLine (bool primary)
+               string GetLine (bool primary)
                {
                        string prompt = primary ? InteractiveBase.Prompt : InteractiveBase.ContinuationPrompt;
 
@@ -70,20 +168,31 @@ namespace Mono {
 
                delegate string ReadLiner (bool primary);
 
-               static void InitializeUsing ()
+               void InitializeUsing ()
                {
                        Evaluate ("using System; using System.Linq; using System.Collections.Generic; using System.Collections;");
                }
 
-               static void InitTerminal ()
+               void InitTerminal ()
                {
-                       isatty = UnixUtils.isatty (0) && UnixUtils.isatty (1);
+#if ON_DOTNET
+                       is_unix = false;
+                       isatty = true;
+#else
+                       int p = (int) Environment.OSVersion.Platform;
+                       is_unix = (p == 4) || (p == 128);
+
+                       if (is_unix)
+                               isatty = UnixUtils.isatty (0) && UnixUtils.isatty (1);
+                       else
+                               isatty = true;
+#endif
 
                        // Work around, since Console is not accounting for
                        // cursor position when writing to Stderr.  It also
                        // has the undesirable side effect of making
                        // errors plain, with no coloring.
-                       Report.Stderr = Console.Out;
+//                     Report.Stderr = Console.Out;
                        SetupConsole ();
 
                        if (isatty)
@@ -91,7 +200,26 @@ namespace Mono {
 
                }
 
-               static void LoadStartupFiles ()
+               void ExecuteSources (IEnumerable<string> sources, bool ignore_errors)
+               {
+                       foreach (string file in sources){
+                               try {
+                                       try {
+                                               using (System.IO.StreamReader r = System.IO.File.OpenText (file)){
+                                                       ReadEvalPrintLoopWith (p => r.ReadLine ());
+                                               }
+                                       } catch (FileNotFoundException){
+                                               Console.Error.WriteLine ("cs2001: Source file `{0}' not found", file);
+                                               return;
+                                       }
+                               } catch {
+                                       if (!ignore_errors)
+                                               throw;
+                               }
+                       }
+               }
+               
+               protected virtual void LoadStartupFiles ()
                {
                        string dir = Path.Combine (
                                Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
@@ -99,26 +227,28 @@ namespace Mono {
                        if (!Directory.Exists (dir))
                                return;
 
-                       foreach (string file in Directory.GetFiles (dir)){
+                       List<string> sources = new List<string> ();
+                       List<string> libraries = new List<string> ();
+                       
+                       foreach (string file in System.IO.Directory.GetFiles (dir)){
                                string l = file.ToLower ();
                                
-                               if (l.EndsWith (".cs")){
-                                       try {
-                                               using (StreamReader r = File.OpenText (file)){
-                                                       ReadEvalPrintLoopWith (p => r.ReadLine ());
-                                               }
-                                       } catch {
-                                       }
-                               } else if (l.EndsWith (".dll")){
-                                       Evaluator.LoadAssembly (file);
-                               }
+                               if (l.EndsWith (".cs"))
+                                       sources.Add (file);
+                               else if (l.EndsWith (".dll"))
+                                       libraries.Add (file);
                        }
+
+                       foreach (string file in libraries)
+                               Evaluator.LoadAssembly (file);
+
+                       ExecuteSources (sources, true);
                }
 
-               static void ReadEvalPrintLoopWith (ReadLiner readline)
+               void ReadEvalPrintLoopWith (ReadLiner readline)
                {
                        string expr = null;
-                       while (true){
+                       while (!InteractiveBase.QuitRequested){
                                string input = readline (expr == null);
                                if (input == null)
                                        return;
@@ -132,19 +262,27 @@ namespace Mono {
                        } 
                }
 
-               static public int ReadEvalPrintLoop ()
+               public int ReadEvalPrintLoop ()
                {
-                       InitTerminal ();
+                       if (startup_files != null && startup_files.Length == 0)
+                               InitTerminal ();
 
                        InitializeUsing ();
 
                        LoadStartupFiles ();
-                       ReadEvalPrintLoopWith (GetLine);
+
+                       //
+                       // Interactive or startup files provided?
+                       //
+                       if (startup_files.Length != 0)
+                               ExecuteSources (startup_files, false);
+                       else
+                               ReadEvalPrintLoopWith (GetLine);
 
                        return 0;
                }
 
-               static string Evaluate (string input)
+               protected virtual string Evaluate (string input)
                {
                        bool result_set;
                        object result;
@@ -153,19 +291,20 @@ namespace Mono {
                                input = Evaluator.Evaluate (input, out result, out result_set);
 
                                if (result_set){
-                                       PrettyPrint (result);
+                                       PrettyPrint (Console.Out, result);
                                        Console.WriteLine ();
                                }
                        } catch (Exception e){
                                Console.WriteLine (e);
+                               return null;
                        }
                        
                        return input;
                }
 
-               static void p (string s)
+               static void p (TextWriter output, string s)
                {
-                       Console.Write (s);
+                       output.Write (s);
                }
 
                static string EscapeString (string s)
@@ -173,324 +312,405 @@ namespace Mono {
                        return s.Replace ("\"", "\\\"");
                }
                
-               static void PrettyPrint (object result)
+               static void EscapeChar (TextWriter output, char c)
+               {
+                       if (c == '\''){
+                               output.Write ("'\\''");
+                               return;
+                       }
+                       if (c > 32){
+                               output.Write ("'{0}'", c);
+                               return;
+                       }
+                       switch (c){
+                       case '\a':
+                               output.Write ("'\\a'");
+                               break;
+
+                       case '\b':
+                               output.Write ("'\\b'");
+                               break;
+                               
+                       case '\n':
+                               output.Write ("'\\n'");
+                               break;
+                               
+                       case '\v':
+                               output.Write ("'\\v'");
+                               break;
+                               
+                       case '\r':
+                               output.Write ("'\\r'");
+                               break;
+                               
+                       case '\f':
+                               output.Write ("'\\f'");
+                               break;
+                               
+                       case '\t':
+                               output.Write ("'\\t");
+                               break;
+
+                       default:
+                               output.Write ("'\\x{0:x}", (int) c);
+                               break;
+                       }
+               }
+               
+               internal static void PrettyPrint (TextWriter output, object result)
                {
                        if (result == null){
-                               p ("null");
+                               p (output, "null");
                                return;
                        }
                        
                        if (result is Array){
                                Array a = (Array) result;
                                
-                               p ("{ ");
+                               p (output, "{ ");
                                int top = a.GetUpperBound (0);
                                for (int i = a.GetLowerBound (0); i <= top; i++){
-                                       PrettyPrint (a.GetValue (i));
+                                       PrettyPrint (output, a.GetValue (i));
                                        if (i != top)
-                                               p (", ");
+                                               p (output, ", ");
                                }
-                               p (" }");
+                               p (output, " }");
                        } else if (result is bool){
                                if ((bool) result)
-                                       p ("true");
+                                       p (output, "true");
                                else
-                                       p ("false");
+                                       p (output, "false");
                        } else if (result is string){
-                               p (String.Format ("\"{0}\"", EscapeString ((string)result)));
+                               p (output, String.Format ("\"{0}\"", EscapeString ((string)result)));
                        } else if (result is IDictionary){
                                IDictionary dict = (IDictionary) result;
                                int top = dict.Count, count = 0;
                                
-                               p ("{");
+                               p (output, "{");
                                foreach (DictionaryEntry entry in dict){
                                        count++;
-                                       p ("{ ");
-                                       PrettyPrint (entry.Key);
-                                       p (", ");
-                                       PrettyPrint (entry.Value);
+                                       p (output, "{ ");
+                                       PrettyPrint (output, entry.Key);
+                                       p (output, ", ");
+                                       PrettyPrint (output, entry.Value);
                                        if (count != top)
-                                               p (" }, ");
+                                               p (output, " }, ");
                                        else
-                                               p (" }");
+                                               p (output, " }");
                                }
-                               p ("}");
+                               p (output, "}");
                        } else if (result is IEnumerable) {
                                int i = 0;
-                               p ("{ ");
+                               p (output, "{ ");
                                foreach (object item in (IEnumerable) result) {
                                        if (i++ != 0)
-                                               p (", ");
+                                               p (output, ", ");
 
-                                       PrettyPrint (item);
+                                       PrettyPrint (output, item);
                                }
-                               p (" }");
+                               p (output, " }");
+                       } else if (result is char) {
+                               EscapeChar (output, (char) result);
                        } else {
-                               p (result.ToString ());
+                               p (output, result.ToString ());
                        }
                }
 
-               static int Main (string [] args)
+               public CSharpShell ()
                {
-                       if (args.Length > 0 && args [0] == "--attach") {
-                               new AttachedCSharpShell (Int32.Parse (args [1]));
-                               return 0;
-                       } else if (args.Length > 0 && args [0].StartsWith ("--agent")) {
-                               new CSharpAgent (args [0]);
-                               return 0;
-                       }
+               }
 
-                       try {
-                               Evaluator.Init (args);
-                       } catch {
-                               return 1;
-                       }
-                       
+               public virtual int Run (string [] startup_files)
+               {
+                       this.startup_files = startup_files;
                        return ReadEvalPrintLoop ();
                }
+               
        }
-}
 
-/*
- * A shell connected to a CSharpAgent running in a remote process.
- * FIXME:
- * - using NOT.EXISTS works, but leads to an error later when mcs tries to search
- *   that namespace.
- * - it would be nice to provide some kind of autocompletion even in remote mode.
- * - maybe add 'class_name' and 'method_name' arguments to LoadAgent.
- */
-class AttachedCSharpShell {
-
-       public AttachedCSharpShell (int pid) {
-               /* Create a server socket we listen on whose address is passed to the agent */
-               TcpListener listener = new TcpListener (new IPEndPoint (IPAddress.Loopback, 0));
-               listener.Start ();
-
-               string agent_assembly = typeof (AttachedCSharpShell).Assembly.Location;
-               string agent_arg = "--agent:" + ((IPEndPoint)listener.Server.LocalEndPoint).Port;
-
-               VirtualMachine vm = new VirtualMachine (pid);
-               vm.Attach (agent_assembly, agent_arg);
-
-               /* Wait for the client to connect */
-               TcpClient client = listener.AcceptTcpClient ();
-               NetworkStream s = client.GetStream ();
-               StreamReader sr = new StreamReader (s);
-               StreamWriter sw = new StreamWriter (s);
-
-               Console.WriteLine ("Connected.");
-
-               InitTerminal ();
-
-               sw.WriteLine ("using System; using System.Linq; using System.Collections.Generic; using System.Collections;");
-               sw.Flush ();
-               /* Read result */
-               while (true) {
-                       string line = sr.ReadLine ();
-                       if (line == "<END>")
-                               break;
+#if !ON_DOTNET
+       //
+       // A shell connected to a CSharpAgent running in a remote process.
+       //  - maybe add 'class_name' and 'method_name' arguments to LoadAgent.
+       //  - Support Gtk and Winforms main loops if detected, this should
+       //    probably be done as a separate agent in a separate place.
+       //
+       class ClientCSharpShell : CSharpShell {
+               NetworkStream ns, interrupt_stream;
+               
+               public ClientCSharpShell (int pid)
+               {
+                       // Create a server socket we listen on whose address is passed to the agent
+                       TcpListener listener = new TcpListener (new IPEndPoint (IPAddress.Loopback, 0));
+                       listener.Start ();
+                       TcpListener interrupt_listener = new TcpListener (new IPEndPoint (IPAddress.Loopback, 0));
+                       interrupt_listener.Start ();
+       
+                       string agent_assembly = typeof (ClientCSharpShell).Assembly.Location;
+                       string agent_arg = String.Format ("--agent:{0}:{1}" ,
+                                                         ((IPEndPoint)listener.Server.LocalEndPoint).Port,
+                                                         ((IPEndPoint)interrupt_listener.Server.LocalEndPoint).Port);
+       
+                       var vm = new Attach.VirtualMachine (pid);
+                       vm.Attach (agent_assembly, agent_arg);
+       
+                       /* Wait for the client to connect */
+                       TcpClient client = listener.AcceptTcpClient ();
+                       ns = client.GetStream ();
+                       TcpClient interrupt_client = interrupt_listener.AcceptTcpClient ();
+                       interrupt_stream = interrupt_client.GetStream ();
+       
+                       Console.WriteLine ("Connected.");
                }
-
-               //LoadStartupFiles ();
-
-               string expr = "";
-               bool eof = false;
-               while (!eof) {
-                       string input = GetLine (expr == "");
-                       if (input == null)
-                               break;
-
-                       if (input == "")
-                               continue;
-
-                       sw.WriteLine (input);
-                       sw.Flush ();
-
-                       /* Read the (possible) error messages */
-                       while (true) {
-                               string line = sr.ReadLine ();
-                               if (line == null) {
-                                       eof = true;
-                                       break;
-                               }
-                               if (line == "<RESULT>")
-                                       break;
-                               else
-                                       // FIXME: Colorize
-                                       Console.WriteLine (line);
-                       }
-                       /* Read the result */
-                       while (true) {
-                               string line = sr.ReadLine ();
-                               if (line == null) {
-                                       eof = true;
-                                       break;
-                               }
-                               if (line == "<INPUT>")
-                                       break;
-                               else
-                                       Console.WriteLine (line);
-                       }
-                       /* Read the (possible) incomplete input */
-                       expr = "";
+       
+               //
+               // A remote version of Evaluate
+               //
+               protected override string Evaluate (string input)
+               {
+                       ns.WriteString (input);
                        while (true) {
-                               string line = sr.ReadLine ();
-                               if (line == null) {
-                                       eof = 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;
                                }
-                               if (line == "<END>")
-                                       break;
-                               else
-                                       expr += line;
                        }
                }
+               
+               public override int Run (string [] startup_files)
+               {
+                       // The difference is that we do not call Evaluator.Init, that is done on the target
+                       return ReadEvalPrintLoop ();
+               }
+       
+               protected override void ConsoleInterrupt (object sender, ConsoleCancelEventArgs a)
+               {
+                       // Do not about our program
+                       a.Cancel = true;
+       
+                       interrupt_stream.WriteByte (0);
+                       int c = interrupt_stream.ReadByte ();
+                       if (c != -1)
+                               Console.WriteLine ("Execution interrupted");
+               }
+                       
        }
 
-       static bool isatty = true;
+       //
+       // Stream helper extension methods
+       //
+       public static class StreamHelper {
+               static DataConverter converter = DataConverter.LittleEndian;
                
-       static Mono.Terminal.LineEditor editor;
-       static bool dumb;
-
-       static void ConsoleInterrupt (object sender, ConsoleCancelEventArgs a)
-       {
-               // Do not about our program
-               a.Cancel = true;
-
-               Mono.CSharp.Evaluator.Interrupt ();
-    }
+               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);
+               }
                
-       static void SetupConsole ()
-       {
-               string term = Environment.GetEnvironmentVariable ("TERM");
-               dumb = term == "dumb" || term == null || isatty == false;
-                       
-               editor = new Mono.Terminal.LineEditor ("csharp", 300);
-               Console.CancelKeyPress += ConsoleInterrupt;
-    }
-
-       static string GetLine (bool primary)
-       {
-               string prompt = primary ? InteractiveBase.Prompt : InteractiveBase.ContinuationPrompt;
-
-               if (dumb){
-                       if (isatty)
-                               Console.Write (prompt);
-
-                       return Console.ReadLine ();
-               } else {
-                       return editor.Edit (prompt, "");
+               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);
                }
-    }
-
-       static void InitTerminal ()
-       {
-               isatty = UnixUtils.isatty (0) && UnixUtils.isatty (1);
-
-               SetupConsole ();
-
-               if (isatty)
-                       Console.WriteLine ("Mono C# Shell, type \"help;\" for help\n\nEnter statements below.");
-    }
-}
-
-namespace Mono.Management
-{
-       interface IVirtualMachine {
-               void LoadAgent (string filename, string args);
-       }
-}
-
-/*
- * This is the agent loaded into the target process when using --attach.
- */
-class CSharpAgent
-{
-       public CSharpAgent (String arg) {
-               new Thread (new ParameterizedThreadStart (Run)).Start (arg);
-       }
-
-       public void Run (object o) {
-               string arg = (string)o;
-               int port = Int32.Parse (arg.Substring (arg.IndexOf (":") + 1));
-
-               Console.WriteLine ("csharp-agent: started, connecting to localhost:" + port);
-
-               TcpClient client = new TcpClient ("127.0.0.1", port);
-               Console.WriteLine ("csharp-agent: connected.");
-
-               NetworkStream s = client.GetStream ();
-
-               try {
-                       Evaluator.Init (new string [0]);
-               } catch {
-                       return;
+       
+               public static void WriteInt (this Stream stream, int n)
+               {
+                       byte [] bytes = converter.GetBytes (n);
+                       stream.Write (bytes, 0, bytes.Length);
                }
-
-               try {
-                       // Add all assemblies loaded later
-                       AppDomain.CurrentDomain.AssemblyLoad += AssemblyLoaded;
-
-                       // Add all currently loaded assemblies
-                       foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies ())
-                               Evaluator.ReferenceAssembly (a);
-
-                       RunRepl (s);
-               } finally {
-                       AppDomain.CurrentDomain.AssemblyLoad -= AssemblyLoaded;
-                       client.Close ();
-                       Console.WriteLine ("csharp-agent: disconnected.");                      
+       
+               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);
                }
        }
-
-       static void AssemblyLoaded (object sender, AssemblyLoadEventArgs e) {
-               Evaluator.ReferenceAssembly (e.LoadedAssembly);
+       
+       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
+       {
+               NetworkStream interrupt_stream;
+               
+               public CSharpAgent (String arg)
+               {
+                       new Thread (new ParameterizedThreadStart (Run)).Start (arg);
+               }
 
-       public void RunRepl (NetworkStream s) {
-               StreamReader r = new StreamReader (s);
-               StreamWriter w = new StreamWriter (s);
-               string input = null;
-
-               Report.Stderr = w;
+               public void InterruptListener ()
+               {
+                       while (true){
+                               int b = interrupt_stream.ReadByte();
+                               if (b == -1)
+                                       return;
+                               Evaluator.Interrupt ();
+                               interrupt_stream.WriteByte (0);
+                       }
+               }
+               
+               public void Run (object o)
+               {
+                       string arg = (string)o;
+                       string ports = arg.Substring (8);
+                       int sp = ports.IndexOf (':');
+                       int port = Int32.Parse (ports.Substring (0, sp));
+                       int interrupt_port = Int32.Parse (ports.Substring (sp+1));
+       
+                       Console.WriteLine ("csharp-agent: started, connecting to localhost:" + port);
+       
+                       TcpClient client = new TcpClient ("127.0.0.1", port);
+                       TcpClient interrupt_client = new TcpClient ("127.0.0.1", interrupt_port);
+                       Console.WriteLine ("csharp-agent: connected.");
+       
+                       NetworkStream s = client.GetStream ();
+                       interrupt_stream = interrupt_client.GetStream ();
+                       new Thread (InterruptListener).Start ();
 
-               while (true) {
                        try {
-                               string line = r.ReadLine ();
-
-                               bool result_set;
-                               object result;
-
-                               if (input == null)
-                                       input = line;
-                               else
-                                       input = input + "\n" + line;
-
-                               // This will print any error messages to w
-                               input = Evaluator.Evaluate (input, out result, out result_set);
-
-                               // FIXME: Emit XML
-
-                               // This separates the result from the possible error messages
-                               w.WriteLine ("<RESULT>");
-                               if (result_set) {
-                                       if (result == null)
-                                               w.Write ("null");
+                               Evaluator.Init (new string [0]);
+                       } catch {
+                               // TODO: send a result back.
+                               Console.WriteLine ("csharp-agent: initialization failed");
+                               return;
+                       }
+       
+                       try {
+                               // Add all assemblies loaded later
+                               AppDomain.CurrentDomain.AssemblyLoad += AssemblyLoaded;
+       
+                               // Add all currently loaded assemblies
+                               foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies ())
+                                       Evaluator.ReferenceAssembly (a);
+       
+                               RunRepl (s);
+                       } finally {
+                               AppDomain.CurrentDomain.AssemblyLoad -= AssemblyLoaded;
+                               client.Close ();
+                               interrupt_client.Close ();
+                               Console.WriteLine ("csharp-agent: disconnected.");                      
+                       }
+               }
+       
+               static void AssemblyLoaded (object sender, AssemblyLoadEventArgs e)
+               {
+                       Evaluator.ReferenceAssembly (e.LoadedAssembly);
+               }
+       
+               public void RunRepl (NetworkStream s)
+               {
+                       string input = null;
+
+                       while (!InteractiveBase.QuitRequested) {
+                               try {
+                                       string error_string;
+                                       StringWriter error_output = new StringWriter ();
+//                                     Report.Stderr = error_output;
+                                       
+                                       string line = s.GetString ();
+       
+                                       bool result_set;
+                                       object result;
+       
+                                       if (input == null)
+                                               input = line;
                                        else
-                                               w.Write (result.ToString ());
-                                       w.WriteLine ();
+                                               input = input + "\n" + line;
+       
+                                       try {
+                                               input = Evaluator.Evaluate (input, out result, out result_set);
+                                       } catch (Exception e) {
+                                               s.WriteByte ((byte) AgentStatus.ERROR);
+                                               s.WriteString (e.ToString ());
+                                               s.WriteByte ((byte) AgentStatus.RESULT_NOT_SET);
+                                               continue;
+                                       }
+                                       
+                                       if (input != null){
+                                               s.WriteByte ((byte) AgentStatus.PARTIAL_INPUT);
+                                               continue;
+                                       }
+       
+                                       // Send warnings and errors back
+                                       error_string = error_output.ToString ();
+                                       if (error_string.Length != 0){
+                                               s.WriteByte ((byte) AgentStatus.ERROR);
+                                               s.WriteString (error_output.ToString ());
+                                       }
+       
+                                       if (result_set){
+                                               s.WriteByte ((byte) AgentStatus.RESULT_SET);
+                                               StringWriter sr = new StringWriter ();
+                                               CSharpShell.PrettyPrint (sr, result);
+                                               s.WriteString (sr.ToString ());
+                                       } else {
+                                               s.WriteByte ((byte) AgentStatus.RESULT_NOT_SET);
+                                       }
+                               } catch (IOException) {
+                                       break;
+                               } catch (Exception e){
+                                       Console.WriteLine (e);
                                }
-                               // FIXME: This might occur in the output as well.
-                               w.WriteLine ("<INPUT>");
-                               /* The rest of the input */
-                               w.WriteLine (input);
-                               w.WriteLine ("<END>");
-                               w.Flush ();
-                       } catch (IOException) {
-                               break;
-                       } catch (Exception e){
-                               Console.WriteLine (e);
                        }
                }
        }
-}
\ No newline at end of file
+
+       public class UnixUtils {
+               [System.Runtime.InteropServices.DllImport ("libc", EntryPoint="isatty")]
+               extern static int _isatty (int fd);
+                       
+               public static bool isatty (int fd)
+               {
+                       try {
+                               return _isatty (fd) == 1;
+                       } catch {
+                               return false;
+                       }
+               }
+       }
+#endif
+}
+       
+namespace Mono.Management
+{
+       interface IVirtualMachine {
+               void LoadAgent (string filename, string args);
+       }
+}
+