Expose the compiler Evaluation routine as a method,
authorMiguel de Icaza <miguel@gnome.org>
Wed, 10 Sep 2008 22:43:07 +0000 (22:43 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Wed, 10 Sep 2008 22:43:07 +0000 (22:43 -0000)
move the REPL shell into a separate tool, the compiler
no longer has the shell.

2008-09-10  Miguel de Icaza  <miguel@novell.com>

* driver.cs: Drop --shell argument, the compiler is no longer a
REPL.

* eval.cs: Move most of the code that deals with evaluation into
this file and document the public API from repl.cs

* repl.cs: Remove from here.

svn path=/trunk/mcs/; revision=112718

20 files changed:
mcs/mcs/ChangeLog
mcs/mcs/Makefile
mcs/mcs/cs-parser.jay
mcs/mcs/driver.cs
mcs/mcs/ecore.cs
mcs/mcs/eval.cs [new file with mode: 0644]
mcs/mcs/getline.cs [deleted file]
mcs/mcs/gmcs.exe.sources
mcs/mcs/mcs.exe.sources
mcs/mcs/repl.cs [deleted file]
mcs/mcs/repl.txt
mcs/mcs/smcs.exe.sources
mcs/tools/ChangeLog
mcs/tools/Makefile
mcs/tools/csharp/ChangeLog [new file with mode: 0644]
mcs/tools/csharp/Makefile [new file with mode: 0644]
mcs/tools/csharp/csharp.exe.sources [new file with mode: 0644]
mcs/tools/csharp/getline.cs [new file with mode: 0644]
mcs/tools/csharp/repl.cs [new file with mode: 0644]
mcs/tools/csharp/repl.txt [new file with mode: 0644]

index 00335983e97197f042c70ea3740c24b432eac56c..5a19e4f93249d1c708a3fcc42c7666a3b58f50d4 100644 (file)
@@ -1,3 +1,13 @@
+2008-09-10  Miguel de Icaza  <miguel@novell.com>
+
+       * driver.cs: Drop --shell argument, the compiler is no longer a
+       REPL. 
+
+       * eval.cs: Move most of the code that deals with evaluation into
+       this file and document the public API from repl.cs
+
+       * repl.cs: Remove from here.
+       
 2008-09-10  Marek Safar  <marek.safar@gmail.com>
 
        A fix for bug #424684
index 206972cbc9a2f5348121c09c82c1bb15e621a589..75241ad1855dfee9ace9cd91fdb70f516eb76cad 100644 (file)
@@ -137,13 +137,13 @@ qh:
        @ cp $(COMPILER_NAME).exe* $(topdir)/class/lib/$(PROFILE)/
 
 q: cs-parser.cs qh
-       echo 'System.Console.WriteLine ("Hello");' | mono --debug gmcs.exe -v --shell
-       echo -e 'using System;\nConsole.WriteLine ("hello");' | mono --debug gmcs.exe -v --shell
-       echo -e '"foo" == "bar";' | mono --debug gmcs.exe -v --shell
-       echo -e 'var a = 1;\na + 2;' | mono --debug gmcs.exe -v --shell
-       echo -e 'int j;\nj = 1;' | mono --debug gmcs.exe -v --shell
-       echo -e 'var a = new int[]{1,2,3};\nfrom x in a select x;' | mono --debug gmcs.exe -v --shell
-       echo -e 'var a = from f in System.IO.Directory.GetFiles ("/tmp") where f == "passwd" select f;' | mono gmcs.exe --shell
+       echo 'System.Console.WriteLine ("Hello");' | csharp
+       echo -e 'using System;\nConsole.WriteLine ("hello");' | csharp
+       echo -e '"foo" == "bar";' | csharp
+       echo -e 'var a = 1;\na + 2;' | csharp
+       echo -e 'int j;\nj = 1;' | csharp
+       echo -e 'var a = new int[]{1,2,3};\nfrom x in a select x;' | csharp
+       echo -e 'var a = from f in System.IO.Directory.GetFiles ("/tmp") where f == "passwd" select f;' | csharp
 
 # read-eval-print-loop test target, for quickly hackign
 repl: 
index 5de8b3b84c470c5bd8d4a27461e799125b47a05d..129c1e639503bf8de7b40fdd4bb47f79a4c5d2e2 100644 (file)
@@ -5417,13 +5417,13 @@ interactive_parsing
        : EVAL_STATEMENT_PARSER EOF 
        | EVAL_USING_DECLARATIONS_UNIT_PARSER using_directives 
        | EVAL_STATEMENT_PARSER { 
-               InteractiveShell.LoadAliases (current_namespace);
+               CSharpEvaluator.LoadAliases (current_namespace);
 
                push_current_class (new Class (current_namespace, current_class, new MemberName ("Class" + class_count++),
                        Modifiers.PUBLIC, null), null);
 
                ArrayList baseclass_list = new ArrayList ();
-               baseclass_list.Add (new TypeExpression (typeof (InteractiveBase), lexer.Location));
+               baseclass_list.Add (new TypeExpression (CSharpEvaluator.InteractiveBaseClass, lexer.Location));
                current_container.AddBasesForPart (current_class, baseclass_list);
 
                // (ref object retval)
@@ -5457,7 +5457,7 @@ interactive_parsing
                current_local_parameters = null;
          } 
        | EVAL_COMPILATION_UNIT_PARSER {
-               InteractiveShell.LoadAliases (current_namespace);
+               CSharpEvaluator.LoadAliases (current_namespace);
          }
          interactive_compilation_unit
        ;
@@ -5645,7 +5645,7 @@ Block declare_local_variables (Expression type, ArrayList variable_declarators,
                                        current_container.AddField (f);
 
                                        // Register the field to be visible later as a global variable
-                                       InteractiveShell.QueueField (f);
+                                       CSharpEvaluator.QueueField (f);
                                }
                        }
 
index 2479ebe7c09a2592398539ccef242597fb38d81a..fc51eb88ea1c2d977d65a6edd37227eefe2d2c12 100644 (file)
@@ -71,10 +71,6 @@ namespace Mono.CSharp
                // 
                bool load_default_config = true;
 
-               //
-               // Whether this is going to be an interactive C-Sharp session 
-               public bool Shell = false;
-
                //
                // A list of resource files
                //
@@ -109,10 +105,10 @@ namespace Mono.CSharp
                        encoding = Encoding.Default;
                }
 
-               public static Driver Create (string [] args)
+               public static Driver Create (string [] args, bool require_files)
                {
                        Driver d = new Driver ();
-                       if (!d.ParseArguments (args))
+                       if (!d.ParseArguments (args, require_files))
                                return null;
 
                        return d;
@@ -296,13 +292,10 @@ namespace Mono.CSharp
 
                        Location.InEmacs = Environment.GetEnvironmentVariable ("EMACS") == "t";
 
-                       Driver d = Driver.Create (args);
+                       Driver d = Driver.Create (args, true);
                        if (d == null)
                                return 1;
 
-                       if (d.Shell)
-                               return d.StartInteractiveShell ();
-
                        else if (d.Compile () && Report.Errors == 0) {
                                if (Report.Warnings > 0) {
                                        Console.WriteLine ("Compilation succeeded - {0} warning(s)", Report.Warnings);
@@ -582,7 +575,7 @@ namespace Mono.CSharp
                        Location.AddFile (f);
                }
 
-               bool ParseArguments (string[] args)
+               bool ParseArguments (string[] args, bool require_files)
                {
                        references = new ArrayList ();
                        external_aliases = new Hashtable ();
@@ -658,10 +651,7 @@ namespace Mono.CSharp
                                ProcessSourceFiles (arg, false);
                        }
 
-                       //
-                       // For now, very lax error checking
-                       //
-                       if (Shell)
+                       if (require_files == false)
                                return true;
                                        
                        //
@@ -1077,10 +1067,6 @@ namespace Mono.CSharp
                                Report.Warning (-29, 1, "Compatibility: Use -noconfig option instead of --noconfig");
                                load_default_config = false;
                                return true;
-
-                       case "--shell":
-                               Shell = true;
-                               return true;
                        }
 
                        return false;
@@ -1597,12 +1583,6 @@ namespace Mono.CSharp
                        return true;
                }
 
-               int StartInteractiveShell ()
-               {
-                       ProcessDefaultConfig ();
-                       return InteractiveShell.ReadEvalPrintLoop ();
-               }
-               
                //
                // Main compilation method
                //
@@ -1969,7 +1949,7 @@ namespace Mono.CSharp
                {
                        Report.Stderr = error;
                        try {
-                               Driver d = Driver.Create (args);
+                               Driver d = Driver.Create (args, true);
                                if (d == null)
                                        return false;
 
index 68edb9539e6c9e9cab57b1d8cdf852171dd2b909..7bb8edb36b92c45e1387d13ffb2765e961c55025 100644 (file)
@@ -794,7 +794,6 @@ namespace Mono.CSharp {
                        Expression e;
 
                        int errors = Report.Errors;
-
                        e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
 
                        if (e != null || errors != Report.Errors)
@@ -2680,7 +2679,7 @@ namespace Mono.CSharp {
                                }
 
                                if (RootContext.EvalMode){
-                                       FieldInfo fi = InteractiveShell.LookupField (Name);
+                                       FieldInfo fi = CSharpEvaluator.LookupField (Name);
                                        if (fi != null)
                                                return new FieldExpr (fi, loc);
                                }
diff --git a/mcs/mcs/eval.cs b/mcs/mcs/eval.cs
new file mode 100644 (file)
index 0000000..c429712
--- /dev/null
@@ -0,0 +1,877 @@
+//
+// eval.cs: Evaluation and Hosting API for the C# compiler
+//
+// Authors:
+//   Miguel de Icaza (miguel@gnome.org)
+//
+// Dual licensed under the terms of the MIT X11 or GNU GPL
+//
+// Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
+// Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
+//
+using System;
+using System.Threading;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.IO;
+using System.Globalization;
+using System.Text;
+
+namespace Mono.CSharp {
+
+       /// <summary>
+       ///   CSharpEvaluator: provides an API to evaluate C# statements and
+       ///   expressions dynamically.
+       /// </summary>
+       /// <remarks>
+       ///   This class exposes static methods to evaluate expressions in the
+       ///   current program.
+       ///
+       ///   To initialize the evaluator with a number of compiler
+       ///   options call the Init(string[]args) method with a set of
+       ///   command line options that the compiler recognizes.
+       ///
+       ///   To interrupt execution of a statement, you can invoke the
+       ///   CSharpEvaluator.Interrupt method.
+       /// </remarks>
+       public class CSharpEvaluator {
+               static CSharpEvaluator evaluator;
+               static string current_debug_name;
+               static int count;
+               static Thread invoke_thread;
+               
+               static public ArrayList using_alias_list = new ArrayList ();
+               static public ArrayList using_list = new ArrayList ();
+               static public Hashtable fields = new Hashtable ();
+
+               static Type   interactive_base_class = typeof (InteractiveBase);
+               static Driver driver;
+               static bool inited;
+
+               /// <summary>
+               ///   Optioanl initialization for the CSharpEvaluator.
+               /// </summary>
+               /// <remarks>
+               ///  Initializes the CSharpEvaluator with the command line options
+               ///  that would be processed by the command line compiler.  Only
+               ///  the first call to Init will work, any future invocations are
+               ///  ignored.
+               ///
+               ///  You can safely avoid calling this method if your application
+               ///  does not need any of the features exposed by the command line
+               ///  interface.
+               /// </remarks>
+               public static void Init (string [] args)
+               {
+                       if (inited)
+                               return;
+
+                       RootContext.Version = LanguageVersion.Default;
+                       Driver driver = Driver.Create (args, false);
+                       if (driver == null)
+                               throw new Exception ("Failed to create compiler driver with the given arguments");
+
+                       driver.ProcessDefaultConfig ();
+                       CompilerCallableEntryPoint.Reset ();
+                       Driver.LoadReferences ();
+                       RootContext.EvalMode = true;
+                       inited = true;
+               }
+
+               static void Init ()
+               {
+                       Init (new string [0]);
+               }
+               
+               static void Reset ()
+               {
+                       CompilerCallableEntryPoint.PartialReset ();
+
+                       //
+                       // PartialReset should not reset the core types, this is very redundant.
+                       //
+                       if (!TypeManager.InitCoreTypes ())
+                               throw new Exception ("Failed to InitCoreTypes");
+                       TypeManager.InitOptionalCoreTypes ();
+                       
+                       Location.AddFile ("<interactive>");
+                       Location.Initialize ();
+
+                       current_debug_name = "interactive" + (count++) + ".dll";
+                       if (Environment.GetEnvironmentVariable ("SAVE") != null){
+                               CodeGen.Init (current_debug_name, current_debug_name, false);
+                       } else
+                               CodeGen.InitDynamic (current_debug_name);
+               }
+
+               /// <summary>
+               ///   The base class for the classes that host the user generated code
+               /// </summary>
+               /// <remarks>
+               ///
+               ///   This is the base class that will host the code
+               ///   executed by the CSharpEvaluator.  By default
+               ///   this is the Mono.CSharp.InteractiveBase class
+               ///   which is useful for interactive use.
+               ///
+               ///   By changing this property you can control the
+               ///   base class and the static members that are
+               ///   available to your evaluated code.
+               /// </remarks>
+               static public Type InteractiveBaseClass {
+                       get {
+                               return interactive_base_class;
+                       }
+
+                       set {
+                               if (value == null)
+                                       throw new ArgumentNullException ();
+                               
+                               interactive_base_class = value;
+                       }
+               }
+
+               /// <summary>
+               ///   Interrupts the evaluation of an expression.
+               /// </summary>
+               /// <remarks>
+               ///   Use this method to interrupt long-running invocations.
+               /// </remarks>
+               public static void Interrupt ()
+               {
+                       if (!inited || !invoking)
+                               return;
+                       
+                       if (invoke_thread != null)
+                               invoke_thread.Abort ();
+               }
+
+               //
+               // Todo: Should we handle errors, or expect the calling code to setup
+               // the recording themselves?
+               //
+
+               /// <summary>
+               ///   Evaluates and expression or statement and returns any result values.
+               /// </summary>
+               /// <remarks>
+               ///   Evaluates the input string as a C# expression or
+               ///   statement.  If the input string is an expression
+               ///   the result will be stored in the result variable
+               ///   and the result_set variable will be set to true.
+               ///
+               ///   It is necessary to use the result/result_set
+               ///   pair to identify when a result was set (for
+               ///   example, execution of user-provided input can be
+               ///   an expression, a statement or others, and
+               ///   result_set would only be set if the input was an
+               ///   expression.
+               ///
+               ///   If the return value of this function is null,
+               ///   this indicates that the parsing was complete.
+               ///   If the return value is a string, it indicates
+               ///   that the input is partial and that the user
+               ///   should provide an updated string.
+               /// </remarks>
+               public static string Evaluate (string input, out object result, out bool result_set)
+               {
+                       result_set = false;
+                       result = null;
+                       
+                       if (input == null || input.Length == 0)
+                               return null;
+
+                       if (!inited)
+                               Init ();
+                       
+                       bool partial_input;
+                       CSharpParser parser = ParseString (true, input, out partial_input);
+                       if (parser == null){
+                               if (partial_input)
+                                       return input;
+                               
+                               ParseString (false, input, out partial_input);
+                               return null;
+                       }
+
+                       object parser_result = parser.InteractiveResult;
+                       
+                       if (!(parser_result is Class))
+                               parser.CurrentNamespace.Extract (using_alias_list, using_list);
+
+                       result = ExecuteBlock (parser_result as Class, parser.undo);
+                       //
+                       // We use a reference to a compiler type, in this case
+                       // Driver as a flag to indicate that this was a statement
+                       //
+                       if (result != typeof (NoValueSet))
+                               result_set = true;
+
+                       return null;
+               }
+
+               /// <summary>
+               ///   Executes the given expression or statement.
+               /// </summary>
+               /// <remarks>
+               ///    Executes the provided statement, returns true
+               ///    on success, false on parsing errors.  Exceptions
+               ///    might be thrown by the called code.
+               /// </remarks>
+               public static bool Run (string statement)
+               {
+                       if (!inited)
+                               Init ();
+                       
+                       object result;
+                       bool result_set;
+                       
+                       bool ok = Evaluate (statement, out result, out result_set) == null;
+                       
+                       return ok;
+               }
+
+               /// <summary>
+               ///   Evaluates and expression or statement and returns the result.
+               /// </summary>
+               /// <remarks>
+               ///   Evaluates the input string as a C# expression or
+               ///   statement and returns the value.   
+               ///
+               ///   This method will throw an exception if there is a syntax error,
+               ///   of if the provided input is not an expression but a statement.
+               /// </remarks>
+               public static object Evaluate (string input)
+               {
+                       object result;
+                       bool result_set;
+                       
+                       string r = Evaluate (input, out result, out result_set);
+
+                       if (r != null || result_set == false)
+                               throw new ArgumentException ("Syntax error on input");
+
+                       return result;
+               }
+               
+               enum InputKind {
+                       EOF,
+                       StatementOrExpression,
+                       CompilationUnit,
+                       Error
+               }
+
+               //
+               // Deambiguates the input string to determine if we
+               // want to process a statement or if we want to
+               // process a compilation unit.
+               //
+               // This is done using a top-down predictive parser,
+               // since the yacc/jay parser can not deambiguage this
+               // without more than one lookahead token.   There are very
+               // few ambiguities.
+               //
+               static InputKind ToplevelOrStatement (SeekableStreamReader seekable)
+               {
+                       Tokenizer tokenizer = new Tokenizer (seekable, Location.SourceFiles [0]);
+                       
+                       int t = tokenizer.token ();
+                       switch (t){
+                       case Token.EOF:
+                               return InputKind.EOF;
+                               
+                       // These are toplevels
+                       case Token.EXTERN:
+                       case Token.OPEN_BRACKET:
+                       case Token.ABSTRACT:
+                       case Token.CLASS:
+                       case Token.ENUM:
+                       case Token.INTERFACE:
+                       case Token.INTERNAL:
+                       case Token.NAMESPACE:
+                       case Token.PRIVATE:
+                       case Token.PROTECTED:
+                       case Token.PUBLIC:
+                       case Token.SEALED:
+                       case Token.STATIC:
+                       case Token.STRUCT:
+                               return InputKind.CompilationUnit;
+                               
+                       // Definitely expression
+                       case Token.FIXED:
+                       case Token.BOOL:
+                       case Token.BYTE:
+                       case Token.CHAR:
+                       case Token.DECIMAL:
+                       case Token.DOUBLE:
+                       case Token.FLOAT:
+                       case Token.INT:
+                       case Token.LONG:
+                       case Token.NEW:
+                       case Token.OBJECT:
+                       case Token.SBYTE:
+                       case Token.SHORT:
+                       case Token.STRING:
+                       case Token.UINT:
+                       case Token.ULONG:
+                               return InputKind.StatementOrExpression;
+
+                       // These need deambiguation help
+                       case Token.USING:
+                               t = tokenizer.token ();
+                               if (t == Token.EOF)
+                                       return InputKind.EOF;
+
+                               if (t == Token.IDENTIFIER)
+                                       return InputKind.CompilationUnit;
+                               return InputKind.StatementOrExpression;
+
+
+                       // Distinguish between:
+                       //    delegate opt_anonymous_method_signature block
+                       //    delegate type 
+                       case Token.DELEGATE:
+                               t = tokenizer.token ();
+                               if (t == Token.EOF)
+                                       return InputKind.EOF;
+                               if (t == Token.OPEN_PARENS || t == Token.OPEN_BRACE)
+                                       return InputKind.StatementOrExpression;
+                               return InputKind.CompilationUnit;
+
+                       // Distinguih between:
+                       //    unsafe block
+                       //    unsafe as modifier of a type declaration
+                       case Token.UNSAFE:
+                               t = tokenizer.token ();
+                               if (t == Token.EOF)
+                                       return InputKind.EOF;
+                               if (t == Token.OPEN_PARENS)
+                                       return InputKind.StatementOrExpression;
+                               return InputKind.CompilationUnit;
+                               
+                       // These are errors: we list explicitly what we had
+                       // from the grammar, ERROR and then everything else
+
+                       case Token.READONLY:
+                       case Token.OVERRIDE:
+                       case Token.ERROR:
+                               return InputKind.Error;
+
+                       // This catches everything else allowed by
+                       // expressions.  We could add one-by-one use cases
+                       // if needed.
+                       default:
+                               return InputKind.StatementOrExpression;
+                       }
+               }
+               
+               //
+               // Parses the string @input and returns a CSharpParser if succeeful.
+               //
+               // if @silent is set to true then no errors are
+               // reported to the user.  This is used to do various calls to the
+               // parser and check if the expression is parsable.
+               //
+               // @partial_input: if @silent is true, then it returns whether the
+               // parsed expression was partial, and more data is needed
+               //
+               static CSharpParser ParseString (bool silent, string input, out bool partial_input)
+               {
+                       partial_input = false;
+                       Reset ();
+                       queued_fields.Clear ();
+
+                       Stream s = new MemoryStream (Encoding.Default.GetBytes (input));
+                       SeekableStreamReader seekable = new SeekableStreamReader (s, Encoding.Default);
+
+                       InputKind kind = ToplevelOrStatement (seekable);
+                       if (kind == InputKind.Error){
+                               if (!silent)
+                                       Report.Error (-25, "Detection Parsing Error");
+                               partial_input = false;
+                               return null;
+                       }
+
+                       if (kind == InputKind.EOF){
+                               if (silent == false)
+                                       Console.Error.WriteLine ("Internal error: EOF condition should have been detected in a previous call with silent=true");
+                               partial_input = true;
+                               return null;
+                               
+                       }
+                       seekable.Position = 0;
+
+                       CSharpParser parser = new CSharpParser (seekable, Location.SourceFiles [0]);
+                       parser.ErrorOutput = Report.Stderr;
+
+                       if (kind == InputKind.StatementOrExpression){
+                               parser.Lexer.putback_char = Tokenizer.EvalStatementParserCharacter;
+                               RootContext.StatementMode = true;
+                       } else {
+                               //
+                               // Do not activate EvalCompilationUnitParserCharacter until
+                               // I have figured out all the limitations to invoke methods
+                               // in the generated classes.  See repl.txt
+                               //
+                               parser.Lexer.putback_char = Tokenizer.EvalUsingDeclarationsParserCharacter;
+                               //parser.Lexer.putback_char = Tokenizer.EvalCompilationUnitParserCharacter;
+                               RootContext.StatementMode = false;
+                       }
+
+                       if (silent)
+                               Report.DisableReporting ();
+                       try {
+                               parser.parse ();
+                       } finally {
+                               if (Report.Errors != 0){
+                                       if (silent && parser.UnexpectedEOF)
+                                               partial_input = true;
+
+                                       parser.undo.ExecuteUndo ();
+                                       parser = null;
+                               }
+
+                               if (silent)
+                                       Report.EnableReporting ();
+                       }
+                       return parser;
+               }
+
+               delegate void HostSignature (ref object retvalue);
+
+               //
+               // Queue all the fields that we use, as we need to then go from FieldBuilder to FieldInfo
+               // or reflection gets confused (it basically gets confused, and variables override each
+               // other).
+               //
+               static ArrayList queued_fields = new ArrayList ();
+               
+               //static ArrayList types = new ArrayList ();
+
+               static volatile bool invoking;
+               
+               static object ExecuteBlock (Class host, Undo undo)
+               {
+                       RootContext.ResolveTree ();
+                       if (Report.Errors != 0){
+                               undo.ExecuteUndo ();
+                               return typeof (NoValueSet);
+                       }
+                       
+                       RootContext.PopulateTypes ();
+                       RootContext.DefineTypes ();
+
+                       if (Report.Errors != 0){
+                               undo.ExecuteUndo ();
+                               return typeof (NoValueSet);
+                       }
+
+                       TypeBuilder tb = null;
+                       MethodBuilder mb = null;
+                               
+                       if (host != null){
+                               tb = host.TypeBuilder;
+                               mb = null;
+                               foreach (MemberCore member in host.Methods){
+                                       if (member.Name != "Host")
+                                               continue;
+                                       
+                                       MethodOrOperator method = (MethodOrOperator) member;
+                                       mb = method.MethodBuilder;
+                                       break;
+                               }
+
+                               if (mb == null)
+                                       throw new Exception ("Internal error: did not find the method builder for the generated method");
+                       }
+                       
+                       RootContext.EmitCode ();
+                       if (Report.Errors != 0)
+                               return typeof (NoValueSet);
+                       
+                       RootContext.CloseTypes ();
+
+                       if (Environment.GetEnvironmentVariable ("SAVE") != null)
+                               CodeGen.Save (current_debug_name, false);
+
+                       if (host == null)
+                               return typeof (NoValueSet);
+                       
+                       //
+                       // Unlike Mono, .NET requires that the MethodInfo is fetched, it cant
+                       // work from MethodBuilders.   Retarded, I know.
+                       //
+                       Type tt = CodeGen.Assembly.Builder.GetType (tb.Name);
+                       MethodInfo mi = tt.GetMethod (mb.Name);
+                       
+                       // Pull the FieldInfos from the type, and keep track of them
+                       foreach (Field field in queued_fields){
+                               FieldInfo fi = tt.GetField (field.Name);
+                               
+                               FieldInfo old = (FieldInfo) fields [field.Name];
+                               
+                               // If a previous value was set, nullify it, so that we do
+                               // not leak memory
+                               if (old != null){
+                                       if (old.FieldType.IsValueType){
+                                               //
+                                               // TODO: Clear fields for structs
+                                               //
+                                       } else {
+                                               try {
+                                                       old.SetValue (null, null);
+                                               } catch {
+                                               }
+                                       }
+                               }
+                               
+                               fields [field.Name] = fi;
+                       }
+                       //types.Add (tb);
+
+                       queued_fields.Clear ();
+                       
+                       HostSignature invoker = (HostSignature) System.Delegate.CreateDelegate (typeof (HostSignature), mi);
+                       object retval = typeof (NoValueSet);
+
+                       try {
+                               invoke_thread = System.Threading.Thread.CurrentThread;
+                               invoking = true;
+                               invoker (ref retval);
+                       } catch (ThreadAbortException e){
+                               Thread.ResetAbort ();
+                               Console.WriteLine ("Interrupted!\n{0}", e);
+                       } finally {
+                               invoking = false;
+                       }
+                       
+                       // d.DynamicInvoke  (new object [] { retval });
+
+                       return retval;
+               }
+
+               static internal void LoadAliases (NamespaceEntry ns)
+               {
+                       ns.Populate (using_alias_list, using_list);
+               }
+               
+               //
+               // Just a placeholder class, used as a sentinel to determine that the
+               // generated code did not set a value
+               class NoValueSet {
+               }
+
+               static internal FieldInfo LookupField (string name)
+               {
+                       FieldInfo fi =  (FieldInfo) fields [name];
+
+                       return fi;
+               }
+
+               //
+               // Puts the FieldBuilder into a queue of names that will be
+               // registered.   We can not register FieldBuilders directly
+               // we need to fetch the FieldInfo after Reflection cooks the
+               // types, or bad things happen (bad means: FieldBuilders behave
+               // incorrectly across multiple assemblies, causing assignments to
+               // invalid areas
+               //
+               // This also serves for the parser to register Field classes
+               // that should be exposed as global variables
+               //
+               static internal void QueueField (Field f)
+               {
+                       queued_fields.Add (f);
+               }
+
+               static string Quote (string s)
+               {
+                       if (s.IndexOf ('"') != -1)
+                               s = s.Replace ("\"", "\\\"");
+                       
+                       return "\"" + s + "\"";
+               }
+
+               static public string GetUsing ()
+               {
+                       StringBuilder sb = new StringBuilder ();
+                       
+                       foreach (object x in using_alias_list)
+                               sb.Append (String.Format ("using {0};\n", x));
+
+                       foreach (object x in using_list)
+                               sb.Append (String.Format ("using {0};\n", x));
+
+                       return sb.ToString ();
+               }
+
+               static public string GetVars ()
+               {
+                       StringBuilder sb = new StringBuilder ();
+                       
+                       foreach (DictionaryEntry de in fields){
+                               FieldInfo fi = LookupField ((string) de.Key);
+                               object value = null;
+                               bool error = false;
+                               
+                               try {
+                                       if (value == null)
+                                               value = "null";
+                                       value = fi.GetValue (null);
+                                       if (value is string)
+                                               value = Quote ((string)value);
+                               } catch {
+                                       error = true;
+                               }
+
+                               if (error)
+                                       sb.Append (String.Format ("{0} {1} <error reading value>", TypeManager.CSharpName(fi.FieldType), de.Key));
+                               else
+                                       sb.Append (String.Format ("{0} {1} = {2}", TypeManager.CSharpName(fi.FieldType), de.Key, value));
+                       }
+
+                       return sb.ToString ();
+               }
+
+               /// <summary>
+               ///    Loads the given assembly and exposes the API to the user.
+               /// </summary>
+               static public void LoadAssembly (string file)
+               {
+                       Driver.LoadAssembly (file, true);
+               }
+
+               /// <summary>
+               ///    Exposes the API of the given assembly to the CSharpEvaluator
+               /// </summary>
+               static public void ReferenceAssembly (Assembly a)
+               {
+                       RootNamespace.Global.AddAssemblyReference (a);
+               }
+               
+       }
+
+       /// <summary>
+       ///   The default base class for every interaction line
+       /// </summary>
+       public class InteractiveBase {
+               public static TextWriter Output = Console.Out;
+               public static TextWriter Error = Console.Error;
+               public static string Prompt             = "csharp> ";
+               public static string ContinuationPrompt = "      > ";
+
+               static public void ShowVars ()
+               {
+                       Output.Write (CSharpEvaluator.GetVars ());
+                       Output.Flush ();
+               }
+
+               static public void ShowUsing ()
+               {
+                       Output.Write (CSharpEvaluator.GetUsing ());
+                       Output.Flush ();
+               }
+
+               public delegate void Simple ();
+               
+               static public TimeSpan Time (Simple a)
+               {
+                       DateTime start = DateTime.Now;
+                       a ();
+                       return DateTime.Now - start;
+               }
+               
+#if !SMCS_SOURCE
+               static public void LoadPackage (string pkg)
+               {
+                       if (pkg == null){
+                               Error.WriteLine ("Invalid package specified");
+                               return;
+                       }
+
+                       string pkgout = Driver.GetPackageFlags (pkg, false);
+                       if (pkgout == null)
+                               return;
+
+                       string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
+                               Split (new Char [] { ' ', '\t'});
+
+                       foreach (string s in xargs){
+                               if (s.StartsWith ("-r:") || s.StartsWith ("/r:") || s.StartsWith ("/reference:")){
+                                       string lib = s.Substring (s.IndexOf (':')+1);
+
+                                       Driver.LoadAssembly (lib, true);
+                                       continue;
+                               }
+                       }
+               }
+#endif
+
+               static public void LoadAssembly (string assembly)
+               {
+                       Driver.LoadAssembly (assembly, true);
+               }
+               
+               static public string help {
+                       get {
+                               return  "Static methods:\n"+
+                                       "  LoadPackage (pkg); - Loads the given Package (like -pkg:FILE)\n" +
+                                       "  LoadAssembly (ass) - Loads the given assembly (like -r:ASS)\n" + 
+                                       "  ShowVars ();       - Shows defined local variables.\n" +
+                                       "  ShowUsing ();      - Show active using decltions.\n" +
+                                       "  Prompt             - The prompt used by the C# shell\n" +
+                                       "  ContinuationPrompt - The prompt for partial input\n" +
+                                       "  Time(() -> { })    - Times the specified code\n" +
+                                       "  quit;\n" +
+                                       "  help;\n";
+                       }
+               }
+
+               static public object quit {
+                       get {
+                               Environment.Exit (0);
+                               return null;
+                       }
+               }
+       }
+
+       //
+       // A local variable reference that will create a Field in a
+       // Class with the resolved type.  This is necessary so we can
+       // support "var" as a field type in a class declaration.
+       //
+       // We allow LocalVariableReferece to do the heavy lifting, and
+       // then we insert the field with the resolved type
+       //
+       public class LocalVariableReferenceWithClassSideEffect : LocalVariableReference {
+               TypeContainer container;
+               string name;
+               
+               public LocalVariableReferenceWithClassSideEffect (TypeContainer container, string name, Block current_block, string local_variable_id, Location loc)
+                       : base (current_block, local_variable_id, loc)
+               {
+                       this.container = container;
+                       this.name = name;
+               }
+
+               public override bool Equals (object obj)
+               {
+                       LocalVariableReferenceWithClassSideEffect lvr = obj as LocalVariableReferenceWithClassSideEffect;
+                       if (lvr == null)
+                               return false;
+
+                       if (lvr.name != name || lvr.container != container)
+                               return false;
+
+                       return base.Equals (obj);
+               }
+
+               public override int GetHashCode ()
+               {
+                       return name.GetHashCode ();
+               }
+               
+               override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+               {
+                       Expression ret = base.DoResolveLValue (ec, right_side);
+                       if (ret == null)
+                               return null;
+
+                       Field f = new Field (container, new TypeExpression (ret.Type, Location),
+                                            Modifiers.PUBLIC | Modifiers.STATIC,
+                                            name, null, Location);
+                       container.AddField (f);
+                       if (f.Define ())
+                               CSharpEvaluator.QueueField (f);
+                       
+                       return ret;
+               }
+       }
+
+       /// <summary>
+       ///    A class used to assign values if the source expression is not void
+       ///
+       ///    Used by the interactive shell to allow it to call this code to set
+       ///    the return value for an invocation.
+       /// </summary>
+       class OptionalAssign : SimpleAssign {
+               public OptionalAssign (Expression t, Expression s, Location loc)
+                       : base (t, s, loc)
+               {
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       CloneContext cc = new CloneContext ();
+                       Expression clone = source.Clone (cc);
+
+                       clone = clone.Resolve (ec);
+                       if (clone == null)
+                               return null;
+
+                       // This means its really a statement.
+                       if (clone.Type == TypeManager.void_type){
+                               source = source.Resolve (ec);
+                               target = null;
+                               type = TypeManager.void_type;
+                               eclass = ExprClass.Value;
+                               return this;
+                       }
+
+                       return base.DoResolve (ec);
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       if (target == null)
+                               source.Emit (ec);
+                       else
+                               base.Emit (ec);
+               }
+
+               public override void EmitStatement (EmitContext ec)
+               {
+                       if (target == null)
+                               source.Emit (ec);
+                       else
+                               base.EmitStatement (ec);
+               }
+       }
+
+       public class Undo {
+               ArrayList undo_types;
+               
+               public Undo ()
+               {
+                       undo_types = new ArrayList ();
+               }
+
+               public void AddTypeContainer (TypeContainer current_container, TypeContainer tc)
+               {
+                       if (current_container == tc){
+                               Console.Error.WriteLine ("Internal error: inserting container into itself");
+                               return;
+                       }
+                       
+                       if (undo_types == null)
+                               undo_types = new ArrayList ();
+                       undo_types.Add (new Pair (current_container, tc));
+               }
+
+               public void ExecuteUndo ()
+               {
+                       if (undo_types == null)
+                               return;
+
+                       foreach (Pair p in undo_types){
+                               TypeContainer current_container = (TypeContainer) p.First;
+
+                               current_container.RemoveTypeContainer ((TypeContainer) p.Second);
+                       }
+                       undo_types = null;
+               }
+       }
+       
+}
+       
\ No newline at end of file
diff --git a/mcs/mcs/getline.cs b/mcs/mcs/getline.cs
deleted file mode 100644 (file)
index b21a065..0000000
+++ /dev/null
@@ -1,971 +0,0 @@
-//
-// getline.cs: A command line editor
-//
-// Authors:
-//   Miguel de Icaza (miguel@novell.com)
-//
-// Copyright 2008 Novell, Inc.
-//
-// Dual-licensed under the terms of the MIT X11 license or the
-// Apache License 2.0
-//
-// USE -define:DEMO to build this as a standalone file and test it
-//
-// TODO:
-//    Enter an error (a = 1);  Notice how the prompt is in the wrong line
-//             This is caused by Stderr not being tracked by System.Console.
-//    Completion support
-//    Why is Thread.Interrupt not working?   Currently I resort to Abort which is too much.
-//
-// Limitations in System.Console:
-//    Console needs SIGWINCH support of some sort
-//    Console needs a way of updating its position after things have been written
-//    behind its back (P/Invoke puts for example).
-//    System.Console needs to get the DELETE character, and report accordingly.
-//    Typing before the program start causes the cursor position to be wrong
-//              This is caused by Console not reading all the available data
-//              before sending the report-position sequence and reading it back.
-//
-#if NET_2_0 || NET_1_1
-#define IN_MCS_BUILD
-#endif
-
-// Only compile this code in the 2.0 profile, but not in the Moonlight one
-#if (IN_MCS_BUILD && NET_2_0 && !SMCS_SOURCE) || !IN_MCS_BUILD
-using System;
-using System.Text;
-using System.IO;
-using System.Threading;
-using System.Reflection;
-
-namespace Mono.Terminal {
-
-       public class LineEditor {
-               //static StreamWriter log;
-               
-               // The text being edited.
-               StringBuilder text;
-
-               // The text as it is rendered (replaces (char)1 with ^A on display for example).
-               StringBuilder rendered_text;
-
-               // The prompt specified, and the prompt shown to the user.
-               string prompt;
-               string shown_prompt;
-               
-               // The current cursor position, indexes into "text", for an index
-               // into rendered_text, use TextToRenderPos
-               int cursor;
-
-               // The row where we started displaying data.
-               int home_row;
-
-               // The maximum length that has been displayed on the screen
-               int max_rendered;
-
-               // If we are done editing, this breaks the interactive loop
-               bool done = false;
-
-               // The thread where the Editing started taking place
-               Thread edit_thread;
-
-               // Our object that tracks history
-               History history;
-
-               // The contents of the kill buffer (cut/paste in Emacs parlance)
-               string kill_buffer = "";
-
-               // The string being searched for
-               string search;
-               string last_search;
-
-               // whether we are searching (-1= reverse; 0 = no; 1 = forward)
-               int searching;
-
-               // The position where we found the match.
-               int match_at;
-               
-               // Used to implement the Kill semantics (multiple Alt-Ds accumulate)
-               KeyHandler last_handler;
-               
-               delegate void KeyHandler ();
-               
-               struct Handler {
-                       public ConsoleKeyInfo CKI;
-                       public KeyHandler KeyHandler;
-
-                       public Handler (ConsoleKey key, KeyHandler h)
-                       {
-                               CKI = new ConsoleKeyInfo ((char) 0, key, false, false, false);
-                               KeyHandler = h;
-                       }
-
-                       public Handler (char c, KeyHandler h)
-                       {
-                               KeyHandler = h;
-                               // Use the "Zoom" as a flag that we only have a character.
-                               CKI = new ConsoleKeyInfo (c, ConsoleKey.Zoom, false, false, false);
-                       }
-
-                       public Handler (ConsoleKeyInfo cki, KeyHandler h)
-                       {
-                               CKI = cki;
-                               KeyHandler = h;
-                       }
-                       
-                       public static Handler Control (char c, KeyHandler h)
-                       {
-                               return new Handler ((char) (c - 'A' + 1), h);
-                       }
-
-                       public static Handler Alt (char c, ConsoleKey k, KeyHandler h)
-                       {
-                               ConsoleKeyInfo cki = new ConsoleKeyInfo ((char) c, k, false, true, false);
-                               return new Handler (cki, h);
-                       }
-               }
-
-               static Handler [] handlers;
-
-               public LineEditor (string name) : this (name, 10) { }
-               
-               public LineEditor (string name, int histsize)
-               {
-                       handlers = new Handler [] {
-                               new Handler (ConsoleKey.Home,       CmdHome),
-                               new Handler (ConsoleKey.End,        CmdEnd),
-                               new Handler (ConsoleKey.LeftArrow,  CmdLeft),
-                               new Handler (ConsoleKey.RightArrow, CmdRight),
-                               new Handler (ConsoleKey.UpArrow,    CmdHistoryPrev),
-                               new Handler (ConsoleKey.DownArrow,  CmdHistoryNext),
-                               new Handler (ConsoleKey.Enter,      CmdDone),
-                               new Handler (ConsoleKey.Backspace,  CmdBackspace),
-                               new Handler (ConsoleKey.Delete,     CmdDeleteChar),
-                               
-                               // Emacs keys
-                               Handler.Control ('A', CmdHome),
-                               Handler.Control ('E', CmdEnd),
-                               Handler.Control ('B', CmdLeft),
-                               Handler.Control ('F', CmdRight),
-                               Handler.Control ('P', CmdHistoryPrev),
-                               Handler.Control ('N', CmdHistoryNext),
-                               Handler.Control ('K', CmdKillToEOF),
-                               Handler.Control ('Y', CmdYank),
-                               Handler.Control ('D', CmdDeleteChar),
-                               Handler.Control ('L', CmdRefresh),
-                               Handler.Control ('R', CmdReverseSearch),
-                               Handler.Control ('G', delegate {} ),
-                               Handler.Alt ('B', ConsoleKey.B, CmdBackwardWord),
-                               Handler.Alt ('F', ConsoleKey.F, CmdForwardWord),
-                               
-                               Handler.Alt ('D', ConsoleKey.D, CmdDeleteWord),
-                               Handler.Alt ((char) 8, ConsoleKey.Backspace, CmdDeleteBackword),
-                               
-                               // DEBUG
-                               Handler.Control ('T', CmdDebug),
-
-                               // quote
-                               Handler.Control ('Q', delegate { HandleChar (Console.ReadKey (true).KeyChar); })
-                       };
-
-                       rendered_text = new StringBuilder ();
-                       text = new StringBuilder ();
-
-                       history = new History (name, histsize);
-                       
-                       //if (File.Exists ("log"))File.Delete ("log");
-                       //log = File.CreateText ("log"); 
-               }
-
-               void CmdDebug ()
-               {
-                       history.Dump ();
-                       Console.WriteLine ();
-                       Render ();
-               }
-
-               void Render ()
-               {
-                       Console.Write (shown_prompt);
-                       Console.Write (rendered_text);
-
-                       int max = System.Math.Max (rendered_text.Length + shown_prompt.Length, max_rendered);
-                       
-                       for (int i = rendered_text.Length + shown_prompt.Length; i < max_rendered; i++)
-                               Console.Write (' ');
-                       max_rendered = shown_prompt.Length + rendered_text.Length;
-
-                       // Write one more to ensure that we always wrap around properly if we are at the
-                       // end of a line.
-                       Console.Write (' ');
-
-                       UpdateHomeRow (max);
-               }
-
-               void UpdateHomeRow (int screenpos)
-               {
-                       int lines = 1 + (screenpos / Console.WindowWidth);
-
-                       home_row = Console.CursorTop - (lines - 1);
-                       if (home_row < 0)
-                               home_row = 0;
-               }
-               
-
-               void RenderFrom (int pos)
-               {
-                       int rpos = TextToRenderPos (pos);
-                       int i;
-                       
-                       for (i = rpos; i < rendered_text.Length; i++)
-                               Console.Write (rendered_text [i]);
-
-                       if ((shown_prompt.Length + rendered_text.Length) > max_rendered)
-                               max_rendered = shown_prompt.Length + rendered_text.Length;
-                       else {
-                               int max_extra = max_rendered - shown_prompt.Length;
-                               for (; i < max_extra; i++)
-                                       Console.Write (' ');
-                       }
-               }
-
-               void ComputeRendered ()
-               {
-                       rendered_text.Length = 0;
-
-                       for (int i = 0; i < text.Length; i++){
-                               int c = (int) text [i];
-                               if (c < 26){
-                                       if (c == '\t')
-                                               rendered_text.Append ("    ");
-                                       else {
-                                               rendered_text.Append ('^');
-                                               rendered_text.Append ((char) (c + (int) 'A' - 1));
-                                       }
-                               } else
-                                       rendered_text.Append ((char)c);
-                       }
-               }
-
-               int TextToRenderPos (int pos)
-               {
-                       int p = 0;
-                       
-                       for (int i = 0; i < pos; i++){
-                               int c = (int) text [i];
-                               if (c < 26){
-                                       if (c == 9)
-                                               p += 4;
-                                       else
-                                               p += 2;
-                               } else
-                                       p++;
-                       }
-                       return p;
-               }
-
-               int TextToScreenPos (int pos)
-               {
-                       return shown_prompt.Length + TextToRenderPos (pos);
-               }
-               
-               string Prompt {
-                       get { return prompt; }
-                       set { prompt = value; }
-               }
-
-               int LineCount {
-                       get {
-                               return (shown_prompt.Length + rendered_text.Length)/Console.WindowWidth;
-                       }
-               }
-               
-               void ForceCursor (int newpos)
-               {
-                       cursor = newpos;
-
-                       int actual_pos = shown_prompt.Length + TextToRenderPos (cursor);
-                       int row = home_row + (actual_pos/Console.WindowWidth);
-                       int col = actual_pos % Console.WindowWidth;
-
-                       if (row >= Console.BufferHeight)
-                               row = Console.BufferHeight-1;
-                       Console.SetCursorPosition (col, row);
-                       
-                       //log.WriteLine ("Going to cursor={0} row={1} col={2} actual={3} prompt={4} ttr={5} old={6}", newpos, row, col, actual_pos, prompt.Length, TextToRenderPos (cursor), cursor);
-                       //log.Flush ();
-               }
-
-               void UpdateCursor (int newpos)
-               {
-                       if (cursor == newpos)
-                               return;
-
-                       ForceCursor (newpos);
-               }
-
-               void InsertChar (char c)
-               {
-                       int prev_lines = LineCount;
-                       text = text.Insert (cursor, c);
-                       ComputeRendered ();
-                       if (prev_lines != LineCount){
-
-                               Console.SetCursorPosition (0, home_row);
-                               Render ();
-                               ForceCursor (++cursor);
-                       } else {
-                               RenderFrom (cursor);
-                               ForceCursor (++cursor);
-                               UpdateHomeRow (TextToScreenPos (cursor));
-                       }
-               }
-
-               //
-               // Commands
-               //
-               void CmdDone ()
-               {
-                       done = true;
-               }
-
-               void CmdHome ()
-               {
-                       UpdateCursor (0);
-               }
-
-               void CmdEnd ()
-               {
-                       UpdateCursor (text.Length);
-               }
-               
-               void CmdLeft ()
-               {
-                       if (cursor == 0)
-                               return;
-
-                       UpdateCursor (cursor-1);
-               }
-
-               void CmdBackwardWord ()
-               {
-                       int p = WordBackward (cursor);
-                       if (p == -1)
-                               return;
-                       UpdateCursor (p);
-               }
-
-               void CmdForwardWord ()
-               {
-                       int p = WordForward (cursor);
-                       if (p == -1)
-                               return;
-                       UpdateCursor (p);
-               }
-
-               void CmdRight ()
-               {
-                       if (cursor == text.Length)
-                               return;
-
-                       UpdateCursor (cursor+1);
-               }
-
-               void RenderAfter (int p)
-               {
-                       ForceCursor (p);
-                       RenderFrom (p);
-                       ForceCursor (cursor);
-               }
-               
-               void CmdBackspace ()
-               {
-                       if (cursor == 0)
-                               return;
-
-                       text.Remove (--cursor, 1);
-                       ComputeRendered ();
-                       RenderAfter (cursor);
-               }
-
-               void CmdDeleteChar ()
-               {
-                       // If there is no input, this behaves like EOF
-                       if (text.Length == 0){
-                               done = true;
-                               text = null;
-                               Console.WriteLine ();
-                               return;
-                       }
-                       
-                       if (cursor == text.Length)
-                               return;
-                       text.Remove (cursor, 1);
-                       ComputeRendered ();
-                       RenderAfter (cursor);
-               }
-
-               int WordForward (int p)
-               {
-                       if (p >= text.Length)
-                               return -1;
-
-                       int i = p;
-                       if (Char.IsPunctuation (text [p]) || Char.IsWhiteSpace (text[p])){
-                               for (; i < text.Length; i++){
-                                       if (Char.IsLetterOrDigit (text [i]))
-                                           break;
-                               }
-                               for (; i < text.Length; i++){
-                                       if (!Char.IsLetterOrDigit (text [i]))
-                                           break;
-                               }
-                       } else {
-                               for (; i < text.Length; i++){
-                                       if (!Char.IsLetterOrDigit (text [i]))
-                                           break;
-                               }
-                       }
-                       if (i != p)
-                               return i;
-                       return -1;
-               }
-
-               int WordBackward (int p)
-               {
-                       if (p == 0)
-                               return -1;
-
-                       int i = p-1;
-                       if (i == 0)
-                               return 0;
-                       
-                       if (Char.IsPunctuation (text [i]) || Char.IsSymbol (text [i]) || Char.IsWhiteSpace (text[i])){
-                               for (; i >= 0; i--){
-                                       if (Char.IsLetterOrDigit (text [i]))
-                                               break;
-                               }
-                               for (; i >= 0; i--){
-                                       if (!Char.IsLetterOrDigit (text[i]))
-                                               break;
-                               }
-                       } else {
-                               for (; i >= 0; i--){
-                                       if (!Char.IsLetterOrDigit (text [i]))
-                                               break;
-                               }
-                       }
-                       i++;
-                       
-                       if (i != p)
-                               return i;
-
-                       return -1;
-               }
-               
-               void CmdDeleteWord ()
-               {
-                       int pos = WordForward (cursor);
-
-                       if (pos == -1)
-                               return;
-
-                       string k = text.ToString (cursor, pos-cursor);
-                       
-                       if (last_handler == CmdDeleteWord)
-                               kill_buffer = kill_buffer + k;
-                       else
-                               kill_buffer = k;
-                       
-                       text.Remove (cursor, pos-cursor);
-                       ComputeRendered ();
-                       RenderAfter (cursor);
-               }
-               
-               void CmdDeleteBackword ()
-               {
-                       int pos = WordBackward (cursor);
-                       if (pos == -1)
-                               return;
-
-                       string k = text.ToString (pos, cursor-pos);
-                       
-                       if (last_handler == CmdDeleteBackword)
-                               kill_buffer = k + kill_buffer;
-                       else
-                               kill_buffer = k;
-                       
-                       text.Remove (pos, cursor-pos);
-                       ComputeRendered ();
-                       RenderAfter (pos);
-               }
-               
-               //
-               // Adds the current line to the history if needed
-               //
-               void HistoryUpdateLine ()
-               {
-                       history.Update (text.ToString ());
-               }
-               
-               void CmdHistoryPrev ()
-               {
-                       if (!history.PreviousAvailable ())
-                               return;
-
-                       HistoryUpdateLine ();
-                       
-                       SetText (history.Previous ());
-               }
-
-               void CmdHistoryNext ()
-               {
-                       if (!history.NextAvailable())
-                               return;
-
-                       history.Update (text.ToString ());
-                       SetText (history.Next ());
-                       
-               }
-
-               void CmdKillToEOF ()
-               {
-                       kill_buffer = text.ToString (cursor, text.Length-cursor);
-                       text.Length = cursor;
-                       ComputeRendered ();
-                       RenderAfter (cursor);
-               }
-
-               void CmdYank ()
-               {
-                       int prev_lines = LineCount;
-                       text.Insert (cursor, kill_buffer);
-                       ComputeRendered ();
-                       if (prev_lines != LineCount){
-                               Console.SetCursorPosition (0, home_row);
-                               Render ();
-                               cursor += kill_buffer.Length;
-                               ForceCursor (cursor);
-                       } else {
-                               RenderFrom (cursor);
-                               cursor += kill_buffer.Length;
-                               ForceCursor (cursor);
-                               UpdateHomeRow (TextToScreenPos (cursor));
-                       }
-               }
-
-               void SetSearchPrompt (string s)
-               {
-                       SetPrompt ("(reverse-i-search)`" + s + "': ");
-               }
-
-               void ReverseSearch ()
-               {
-                       int p;
-
-                       if (cursor == text.Length){
-                               // The cursor is at the end of the string
-                               
-                               p = text.ToString ().LastIndexOf (search);
-                               if (p != -1){
-                                       match_at = p;
-                                       cursor = p;
-                                       ForceCursor (cursor);
-                                       return;
-                               }
-                       } else {
-                               // The cursor is somewhere in the middle of the string
-                               int start = (cursor == match_at) ? cursor - 1 : cursor;
-                               if (start != -1){
-                                       p = text.ToString ().LastIndexOf (search, start);
-                                       if (p != -1){
-                                               match_at = p;
-                                               cursor = p;
-                                               ForceCursor (cursor);
-                                               return;
-                                       }
-                               }
-                       }
-
-                       // Need to search backwards in history
-                       HistoryUpdateLine ();
-                       string s = history.SearchBackward (search);
-                       if (s != null){
-                               match_at = -1;
-                               SetText (s);
-                               ReverseSearch ();
-                       }
-               }
-               
-               void CmdReverseSearch ()
-               {
-                       if (searching == 0){
-                               match_at = -1;
-                               last_search = search;
-                               searching = -1;
-                               search = "";
-                               SetSearchPrompt ("");
-                       } else {
-                               if (search == ""){
-                                       if (last_search != "" && last_search != null){
-                                               search = last_search;
-                                               SetSearchPrompt (search);
-
-                                               ReverseSearch ();
-                                       }
-                                       return;
-                               }
-                               ReverseSearch ();
-                       } 
-               }
-
-               void SearchAppend (char c)
-               {
-                       search = search + c;
-                       SetSearchPrompt (search);
-
-                       //
-                       // If the new typed data still matches the current text, stay here
-                       //
-                       if (cursor < text.Length){
-                               string r = text.ToString (cursor, text.Length - cursor);
-                               if (r.StartsWith (search))
-                                       return;
-                       }
-
-                       ReverseSearch ();
-               }
-               
-               void CmdRefresh ()
-               {
-                       Console.Clear ();
-                       max_rendered = 0;
-                       Render ();
-                       ForceCursor (cursor);
-               }
-
-               void InterruptEdit (object sender, ConsoleCancelEventArgs a)
-               {
-                       // Do not abort our program:
-                       a.Cancel = true;
-
-                       // Interrupt the editor
-                       edit_thread.Abort();
-               }
-
-               void HandleChar (char c)
-               {
-                       if (searching != 0)
-                               SearchAppend (c);
-                       else
-                               InsertChar (c);
-               }
-
-               void EditLoop ()
-               {
-                       ConsoleKeyInfo cki;
-
-                       while (!done){
-                               cki = Console.ReadKey (true);
-
-                               bool handled = false;
-                               foreach (Handler handler in handlers){
-                                       ConsoleKeyInfo t = handler.CKI;
-
-                                       if (t.Key == cki.Key && t.Modifiers == cki.Modifiers){
-                                               handled = true;
-                                               handler.KeyHandler ();
-                                               last_handler = handler.KeyHandler;
-                                               break;
-                                       } else if (t.KeyChar == cki.KeyChar && t.Key == ConsoleKey.Zoom){
-                                               handled = true;
-                                               handler.KeyHandler ();
-                                               last_handler = handler.KeyHandler;
-                                               break;
-                                       }
-                               }
-                               if (handled){
-                                       if (searching != 0){
-                                               if (last_handler != CmdReverseSearch){
-                                                       searching = 0;
-                                                       SetPrompt (prompt);
-                                               }
-                                       }
-                                       continue;
-                               }
-
-                               if (cki.KeyChar != (char) 0)
-                                       HandleChar (cki.KeyChar);
-                       } 
-               }
-
-               void InitText (string initial)
-               {
-                       text = new StringBuilder (initial);
-                       ComputeRendered ();
-                       cursor = text.Length;
-                       Render ();
-                       ForceCursor (cursor);
-               }
-
-               void SetText (string newtext)
-               {
-                       Console.SetCursorPosition (0, home_row);
-                       InitText (newtext);
-               }
-
-               void SetPrompt (string newprompt)
-               {
-                       shown_prompt = newprompt;
-                       Console.SetCursorPosition (0, home_row);
-                       Render ();
-                       ForceCursor (cursor);
-               }
-               
-               public string Edit (string prompt, string initial)
-               {
-                       edit_thread = Thread.CurrentThread;
-                       searching = 0;
-                       Console.CancelKeyPress += InterruptEdit;
-                       
-                       done = false;
-                       history.CursorToEnd ();
-                       max_rendered = 0;
-                       
-                       Prompt = prompt;
-                       shown_prompt = prompt;
-                       InitText (initial);
-                       history.Append (initial);
-
-                       do {
-                               try {
-                                       EditLoop ();
-                               } catch (ThreadAbortException){
-                                       searching = 0;
-                                       Thread.ResetAbort ();
-                                       Console.WriteLine ();
-                                       SetPrompt (prompt);
-                                       SetText ("");
-                               }
-                       } while (!done);
-                       Console.WriteLine ();
-                       
-                       Console.CancelKeyPress -= InterruptEdit;
-
-                       if (text == null){
-                               history.Close ();
-                               return null;
-                       }
-
-                       string result = text.ToString ();
-                       if (result != "")
-                               history.Accept (result);
-                       else
-                               history.RemoveLast ();
-
-                       return result;
-               }
-
-               //
-               // Emulates the bash-like behavior, where edits done to the
-               // history are recorded
-               //
-               class History {
-                       string [] history;
-                       int head, tail;
-                       int cursor, count;
-                       string histfile;
-                       
-                       public History (string app, int size)
-                       {
-                               if (size < 1)
-                                       throw new ArgumentException ("size");
-
-                               if (app != null){
-                                       string dir = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
-                                       //Console.WriteLine (dir);
-                                       if (!Directory.Exists (dir)){
-                                               try {
-                                                       Directory.CreateDirectory (dir);
-                                               } catch {
-                                                       app = null;
-                                               }
-                                       }
-                                       if (app != null)
-                                               histfile = Path.Combine (dir, app) + ".history";
-                               }
-                               
-                               history = new string [size];
-                               head = tail = cursor = 0;
-
-                               if (File.Exists (histfile)){
-                                       using (StreamReader sr = File.OpenText (histfile)){
-                                               string line;
-                                               
-                                               while ((line = sr.ReadLine ()) != null){
-                                                       if (line != "")
-                                                               Append (line);
-                                               }
-                                       }
-                               }
-                       }
-
-                       public void Close ()
-                       {
-                               if (histfile == null)
-                                       return;
-
-                               try {
-                                       using (StreamWriter sw = File.CreateText (histfile)){
-                                               int start = (count == history.Length) ? head : tail;
-                                               for (int i = start; i < start+count; i++){
-                                                       int p = i % history.Length;
-                                                       sw.WriteLine (history [p]);
-                                               }
-                                       }
-                               } catch {
-                                       // ignore
-                               }
-                       }
-                       
-                       //
-                       // Appends a value to the history
-                       //
-                       public void Append (string s)
-                       {
-                               //Console.WriteLine ("APPENDING {0} {1}", s, Environment.StackTrace);
-                               history [head] = s;
-                               head = (head+1) % history.Length;
-                               if (head == tail)
-                                       tail = (tail+1 % history.Length);
-                               if (count != history.Length)
-                                       count++;
-                       }
-
-                       //
-                       // Updates the current cursor location with the string,
-                       // to support editing of history items.   For the current
-                       // line to participate, an Append must be done before.
-                       //
-                       public void Update (string s)
-                       {
-                               history [cursor] = s;
-                       }
-
-                       public void RemoveLast ()
-                       {
-                               head = head-1;
-                               if (head < 0)
-                                       head = history.Length-1;
-                       }
-                       
-                       public void Accept (string s)
-                       {
-                               int t = head-1;
-                               if (t < 0)
-                                       t = history.Length-1;
-                               
-                               history [t] = s;
-                       }
-                       
-                       public bool PreviousAvailable ()
-                       {
-                               //Console.WriteLine ("h={0} t={1} cursor={2}", head, tail, cursor);
-                               if (count == 0 || cursor == tail)
-                                       return false;
-
-                               return true;
-                       }
-
-                       public bool NextAvailable ()
-                       {
-                               int next = (cursor + 1) % history.Length;
-                               if (count == 0 || next > head)
-                                       return false;
-
-                               return true;
-                       }
-                       
-                       
-                       //
-                       // Returns: a string with the previous line contents, or
-                       // nul if there is no data in the history to move to.
-                       //
-                       public string Previous ()
-                       {
-                               if (!PreviousAvailable ())
-                                       return null;
-
-                               cursor--;
-                               if (cursor < 0)
-                                       cursor = history.Length - 1;
-
-                               return history [cursor];
-                       }
-
-                       public string Next ()
-                       {
-                               if (!NextAvailable ())
-                                       return null;
-
-                               cursor = (cursor + 1) % history.Length;
-                               return history [cursor];
-                       }
-
-                       public void CursorToEnd ()
-                       {
-                               if (head == tail)
-                                       return;
-
-                               cursor = head;
-                       }
-
-                       public void Dump ()
-                       {
-                               Console.WriteLine ("Head={0} Tail={1} Cursor={2}", head, tail, cursor);
-                               for (int i = 0; i < history.Length;i++){
-                                       Console.WriteLine (" {0} {1}: {2}", i == cursor ? "==>" : "   ", i, history[i]);
-                               }
-                               //log.Flush ();
-                       }
-
-                       public string SearchBackward (string term)
-                       {
-                               for (int i = 1; i < count; i++){
-                                       int slot = cursor-i;
-                                       if (slot < 0)
-                                               slot = history.Length-1;
-                                       if (history [slot] != null && history [slot].IndexOf (term) != -1){
-                                               cursor = slot;
-                                               return history [slot];
-                                       }
-
-                                       // Will the next hit tail?
-                                       slot--;
-                                       if (slot < 0)
-                                               slot = history.Length-1;
-                                       if (slot == tail)
-                                               break;
-                               }
-
-                               return null;
-                       }
-                       
-               }
-       }
-
-#if DEMO
-       class Demo {
-               static void Main ()
-               {
-                       LineEditor le = new LineEditor (null);
-                       string s;
-                       
-                       while ((s = le.Edit ("shell> ", "")) != null){
-                               Console.WriteLine ("----> [{0}]", s);
-                       }
-               }
-       }
-#endif
-}
-#endif
index 3df9d818e3562af09e460f2afdb3533b9fdb4e3f..1ef0870d05c4a41025d23647a9b235beee0a9fe3 100644 (file)
@@ -2,7 +2,6 @@ AssemblyInfo.cs
 anonymous.cs
 assign.cs
 attribute.cs
-driver.cs
 cs-tokenizer.cs
 cfold.cs
 class.cs
@@ -13,12 +12,13 @@ convert.cs
 decl.cs
 delegate.cs
 doc.cs
-enum.cs
+driver.cs
 ecore.cs
+enum.cs
+eval.cs
 expression.cs
 flowanalysis.cs
 generic.cs
-getline.cs
 iterators.cs
 lambda.cs
 linq.cs
@@ -29,7 +29,6 @@ namespace.cs
 nullable.cs
 parameter.cs
 pending.cs
-repl.cs
 report.cs
 rootcontext.cs
 roottypes.cs
index b1423d8782af5aa9b7cf5ed8ae51c2307def5567..9ddafc3ed7f9e9b4c904d0f15f90a36da958ad84 100644 (file)
@@ -16,6 +16,7 @@ doc.cs
 doc-bootstrap.cs
 enum.cs
 ecore.cs
+eval.cs
 expression.cs
 flowanalysis.cs
 generic-mcs.cs
@@ -27,7 +28,6 @@ namespace.cs
 nullable.cs
 parameter.cs
 pending.cs
-repl.cs
 report.cs
 rootcontext.cs
 roottypes.cs
diff --git a/mcs/mcs/repl.cs b/mcs/mcs/repl.cs
deleted file mode 100644 (file)
index 7f7b60a..0000000
+++ /dev/null
@@ -1,893 +0,0 @@
-//
-// repl.cs: Support for using the compiler in interactive mode (read-eval-print loop)
-//
-// Authors:
-//   Miguel de Icaza (miguel@gnome.org)
-//
-// Dual licensed under the terms of the MIT X11 or GNU GPL
-//
-// Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
-// Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
-//
-//
-// TODO:
-//   Do not print results in Evaluate, do that elsewhere in preparation for Eval refactoring.
-//   Driver.PartialReset should not reset the coretypes, nor the optional types, to avoid
-//      computing that on every call.
-//
-using System;
-using System.IO;
-using System.Text;
-using System.Globalization;
-using System.Collections;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Threading;
-
-namespace Mono.CSharp {
-
-       public static class InteractiveShell {
-               static bool isatty = true;
-               static public ArrayList using_alias_list = new ArrayList ();
-               static public ArrayList using_list = new ArrayList ();
-               public static Hashtable fields = new Hashtable ();
-
-               static int count;
-               static string current_debug_name;
-
-#if NET_2_0 && !SMCS_SOURCE
-               static Mono.Terminal.LineEditor editor;
-               static bool dumb;
-               static Thread invoke_thread;
-
-               static void ConsoleInterrupt (object sender, ConsoleCancelEventArgs a)
-               {
-                       // Do not about our program
-                       a.Cancel = true;
-
-                       if (invoking)
-                               invoke_thread.Abort ();
-               }
-               
-               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;
-                       invoke_thread = System.Threading.Thread.CurrentThread;
-               }
-
-               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, "");
-                       }
-               }
-
-#else
-               static void SetupConsole ()
-               {
-                       // Here just to shut up the compiler warnings about unused invoking variable
-                       if (invoking)
-                               invoking = false;
-
-                       Console.Error.WriteLine ("Warning: limited functionality in 1.0 mode");
-               }
-
-               static string GetLine (bool primary)
-               {
-                       string prompt = primary ? InteractiveBase.Prompt : InteractiveBase.ContinuationPrompt;
-
-                       if (isatty)
-                               Console.Write (prompt);
-
-                       return Console.ReadLine ();
-               }
-
-#endif
-               delegate string ReadLiner (bool primary);
-
-               static void Reset ()
-               {
-                       CompilerCallableEntryPoint.PartialReset ();
-
-                       //
-                       // PartialReset should not reset the core types, this is very redundant.
-                       //
-                       if (!TypeManager.InitCoreTypes ())
-                               throw new Exception ("Failed to InitCoreTypes");
-                       TypeManager.InitOptionalCoreTypes ();
-                       
-                       Location.AddFile ("<interactive>");
-                       Location.Initialize ();
-
-                       current_debug_name = "interactive" + (count++) + ".dll";
-                       if (Environment.GetEnvironmentVariable ("SAVE") != null){
-                               CodeGen.Init (current_debug_name, current_debug_name, false);
-                       } else
-                               CodeGen.InitDynamic (current_debug_name);
-               }
-
-               static void InitializeUsing ()
-               {
-                       Evaluate ("using System; using System.Linq; using System.Collections.Generic; using System.Collections;");
-               }
-
-               static void InitTerminal ()
-               {
-                       isatty = UnixUtils.isatty (0) && UnixUtils.isatty (1);
-
-                       // 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;
-                       SetupConsole ();
-
-                       if (isatty)
-                               Console.WriteLine ("Mono C# Shell, type \"help;\" for help\n\nEnter statements below.");
-
-               }
-
-#if BOOTSTRAP_WITH_OLDLIB
-               static void LoadStartupFiles ()
-               {
-               }
-#else
-               static void LoadStartupFiles ()
-               {
-                       string dir = Path.Combine (
-                               Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
-                               "csharp");
-                       if (!Directory.Exists (dir))
-                               return;
-
-                       foreach (string file in 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")){
-                                       Driver.LoadAssembly (file, true);
-                               }
-                       }
-               }
-#endif
-
-               static void ReadEvalPrintLoopWith (ReadLiner readline)
-               {
-                       string expr = null;
-                       while (true){
-                               string input = readline (expr == null);
-                               if (input == null)
-                                       return;
-
-                               if (input == "")
-                                       continue;
-
-                               expr = expr == null ? input : expr + "\n" + input;
-                               
-                               expr = Evaluate (expr);
-                       } 
-               }
-               
-               static public int ReadEvalPrintLoop ()
-               {
-                       CompilerCallableEntryPoint.Reset ();
-                       Driver.LoadReferences ();
-                       
-                       InitTerminal ();
-                       RootContext.EvalMode = true;
-
-                       InitializeUsing ();
-
-                       LoadStartupFiles ();
-                       ReadEvalPrintLoopWith (GetLine);
-
-                       return 0;
-               }
-
-               
-               static string Evaluate (string input)
-               {
-                       if (input == null)
-                               return null;
-
-                       bool partial_input;
-                       CSharpParser parser = ParseString (true, input, out partial_input);
-                       if (parser == null){
-                               if (partial_input)
-                                       return input;
-                               
-                               ParseString (false, input, out partial_input);
-                               return null;
-                       }
-                       
-                       // 
-                       // The parser.InteractiveResult will eventually be multiple
-                       // different things.  Currently they are statements, but
-                       // we will add support for copy-pasting entire blocks of
-                       // code, so we will allow namespaces, types, etc
-                       //
-                       object result = parser.InteractiveResult;
-                       
-                       try { 
-                               if (!(result is Class))
-                                       parser.CurrentNamespace.Extract (using_alias_list, using_list);
-
-                               object rval = ExecuteBlock (result as Class, parser.undo);
-                               //
-                               // We use a reference to a compiler type, in this case
-                               // Driver as a flag to indicate that this was a statement
-                               //
-                               if (rval != typeof (NoValueSet)){
-                                       PrettyPrint (rval);
-                                       Console.WriteLine ();
-                               }
-                       } catch (Exception e){
-                               Console.WriteLine (e);
-                       }
-                       return null;
-               }
-
-               enum InputKind {
-                       EOF,
-                       StatementOrExpression,
-                       CompilationUnit,
-                       Error
-               }
-
-               //
-               // Deambiguates the input string to determine if we
-               // want to process a statement or if we want to
-               // process a compilation unit.
-               //
-               // This is done using a top-down predictive parser,
-               // since the yacc/jay parser can not deambiguage this
-               // without more than one lookahead token.   There are very
-               // few ambiguities.
-               //
-               static InputKind ToplevelOrStatement (SeekableStreamReader seekable)
-               {
-                       Tokenizer tokenizer = new Tokenizer (seekable, Location.SourceFiles [0]);
-                       
-                       int t = tokenizer.token ();
-                       switch (t){
-                       case Token.EOF:
-                               return InputKind.EOF;
-                               
-                       // These are toplevels
-                       case Token.EXTERN:
-                       case Token.OPEN_BRACKET:
-                       case Token.ABSTRACT:
-                       case Token.CLASS:
-                       case Token.ENUM:
-                       case Token.INTERFACE:
-                       case Token.INTERNAL:
-                       case Token.NAMESPACE:
-                       case Token.PRIVATE:
-                       case Token.PROTECTED:
-                       case Token.PUBLIC:
-                       case Token.SEALED:
-                       case Token.STATIC:
-                       case Token.STRUCT:
-                               return InputKind.CompilationUnit;
-                               
-                       // Definitely expression
-                       case Token.FIXED:
-                       case Token.BOOL:
-                       case Token.BYTE:
-                       case Token.CHAR:
-                       case Token.DECIMAL:
-                       case Token.DOUBLE:
-                       case Token.FLOAT:
-                       case Token.INT:
-                       case Token.LONG:
-                       case Token.NEW:
-                       case Token.OBJECT:
-                       case Token.SBYTE:
-                       case Token.SHORT:
-                       case Token.STRING:
-                       case Token.UINT:
-                       case Token.ULONG:
-                               return InputKind.StatementOrExpression;
-
-                       // These need deambiguation help
-                       case Token.USING:
-                               t = tokenizer.token ();
-                               if (t == Token.EOF)
-                                       return InputKind.EOF;
-
-                               if (t == Token.IDENTIFIER)
-                                       return InputKind.CompilationUnit;
-                               return InputKind.StatementOrExpression;
-
-
-                       // Distinguish between:
-                       //    delegate opt_anonymous_method_signature block
-                       //    delegate type 
-                       case Token.DELEGATE:
-                               t = tokenizer.token ();
-                               if (t == Token.EOF)
-                                       return InputKind.EOF;
-                               if (t == Token.OPEN_PARENS || t == Token.OPEN_BRACE)
-                                       return InputKind.StatementOrExpression;
-                               return InputKind.CompilationUnit;
-
-                       // Distinguih between:
-                       //    unsafe block
-                       //    unsafe as modifier of a type declaration
-                       case Token.UNSAFE:
-                               t = tokenizer.token ();
-                               if (t == Token.EOF)
-                                       return InputKind.EOF;
-                               if (t == Token.OPEN_PARENS)
-                                       return InputKind.StatementOrExpression;
-                               return InputKind.CompilationUnit;
-                               
-                       // These are errors: we list explicitly what we had
-                       // from the grammar, ERROR and then everything else
-
-                       case Token.READONLY:
-                       case Token.OVERRIDE:
-                       case Token.ERROR:
-                               return InputKind.Error;
-
-                       // This catches everything else allowed by
-                       // expressions.  We could add one-by-one use cases
-                       // if needed.
-                       default:
-                               return InputKind.StatementOrExpression;
-                       }
-               }
-               
-               //
-               // Parses the string @input and returns a CSharpParser if succeeful.
-               //
-               // if @silent is set to true then no errors are
-               // reported to the user.  This is used to do various calls to the
-               // parser and check if the expression is parsable.
-               //
-               // @partial_input: if @silent is true, then it returns whether the
-               // parsed expression was partial, and more data is needed
-               //
-               static CSharpParser ParseString (bool silent, string input, out bool partial_input)
-               {
-                       partial_input = false;
-                       Reset ();
-                       queued_fields.Clear ();
-
-                       Stream s = new MemoryStream (Encoding.Default.GetBytes (input));
-                       SeekableStreamReader seekable = new SeekableStreamReader (s, Encoding.Default);
-
-                       InputKind kind = ToplevelOrStatement (seekable);
-                       if (kind == InputKind.Error){
-                               if (!silent)
-                                       Report.Error (-25, "Detection Parsing Error");
-                               partial_input = false;
-                               return null;
-                       }
-
-                       if (kind == InputKind.EOF){
-                               if (silent == false)
-                                       Console.Error.WriteLine ("Internal error: EOF condition should have been detected in a previous call with silent=true");
-                               partial_input = true;
-                               return null;
-                               
-                       }
-                       seekable.Position = 0;
-
-                       CSharpParser parser = new CSharpParser (seekable, Location.SourceFiles [0]);
-                       parser.ErrorOutput = Report.Stderr;
-
-                       if (kind == InputKind.StatementOrExpression){
-                               parser.Lexer.putback_char = Tokenizer.EvalStatementParserCharacter;
-                               RootContext.StatementMode = true;
-                       } else {
-                               //
-                               // Do not activate EvalCompilationUnitParserCharacter until
-                               // I have figured out all the limitations to invoke methods
-                               // in the generated classes.  See repl.txt
-                               //
-                               parser.Lexer.putback_char = Tokenizer.EvalUsingDeclarationsParserCharacter;
-                               //parser.Lexer.putback_char = Tokenizer.EvalCompilationUnitParserCharacter;
-                               RootContext.StatementMode = false;
-                       }
-
-                       if (silent)
-                               Report.DisableReporting ();
-                       try {
-                               parser.parse ();
-                       } finally {
-                               if (Report.Errors != 0){
-                                       if (silent && parser.UnexpectedEOF)
-                                               partial_input = true;
-
-                                       parser.undo.ExecuteUndo ();
-                                       parser = null;
-                               }
-
-                               if (silent)
-                                       Report.EnableReporting ();
-                       }
-                       return parser;
-               }
-
-               static void p (string s)
-               {
-                       Console.Write (s);
-               }
-
-               static string EscapeString (string s)
-               {
-                       return s.Replace ("\"", "\\\"");
-               }
-               
-               static void PrettyPrint (object result)
-               {
-                       if (result == null){
-                               p ("null");
-                               return;
-                       }
-                       
-                       if (result is Array){
-                               Array a = (Array) result;
-                               
-                               p ("{ ");
-                               int top = a.GetUpperBound (0);
-                               for (int i = a.GetLowerBound (0); i <= top; i++){
-                                       PrettyPrint (a.GetValue (i));
-                                       if (i != top)
-                                               p (", ");
-                               }
-                               p (" }");
-                       } else if (result is bool){
-                               if ((bool) result)
-                                       p ("true");
-                               else
-                                       p ("false");
-                       } else if (result is string){
-                               p (String.Format ("\"{0}\"", EscapeString ((string)result)));
-                       } else if (result is IDictionary){
-                               IDictionary dict = (IDictionary) result;
-                               int top = dict.Count, count = 0;
-                               
-                               p ("{");
-                               foreach (DictionaryEntry entry in dict){
-                                       count++;
-                                       p ("{ ");
-                                       PrettyPrint (entry.Key);
-                                       p (", ");
-                                       PrettyPrint (entry.Value);
-                                       if (count != top)
-                                               p (" }, ");
-                                       else
-                                               p (" }");
-                               }
-                               p ("}");
-                       } else if (result is IEnumerable) {
-                               int i = 0;
-                               p ("{ ");
-                               foreach (object item in (IEnumerable) result) {
-                                       if (i++ != 0)
-                                               p (", ");
-
-                                       PrettyPrint (item);
-                               }
-                               p (" }");
-                       } else {
-                               p (result.ToString ());
-                       }
-               }
-               
-               delegate void HostSignature (ref object retvalue);
-
-               //
-               // Queue all the fields that we use, as we need to then go from FieldBuilder to FieldInfo
-               // or reflection gets confused (it basically gets confused, and variables override each
-               // other).
-               //
-               static ArrayList queued_fields = new ArrayList ();
-               
-               //static ArrayList types = new ArrayList ();
-
-               static volatile bool invoking;
-               
-               static object ExecuteBlock (Class host, Undo undo)
-               {
-                       RootContext.ResolveTree ();
-                       if (Report.Errors != 0){
-                               undo.ExecuteUndo ();
-                               return typeof (NoValueSet);
-                       }
-                       
-                       RootContext.PopulateTypes ();
-                       RootContext.DefineTypes ();
-
-                       if (Report.Errors != 0){
-                               undo.ExecuteUndo ();
-                               return typeof (NoValueSet);
-                       }
-
-                       TypeBuilder tb = null;
-                       MethodBuilder mb = null;
-                               
-                       if (host != null){
-                               tb = host.TypeBuilder;
-                               mb = null;
-                               foreach (MemberCore member in host.Methods){
-                                       if (member.Name != "Host")
-                                               continue;
-                                       
-                                       MethodOrOperator method = (MethodOrOperator) member;
-                                       mb = method.MethodBuilder;
-                                       break;
-                               }
-
-                               if (mb == null)
-                                       throw new Exception ("Internal error: did not find the method builder for the generated method");
-                       }
-                       
-                       RootContext.EmitCode ();
-                       if (Report.Errors != 0)
-                               return typeof (NoValueSet);
-                       
-                       RootContext.CloseTypes ();
-
-                       if (Environment.GetEnvironmentVariable ("SAVE") != null)
-                               CodeGen.Save (current_debug_name, false);
-
-                       if (host == null)
-                               return typeof (NoValueSet);
-                       
-                       //
-                       // Unlike Mono, .NET requires that the MethodInfo is fetched, it cant
-                       // work from MethodBuilders.   Retarded, I know.
-                       //
-                       Type tt = CodeGen.Assembly.Builder.GetType (tb.Name);
-                       MethodInfo mi = tt.GetMethod (mb.Name);
-                       
-                       // Pull the FieldInfos from the type, and keep track of them
-                       foreach (Field field in queued_fields){
-                               FieldInfo fi = tt.GetField (field.Name);
-                               
-                               FieldInfo old = (FieldInfo) fields [field.Name];
-                               
-                               // If a previous value was set, nullify it, so that we do
-                               // not leak memory
-                               if (old != null){
-                                       if (!old.FieldType.IsValueType){
-                                               try {
-                                                       old.SetValue (null, null);
-                                               } catch {
-                                               }
-                                       }
-                               }
-                               
-                               fields [field.Name] = fi;
-                       }
-                       //types.Add (tb);
-
-                       queued_fields.Clear ();
-                       
-                       HostSignature invoker = (HostSignature) System.Delegate.CreateDelegate (typeof (HostSignature), mi);
-                       object retval = typeof (NoValueSet);
-                       
-                       try {
-                               invoking = true;
-                               invoker (ref retval);
-                       } catch (ThreadAbortException e){
-                               Thread.ResetAbort ();
-                               Console.WriteLine ("Interrupted!\n{0}", e);
-                       } finally {
-                               invoking = false;
-                       }
-                       
-                       // d.DynamicInvoke  (new object [] { retval });
-
-                       return retval;
-               }
-
-               static public void LoadAliases (NamespaceEntry ns)
-               {
-                       ns.Populate (using_alias_list, using_list);
-               }
-               
-               //
-               // Just a placeholder class, used as a sentinel to determine that the
-               // generated code did not set a value
-               class NoValueSet {
-               }
-
-               static public FieldInfo LookupField (string name)
-               {
-                       FieldInfo fi =  (FieldInfo) fields [name];
-
-                       return fi;
-               }
-
-               //
-               // Puts the FieldBuilder into a queue of names that will be
-               // registered.   We can not register FieldBuilders directly
-               // we need to fetch the FieldInfo after Reflection cooks the
-               // types, or bad things happen (bad means: FieldBuilders behave
-               // incorrectly across multiple assemblies, causing assignments to
-               // invalid areas
-               //
-               // This also serves for the parser to register Field classes
-               // that should be exposed as global variables
-               //
-               static public void QueueField (Field f)
-               {
-                       queued_fields.Add (f);
-               }
-
-               static public void ShowUsing ()
-               {
-                       foreach (object x in using_alias_list)
-                               Console.WriteLine ("using {0};", x);
-
-                       foreach (object x in using_list)
-                               Console.WriteLine ("using {0};", x);
-               }
-       }
-
-       //
-       // A local variable reference that will create a Field in a
-       // Class with the resolved type.  This is necessary so we can
-       // support "var" as a field type in a class declaration.
-       //
-       // We allow LocalVariableReferece to do the heavy lifting, and
-       // then we insert the field with the resolved type
-       //
-       public class LocalVariableReferenceWithClassSideEffect : LocalVariableReference {
-               TypeContainer container;
-               string name;
-               
-               public LocalVariableReferenceWithClassSideEffect (TypeContainer container, string name, Block current_block, string local_variable_id, Location loc)
-                       : base (current_block, local_variable_id, loc)
-               {
-                       this.container = container;
-                       this.name = name;
-               }
-
-               public override bool Equals (object obj)
-               {
-                       LocalVariableReferenceWithClassSideEffect lvr = obj as LocalVariableReferenceWithClassSideEffect;
-                       if (lvr == null)
-                               return false;
-
-                       if (lvr.name != name || lvr.container != container)
-                               return false;
-
-                       return base.Equals (obj);
-               }
-
-               public override int GetHashCode ()
-               {
-                       return name.GetHashCode ();
-               }
-               
-               override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
-               {
-                       Expression ret = base.DoResolveLValue (ec, right_side);
-                       if (ret == null)
-                               return null;
-
-                       Field f = new Field (container, new TypeExpression (ret.Type, Location),
-                                            Modifiers.PUBLIC | Modifiers.STATIC,
-                                            name, null, Location);
-                       container.AddField (f);
-                       if (f.Define ())
-                               InteractiveShell.QueueField (f);
-                       
-                       return ret;
-               }
-       }
-
-       /// <summary>
-       ///    A class used to assign values if the source expression is not void
-       ///
-       ///    Used by the interactive shell to allow it to call this code to set
-       ///    the return value for an invocation.
-       /// </summary>
-       class OptionalAssign : SimpleAssign {
-               public OptionalAssign (Expression t, Expression s, Location loc)
-                       : base (t, s, loc)
-               {
-               }
-
-               public override Expression DoResolve (EmitContext ec)
-               {
-                       CloneContext cc = new CloneContext ();
-                       Expression clone = source.Clone (cc);
-
-                       clone = clone.Resolve (ec);
-                       if (clone == null)
-                               return null;
-
-                       // This means its really a statement.
-                       if (clone.Type == TypeManager.void_type){
-                               source = source.Resolve (ec);
-                               target = null;
-                               type = TypeManager.void_type;
-                               eclass = ExprClass.Value;
-                               return this;
-                       }
-
-                       return base.DoResolve (ec);
-               }
-
-               public override void Emit (EmitContext ec)
-               {
-                       if (target == null)
-                               source.Emit (ec);
-                       else
-                               base.Emit (ec);
-               }
-
-               public override void EmitStatement (EmitContext ec)
-               {
-                       if (target == null)
-                               source.Emit (ec);
-                       else
-                               base.EmitStatement (ec);
-               }
-       }
-
-       public class Undo {
-               ArrayList undo_types;
-               
-               public Undo ()
-               {
-                       undo_types = new ArrayList ();
-               }
-
-               public void AddTypeContainer (TypeContainer current_container, TypeContainer tc)
-               {
-                       if (current_container == tc){
-                               Console.Error.WriteLine ("Internal error: inserting container into itself");
-                               return;
-                       }
-                       
-                       if (undo_types == null)
-                               undo_types = new ArrayList ();
-                       undo_types.Add (new Pair (current_container, tc));
-               }
-
-               public void ExecuteUndo ()
-               {
-                       if (undo_types == null)
-                               return;
-
-                       foreach (Pair p in undo_types){
-                               TypeContainer current_container = (TypeContainer) p.First;
-
-                               current_container.RemoveTypeContainer ((TypeContainer) p.Second);
-                       }
-                       undo_types = null;
-               }
-       }
-       
-       /// <summary>
-       ///   The base class for every interaction line
-       /// </summary>
-       public class InteractiveBase {
-               public static string Prompt             = "csharp> ";
-               public static string ContinuationPrompt = "      > ";
-
-               static string Quote (string s)
-               {
-                       if (s.IndexOf ('"') != -1)
-                               s = s.Replace ("\"", "\\\"");
-                       
-                       return "\"" + s + "\"";
-               }
-
-               static public void ShowVars ()
-               {
-                       foreach (DictionaryEntry de in InteractiveShell.fields){
-                               FieldInfo fi = InteractiveShell.LookupField ((string) de.Key);
-                               object value = null;
-                               bool error = false;
-                               
-                               try {
-                                       if (value == null)
-                                               value = "null";
-                                       value = fi.GetValue (null);
-                                       if (value is string)
-                                               value = Quote ((string)value);
-                               } catch {
-                                       error = true;
-                               }
-
-                               if (error)
-                                       Console.WriteLine ("{0} {1} <error reading value>", TypeManager.CSharpName(fi.FieldType), de.Key);
-                               else
-                                       Console.WriteLine ("{0} {1} = {2}", TypeManager.CSharpName(fi.FieldType), de.Key, value);
-                       }
-               }
-
-               static public void ShowUsing ()
-               {
-                       InteractiveShell.ShowUsing ();
-               }
-
-               public delegate void Simple ();
-               
-               static public TimeSpan Time (Simple a)
-               {
-                       DateTime start = DateTime.Now;
-                       a ();
-                       return DateTime.Now - start;
-               }
-               
-#if !SMCS_SOURCE
-               static public void LoadPackage (string pkg)
-               {
-                       if (pkg == null){
-                               Console.Error.WriteLine ("Invalid package specified");
-                               return;
-                       }
-
-                       string pkgout = Driver.GetPackageFlags (pkg, false);
-                       if (pkgout == null)
-                               return;
-
-                       string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
-                               Split (new Char [] { ' ', '\t'});
-
-                       foreach (string s in xargs){
-                               if (s.StartsWith ("-r:") || s.StartsWith ("/r:") || s.StartsWith ("/reference:")){
-                                       string lib = s.Substring (s.IndexOf (':')+1);
-
-                                       //Console.WriteLine ("Loading: {0}", lib);
-                                       Driver.LoadAssembly (lib, true);
-                                       continue;
-                               }
-                       }
-               }
-#endif
-
-               static public void LoadAssembly (string assembly)
-               {
-                       Driver.LoadAssembly (assembly, true);
-               }
-               
-               static public string help {
-                       get {
-                               return  "Static methods:\n"+
-                                       "  LoadPackage (pkg); - Loads the given Package (like -pkg:FILE)\n" +
-                                       "  LoadAssembly (ass) - Loads the given assembly (like -r:ASS)\n" + 
-                                       "  ShowVars ();       - Shows defined local variables.\n" +
-                                       "  ShowUsing ();      - Show active using decltions.\n" +
-                                       "  Prompt             - The prompt used by the C# shell\n" +
-                                       "  ContinuationPrompt - The prompt for partial input\n" +
-                                       "  Time(() -> { })    - Times the specified code\n" +
-                                       "  quit;\n" +
-                                       "  help;\n";
-                       }
-               }
-
-               static public object quit {
-                       get {
-                               Environment.Exit (0);
-                               return null;
-                       }
-               }
-       }
-}
index 508894bfce7813997f505703c411f3d5e44d03c2..b56a896c7518fe127dcc92814d31aab0d1c8d4b0 100644 (file)
@@ -17,6 +17,10 @@ Documentation for the REPL mode for MCS can be found here:
        * Run a REPL on a socket (from Joe Shaw)
        * Host a REPL on XSP (from Nat).
 
+* TODO
+
+       Clear struct fields inside the clearing code.
+
 * Other ideas:
 
        MD addin for "csharp"
index e052702cbf0d0eb6365cffd2be38cb61629f3e0f..3b58eae84c75f2c8bb90fa7785c0f7427961d99e 100644 (file)
@@ -15,6 +15,7 @@ delegate.cs
 doc-bootstrap.cs
 enum.cs
 ecore.cs
+eval.cs
 expression.cs
 flowanalysis.cs
 generic.cs
@@ -28,7 +29,6 @@ namespace.cs
 nullable.cs
 parameter.cs
 pending.cs
-repl.cs
 report.cs
 rootcontext.cs
 roottypes.cs
index 4001b640b57c4cde70cc034ae362588cfb214f3d..471ce0b4632578a74a0c1b425d1733c74d8ebdc9 100644 (file)
@@ -1,3 +1,7 @@
+2008-09-10  Miguel de Icaza  <miguel@novell.com>
+
+       * Makefile (thisdir): Add csharp here.
+
 2008-08-28  Zoltan Varga  <vargaz@gmail.com>
 
        * Makefile (net_2_0_SUBDIRS): Add gacutil.
index 83ad6b5048c9802bbfa66a9284b045e23c069c96..1f141184c4b00307a8c371b87dcd5d7af3ade6f8 100644 (file)
@@ -9,13 +9,13 @@ net_1_1_bootstrap_SUBDIRS = gacutil security resgen culevel
 net_2_0_bootstrap_SUBDIRS = resgen
 
 net_2_0_SUBDIRS = \
-       al corcompare mono-xsd wsdl compiler-tester monop xbuild resgen \
+       al corcompare csharp mono-xsd wsdl compiler-tester monop xbuild resgen \
        mono-service mkbundle sgen security mconfig installutil nunitreport sqlsharp \
        gacutil
 net_2_1_raw_SUBDIRS = compiler-tester
 net_2_1_SUBDIRS = compiler-tester tuner
 
-DIST_ONLY_SUBDIRS = xbuild sgen mconfig nunitreport sqlsharp
+DIST_ONLY_SUBDIRS = xbuild sgen mconfig nunitreport sqlsharp csharp
 
 include ../build/rules.make
 
diff --git a/mcs/tools/csharp/ChangeLog b/mcs/tools/csharp/ChangeLog
new file mode 100644 (file)
index 0000000..885a14e
--- /dev/null
@@ -0,0 +1,4 @@
+2008-09-10  Miguel de Icaza  <miguel@novell.com>
+
+       * Move the repl shell here.
+
diff --git a/mcs/tools/csharp/Makefile b/mcs/tools/csharp/Makefile
new file mode 100644 (file)
index 0000000..b7a51da
--- /dev/null
@@ -0,0 +1,17 @@
+thisdir = tools/csharp
+SUBDIRS = 
+include ../../build/rules.make
+
+LOCAL_MCS_FLAGS = -r:$(topdir)/class/lib/$(PROFILE)/gmcs.exe
+
+ifeq (net_2_0, $(PROFILE))
+PROGRAM = $(topdir)/class/lib/$(PROFILE)/csharp.exe
+else
+PROGRAM = 
+endif
+
+DISTFILES = repl.txt
+
+CLEAN_FILES = csharp.exe *.mdb
+
+include ../../build/executable.make
\ No newline at end of file
diff --git a/mcs/tools/csharp/csharp.exe.sources b/mcs/tools/csharp/csharp.exe.sources
new file mode 100644 (file)
index 0000000..911caa4
--- /dev/null
@@ -0,0 +1 @@
+repl.cs
\ No newline at end of file
diff --git a/mcs/tools/csharp/getline.cs b/mcs/tools/csharp/getline.cs
new file mode 100644 (file)
index 0000000..b21a065
--- /dev/null
@@ -0,0 +1,971 @@
+//
+// getline.cs: A command line editor
+//
+// Authors:
+//   Miguel de Icaza (miguel@novell.com)
+//
+// Copyright 2008 Novell, Inc.
+//
+// Dual-licensed under the terms of the MIT X11 license or the
+// Apache License 2.0
+//
+// USE -define:DEMO to build this as a standalone file and test it
+//
+// TODO:
+//    Enter an error (a = 1);  Notice how the prompt is in the wrong line
+//             This is caused by Stderr not being tracked by System.Console.
+//    Completion support
+//    Why is Thread.Interrupt not working?   Currently I resort to Abort which is too much.
+//
+// Limitations in System.Console:
+//    Console needs SIGWINCH support of some sort
+//    Console needs a way of updating its position after things have been written
+//    behind its back (P/Invoke puts for example).
+//    System.Console needs to get the DELETE character, and report accordingly.
+//    Typing before the program start causes the cursor position to be wrong
+//              This is caused by Console not reading all the available data
+//              before sending the report-position sequence and reading it back.
+//
+#if NET_2_0 || NET_1_1
+#define IN_MCS_BUILD
+#endif
+
+// Only compile this code in the 2.0 profile, but not in the Moonlight one
+#if (IN_MCS_BUILD && NET_2_0 && !SMCS_SOURCE) || !IN_MCS_BUILD
+using System;
+using System.Text;
+using System.IO;
+using System.Threading;
+using System.Reflection;
+
+namespace Mono.Terminal {
+
+       public class LineEditor {
+               //static StreamWriter log;
+               
+               // The text being edited.
+               StringBuilder text;
+
+               // The text as it is rendered (replaces (char)1 with ^A on display for example).
+               StringBuilder rendered_text;
+
+               // The prompt specified, and the prompt shown to the user.
+               string prompt;
+               string shown_prompt;
+               
+               // The current cursor position, indexes into "text", for an index
+               // into rendered_text, use TextToRenderPos
+               int cursor;
+
+               // The row where we started displaying data.
+               int home_row;
+
+               // The maximum length that has been displayed on the screen
+               int max_rendered;
+
+               // If we are done editing, this breaks the interactive loop
+               bool done = false;
+
+               // The thread where the Editing started taking place
+               Thread edit_thread;
+
+               // Our object that tracks history
+               History history;
+
+               // The contents of the kill buffer (cut/paste in Emacs parlance)
+               string kill_buffer = "";
+
+               // The string being searched for
+               string search;
+               string last_search;
+
+               // whether we are searching (-1= reverse; 0 = no; 1 = forward)
+               int searching;
+
+               // The position where we found the match.
+               int match_at;
+               
+               // Used to implement the Kill semantics (multiple Alt-Ds accumulate)
+               KeyHandler last_handler;
+               
+               delegate void KeyHandler ();
+               
+               struct Handler {
+                       public ConsoleKeyInfo CKI;
+                       public KeyHandler KeyHandler;
+
+                       public Handler (ConsoleKey key, KeyHandler h)
+                       {
+                               CKI = new ConsoleKeyInfo ((char) 0, key, false, false, false);
+                               KeyHandler = h;
+                       }
+
+                       public Handler (char c, KeyHandler h)
+                       {
+                               KeyHandler = h;
+                               // Use the "Zoom" as a flag that we only have a character.
+                               CKI = new ConsoleKeyInfo (c, ConsoleKey.Zoom, false, false, false);
+                       }
+
+                       public Handler (ConsoleKeyInfo cki, KeyHandler h)
+                       {
+                               CKI = cki;
+                               KeyHandler = h;
+                       }
+                       
+                       public static Handler Control (char c, KeyHandler h)
+                       {
+                               return new Handler ((char) (c - 'A' + 1), h);
+                       }
+
+                       public static Handler Alt (char c, ConsoleKey k, KeyHandler h)
+                       {
+                               ConsoleKeyInfo cki = new ConsoleKeyInfo ((char) c, k, false, true, false);
+                               return new Handler (cki, h);
+                       }
+               }
+
+               static Handler [] handlers;
+
+               public LineEditor (string name) : this (name, 10) { }
+               
+               public LineEditor (string name, int histsize)
+               {
+                       handlers = new Handler [] {
+                               new Handler (ConsoleKey.Home,       CmdHome),
+                               new Handler (ConsoleKey.End,        CmdEnd),
+                               new Handler (ConsoleKey.LeftArrow,  CmdLeft),
+                               new Handler (ConsoleKey.RightArrow, CmdRight),
+                               new Handler (ConsoleKey.UpArrow,    CmdHistoryPrev),
+                               new Handler (ConsoleKey.DownArrow,  CmdHistoryNext),
+                               new Handler (ConsoleKey.Enter,      CmdDone),
+                               new Handler (ConsoleKey.Backspace,  CmdBackspace),
+                               new Handler (ConsoleKey.Delete,     CmdDeleteChar),
+                               
+                               // Emacs keys
+                               Handler.Control ('A', CmdHome),
+                               Handler.Control ('E', CmdEnd),
+                               Handler.Control ('B', CmdLeft),
+                               Handler.Control ('F', CmdRight),
+                               Handler.Control ('P', CmdHistoryPrev),
+                               Handler.Control ('N', CmdHistoryNext),
+                               Handler.Control ('K', CmdKillToEOF),
+                               Handler.Control ('Y', CmdYank),
+                               Handler.Control ('D', CmdDeleteChar),
+                               Handler.Control ('L', CmdRefresh),
+                               Handler.Control ('R', CmdReverseSearch),
+                               Handler.Control ('G', delegate {} ),
+                               Handler.Alt ('B', ConsoleKey.B, CmdBackwardWord),
+                               Handler.Alt ('F', ConsoleKey.F, CmdForwardWord),
+                               
+                               Handler.Alt ('D', ConsoleKey.D, CmdDeleteWord),
+                               Handler.Alt ((char) 8, ConsoleKey.Backspace, CmdDeleteBackword),
+                               
+                               // DEBUG
+                               Handler.Control ('T', CmdDebug),
+
+                               // quote
+                               Handler.Control ('Q', delegate { HandleChar (Console.ReadKey (true).KeyChar); })
+                       };
+
+                       rendered_text = new StringBuilder ();
+                       text = new StringBuilder ();
+
+                       history = new History (name, histsize);
+                       
+                       //if (File.Exists ("log"))File.Delete ("log");
+                       //log = File.CreateText ("log"); 
+               }
+
+               void CmdDebug ()
+               {
+                       history.Dump ();
+                       Console.WriteLine ();
+                       Render ();
+               }
+
+               void Render ()
+               {
+                       Console.Write (shown_prompt);
+                       Console.Write (rendered_text);
+
+                       int max = System.Math.Max (rendered_text.Length + shown_prompt.Length, max_rendered);
+                       
+                       for (int i = rendered_text.Length + shown_prompt.Length; i < max_rendered; i++)
+                               Console.Write (' ');
+                       max_rendered = shown_prompt.Length + rendered_text.Length;
+
+                       // Write one more to ensure that we always wrap around properly if we are at the
+                       // end of a line.
+                       Console.Write (' ');
+
+                       UpdateHomeRow (max);
+               }
+
+               void UpdateHomeRow (int screenpos)
+               {
+                       int lines = 1 + (screenpos / Console.WindowWidth);
+
+                       home_row = Console.CursorTop - (lines - 1);
+                       if (home_row < 0)
+                               home_row = 0;
+               }
+               
+
+               void RenderFrom (int pos)
+               {
+                       int rpos = TextToRenderPos (pos);
+                       int i;
+                       
+                       for (i = rpos; i < rendered_text.Length; i++)
+                               Console.Write (rendered_text [i]);
+
+                       if ((shown_prompt.Length + rendered_text.Length) > max_rendered)
+                               max_rendered = shown_prompt.Length + rendered_text.Length;
+                       else {
+                               int max_extra = max_rendered - shown_prompt.Length;
+                               for (; i < max_extra; i++)
+                                       Console.Write (' ');
+                       }
+               }
+
+               void ComputeRendered ()
+               {
+                       rendered_text.Length = 0;
+
+                       for (int i = 0; i < text.Length; i++){
+                               int c = (int) text [i];
+                               if (c < 26){
+                                       if (c == '\t')
+                                               rendered_text.Append ("    ");
+                                       else {
+                                               rendered_text.Append ('^');
+                                               rendered_text.Append ((char) (c + (int) 'A' - 1));
+                                       }
+                               } else
+                                       rendered_text.Append ((char)c);
+                       }
+               }
+
+               int TextToRenderPos (int pos)
+               {
+                       int p = 0;
+                       
+                       for (int i = 0; i < pos; i++){
+                               int c = (int) text [i];
+                               if (c < 26){
+                                       if (c == 9)
+                                               p += 4;
+                                       else
+                                               p += 2;
+                               } else
+                                       p++;
+                       }
+                       return p;
+               }
+
+               int TextToScreenPos (int pos)
+               {
+                       return shown_prompt.Length + TextToRenderPos (pos);
+               }
+               
+               string Prompt {
+                       get { return prompt; }
+                       set { prompt = value; }
+               }
+
+               int LineCount {
+                       get {
+                               return (shown_prompt.Length + rendered_text.Length)/Console.WindowWidth;
+                       }
+               }
+               
+               void ForceCursor (int newpos)
+               {
+                       cursor = newpos;
+
+                       int actual_pos = shown_prompt.Length + TextToRenderPos (cursor);
+                       int row = home_row + (actual_pos/Console.WindowWidth);
+                       int col = actual_pos % Console.WindowWidth;
+
+                       if (row >= Console.BufferHeight)
+                               row = Console.BufferHeight-1;
+                       Console.SetCursorPosition (col, row);
+                       
+                       //log.WriteLine ("Going to cursor={0} row={1} col={2} actual={3} prompt={4} ttr={5} old={6}", newpos, row, col, actual_pos, prompt.Length, TextToRenderPos (cursor), cursor);
+                       //log.Flush ();
+               }
+
+               void UpdateCursor (int newpos)
+               {
+                       if (cursor == newpos)
+                               return;
+
+                       ForceCursor (newpos);
+               }
+
+               void InsertChar (char c)
+               {
+                       int prev_lines = LineCount;
+                       text = text.Insert (cursor, c);
+                       ComputeRendered ();
+                       if (prev_lines != LineCount){
+
+                               Console.SetCursorPosition (0, home_row);
+                               Render ();
+                               ForceCursor (++cursor);
+                       } else {
+                               RenderFrom (cursor);
+                               ForceCursor (++cursor);
+                               UpdateHomeRow (TextToScreenPos (cursor));
+                       }
+               }
+
+               //
+               // Commands
+               //
+               void CmdDone ()
+               {
+                       done = true;
+               }
+
+               void CmdHome ()
+               {
+                       UpdateCursor (0);
+               }
+
+               void CmdEnd ()
+               {
+                       UpdateCursor (text.Length);
+               }
+               
+               void CmdLeft ()
+               {
+                       if (cursor == 0)
+                               return;
+
+                       UpdateCursor (cursor-1);
+               }
+
+               void CmdBackwardWord ()
+               {
+                       int p = WordBackward (cursor);
+                       if (p == -1)
+                               return;
+                       UpdateCursor (p);
+               }
+
+               void CmdForwardWord ()
+               {
+                       int p = WordForward (cursor);
+                       if (p == -1)
+                               return;
+                       UpdateCursor (p);
+               }
+
+               void CmdRight ()
+               {
+                       if (cursor == text.Length)
+                               return;
+
+                       UpdateCursor (cursor+1);
+               }
+
+               void RenderAfter (int p)
+               {
+                       ForceCursor (p);
+                       RenderFrom (p);
+                       ForceCursor (cursor);
+               }
+               
+               void CmdBackspace ()
+               {
+                       if (cursor == 0)
+                               return;
+
+                       text.Remove (--cursor, 1);
+                       ComputeRendered ();
+                       RenderAfter (cursor);
+               }
+
+               void CmdDeleteChar ()
+               {
+                       // If there is no input, this behaves like EOF
+                       if (text.Length == 0){
+                               done = true;
+                               text = null;
+                               Console.WriteLine ();
+                               return;
+                       }
+                       
+                       if (cursor == text.Length)
+                               return;
+                       text.Remove (cursor, 1);
+                       ComputeRendered ();
+                       RenderAfter (cursor);
+               }
+
+               int WordForward (int p)
+               {
+                       if (p >= text.Length)
+                               return -1;
+
+                       int i = p;
+                       if (Char.IsPunctuation (text [p]) || Char.IsWhiteSpace (text[p])){
+                               for (; i < text.Length; i++){
+                                       if (Char.IsLetterOrDigit (text [i]))
+                                           break;
+                               }
+                               for (; i < text.Length; i++){
+                                       if (!Char.IsLetterOrDigit (text [i]))
+                                           break;
+                               }
+                       } else {
+                               for (; i < text.Length; i++){
+                                       if (!Char.IsLetterOrDigit (text [i]))
+                                           break;
+                               }
+                       }
+                       if (i != p)
+                               return i;
+                       return -1;
+               }
+
+               int WordBackward (int p)
+               {
+                       if (p == 0)
+                               return -1;
+
+                       int i = p-1;
+                       if (i == 0)
+                               return 0;
+                       
+                       if (Char.IsPunctuation (text [i]) || Char.IsSymbol (text [i]) || Char.IsWhiteSpace (text[i])){
+                               for (; i >= 0; i--){
+                                       if (Char.IsLetterOrDigit (text [i]))
+                                               break;
+                               }
+                               for (; i >= 0; i--){
+                                       if (!Char.IsLetterOrDigit (text[i]))
+                                               break;
+                               }
+                       } else {
+                               for (; i >= 0; i--){
+                                       if (!Char.IsLetterOrDigit (text [i]))
+                                               break;
+                               }
+                       }
+                       i++;
+                       
+                       if (i != p)
+                               return i;
+
+                       return -1;
+               }
+               
+               void CmdDeleteWord ()
+               {
+                       int pos = WordForward (cursor);
+
+                       if (pos == -1)
+                               return;
+
+                       string k = text.ToString (cursor, pos-cursor);
+                       
+                       if (last_handler == CmdDeleteWord)
+                               kill_buffer = kill_buffer + k;
+                       else
+                               kill_buffer = k;
+                       
+                       text.Remove (cursor, pos-cursor);
+                       ComputeRendered ();
+                       RenderAfter (cursor);
+               }
+               
+               void CmdDeleteBackword ()
+               {
+                       int pos = WordBackward (cursor);
+                       if (pos == -1)
+                               return;
+
+                       string k = text.ToString (pos, cursor-pos);
+                       
+                       if (last_handler == CmdDeleteBackword)
+                               kill_buffer = k + kill_buffer;
+                       else
+                               kill_buffer = k;
+                       
+                       text.Remove (pos, cursor-pos);
+                       ComputeRendered ();
+                       RenderAfter (pos);
+               }
+               
+               //
+               // Adds the current line to the history if needed
+               //
+               void HistoryUpdateLine ()
+               {
+                       history.Update (text.ToString ());
+               }
+               
+               void CmdHistoryPrev ()
+               {
+                       if (!history.PreviousAvailable ())
+                               return;
+
+                       HistoryUpdateLine ();
+                       
+                       SetText (history.Previous ());
+               }
+
+               void CmdHistoryNext ()
+               {
+                       if (!history.NextAvailable())
+                               return;
+
+                       history.Update (text.ToString ());
+                       SetText (history.Next ());
+                       
+               }
+
+               void CmdKillToEOF ()
+               {
+                       kill_buffer = text.ToString (cursor, text.Length-cursor);
+                       text.Length = cursor;
+                       ComputeRendered ();
+                       RenderAfter (cursor);
+               }
+
+               void CmdYank ()
+               {
+                       int prev_lines = LineCount;
+                       text.Insert (cursor, kill_buffer);
+                       ComputeRendered ();
+                       if (prev_lines != LineCount){
+                               Console.SetCursorPosition (0, home_row);
+                               Render ();
+                               cursor += kill_buffer.Length;
+                               ForceCursor (cursor);
+                       } else {
+                               RenderFrom (cursor);
+                               cursor += kill_buffer.Length;
+                               ForceCursor (cursor);
+                               UpdateHomeRow (TextToScreenPos (cursor));
+                       }
+               }
+
+               void SetSearchPrompt (string s)
+               {
+                       SetPrompt ("(reverse-i-search)`" + s + "': ");
+               }
+
+               void ReverseSearch ()
+               {
+                       int p;
+
+                       if (cursor == text.Length){
+                               // The cursor is at the end of the string
+                               
+                               p = text.ToString ().LastIndexOf (search);
+                               if (p != -1){
+                                       match_at = p;
+                                       cursor = p;
+                                       ForceCursor (cursor);
+                                       return;
+                               }
+                       } else {
+                               // The cursor is somewhere in the middle of the string
+                               int start = (cursor == match_at) ? cursor - 1 : cursor;
+                               if (start != -1){
+                                       p = text.ToString ().LastIndexOf (search, start);
+                                       if (p != -1){
+                                               match_at = p;
+                                               cursor = p;
+                                               ForceCursor (cursor);
+                                               return;
+                                       }
+                               }
+                       }
+
+                       // Need to search backwards in history
+                       HistoryUpdateLine ();
+                       string s = history.SearchBackward (search);
+                       if (s != null){
+                               match_at = -1;
+                               SetText (s);
+                               ReverseSearch ();
+                       }
+               }
+               
+               void CmdReverseSearch ()
+               {
+                       if (searching == 0){
+                               match_at = -1;
+                               last_search = search;
+                               searching = -1;
+                               search = "";
+                               SetSearchPrompt ("");
+                       } else {
+                               if (search == ""){
+                                       if (last_search != "" && last_search != null){
+                                               search = last_search;
+                                               SetSearchPrompt (search);
+
+                                               ReverseSearch ();
+                                       }
+                                       return;
+                               }
+                               ReverseSearch ();
+                       } 
+               }
+
+               void SearchAppend (char c)
+               {
+                       search = search + c;
+                       SetSearchPrompt (search);
+
+                       //
+                       // If the new typed data still matches the current text, stay here
+                       //
+                       if (cursor < text.Length){
+                               string r = text.ToString (cursor, text.Length - cursor);
+                               if (r.StartsWith (search))
+                                       return;
+                       }
+
+                       ReverseSearch ();
+               }
+               
+               void CmdRefresh ()
+               {
+                       Console.Clear ();
+                       max_rendered = 0;
+                       Render ();
+                       ForceCursor (cursor);
+               }
+
+               void InterruptEdit (object sender, ConsoleCancelEventArgs a)
+               {
+                       // Do not abort our program:
+                       a.Cancel = true;
+
+                       // Interrupt the editor
+                       edit_thread.Abort();
+               }
+
+               void HandleChar (char c)
+               {
+                       if (searching != 0)
+                               SearchAppend (c);
+                       else
+                               InsertChar (c);
+               }
+
+               void EditLoop ()
+               {
+                       ConsoleKeyInfo cki;
+
+                       while (!done){
+                               cki = Console.ReadKey (true);
+
+                               bool handled = false;
+                               foreach (Handler handler in handlers){
+                                       ConsoleKeyInfo t = handler.CKI;
+
+                                       if (t.Key == cki.Key && t.Modifiers == cki.Modifiers){
+                                               handled = true;
+                                               handler.KeyHandler ();
+                                               last_handler = handler.KeyHandler;
+                                               break;
+                                       } else if (t.KeyChar == cki.KeyChar && t.Key == ConsoleKey.Zoom){
+                                               handled = true;
+                                               handler.KeyHandler ();
+                                               last_handler = handler.KeyHandler;
+                                               break;
+                                       }
+                               }
+                               if (handled){
+                                       if (searching != 0){
+                                               if (last_handler != CmdReverseSearch){
+                                                       searching = 0;
+                                                       SetPrompt (prompt);
+                                               }
+                                       }
+                                       continue;
+                               }
+
+                               if (cki.KeyChar != (char) 0)
+                                       HandleChar (cki.KeyChar);
+                       } 
+               }
+
+               void InitText (string initial)
+               {
+                       text = new StringBuilder (initial);
+                       ComputeRendered ();
+                       cursor = text.Length;
+                       Render ();
+                       ForceCursor (cursor);
+               }
+
+               void SetText (string newtext)
+               {
+                       Console.SetCursorPosition (0, home_row);
+                       InitText (newtext);
+               }
+
+               void SetPrompt (string newprompt)
+               {
+                       shown_prompt = newprompt;
+                       Console.SetCursorPosition (0, home_row);
+                       Render ();
+                       ForceCursor (cursor);
+               }
+               
+               public string Edit (string prompt, string initial)
+               {
+                       edit_thread = Thread.CurrentThread;
+                       searching = 0;
+                       Console.CancelKeyPress += InterruptEdit;
+                       
+                       done = false;
+                       history.CursorToEnd ();
+                       max_rendered = 0;
+                       
+                       Prompt = prompt;
+                       shown_prompt = prompt;
+                       InitText (initial);
+                       history.Append (initial);
+
+                       do {
+                               try {
+                                       EditLoop ();
+                               } catch (ThreadAbortException){
+                                       searching = 0;
+                                       Thread.ResetAbort ();
+                                       Console.WriteLine ();
+                                       SetPrompt (prompt);
+                                       SetText ("");
+                               }
+                       } while (!done);
+                       Console.WriteLine ();
+                       
+                       Console.CancelKeyPress -= InterruptEdit;
+
+                       if (text == null){
+                               history.Close ();
+                               return null;
+                       }
+
+                       string result = text.ToString ();
+                       if (result != "")
+                               history.Accept (result);
+                       else
+                               history.RemoveLast ();
+
+                       return result;
+               }
+
+               //
+               // Emulates the bash-like behavior, where edits done to the
+               // history are recorded
+               //
+               class History {
+                       string [] history;
+                       int head, tail;
+                       int cursor, count;
+                       string histfile;
+                       
+                       public History (string app, int size)
+                       {
+                               if (size < 1)
+                                       throw new ArgumentException ("size");
+
+                               if (app != null){
+                                       string dir = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
+                                       //Console.WriteLine (dir);
+                                       if (!Directory.Exists (dir)){
+                                               try {
+                                                       Directory.CreateDirectory (dir);
+                                               } catch {
+                                                       app = null;
+                                               }
+                                       }
+                                       if (app != null)
+                                               histfile = Path.Combine (dir, app) + ".history";
+                               }
+                               
+                               history = new string [size];
+                               head = tail = cursor = 0;
+
+                               if (File.Exists (histfile)){
+                                       using (StreamReader sr = File.OpenText (histfile)){
+                                               string line;
+                                               
+                                               while ((line = sr.ReadLine ()) != null){
+                                                       if (line != "")
+                                                               Append (line);
+                                               }
+                                       }
+                               }
+                       }
+
+                       public void Close ()
+                       {
+                               if (histfile == null)
+                                       return;
+
+                               try {
+                                       using (StreamWriter sw = File.CreateText (histfile)){
+                                               int start = (count == history.Length) ? head : tail;
+                                               for (int i = start; i < start+count; i++){
+                                                       int p = i % history.Length;
+                                                       sw.WriteLine (history [p]);
+                                               }
+                                       }
+                               } catch {
+                                       // ignore
+                               }
+                       }
+                       
+                       //
+                       // Appends a value to the history
+                       //
+                       public void Append (string s)
+                       {
+                               //Console.WriteLine ("APPENDING {0} {1}", s, Environment.StackTrace);
+                               history [head] = s;
+                               head = (head+1) % history.Length;
+                               if (head == tail)
+                                       tail = (tail+1 % history.Length);
+                               if (count != history.Length)
+                                       count++;
+                       }
+
+                       //
+                       // Updates the current cursor location with the string,
+                       // to support editing of history items.   For the current
+                       // line to participate, an Append must be done before.
+                       //
+                       public void Update (string s)
+                       {
+                               history [cursor] = s;
+                       }
+
+                       public void RemoveLast ()
+                       {
+                               head = head-1;
+                               if (head < 0)
+                                       head = history.Length-1;
+                       }
+                       
+                       public void Accept (string s)
+                       {
+                               int t = head-1;
+                               if (t < 0)
+                                       t = history.Length-1;
+                               
+                               history [t] = s;
+                       }
+                       
+                       public bool PreviousAvailable ()
+                       {
+                               //Console.WriteLine ("h={0} t={1} cursor={2}", head, tail, cursor);
+                               if (count == 0 || cursor == tail)
+                                       return false;
+
+                               return true;
+                       }
+
+                       public bool NextAvailable ()
+                       {
+                               int next = (cursor + 1) % history.Length;
+                               if (count == 0 || next > head)
+                                       return false;
+
+                               return true;
+                       }
+                       
+                       
+                       //
+                       // Returns: a string with the previous line contents, or
+                       // nul if there is no data in the history to move to.
+                       //
+                       public string Previous ()
+                       {
+                               if (!PreviousAvailable ())
+                                       return null;
+
+                               cursor--;
+                               if (cursor < 0)
+                                       cursor = history.Length - 1;
+
+                               return history [cursor];
+                       }
+
+                       public string Next ()
+                       {
+                               if (!NextAvailable ())
+                                       return null;
+
+                               cursor = (cursor + 1) % history.Length;
+                               return history [cursor];
+                       }
+
+                       public void CursorToEnd ()
+                       {
+                               if (head == tail)
+                                       return;
+
+                               cursor = head;
+                       }
+
+                       public void Dump ()
+                       {
+                               Console.WriteLine ("Head={0} Tail={1} Cursor={2}", head, tail, cursor);
+                               for (int i = 0; i < history.Length;i++){
+                                       Console.WriteLine (" {0} {1}: {2}", i == cursor ? "==>" : "   ", i, history[i]);
+                               }
+                               //log.Flush ();
+                       }
+
+                       public string SearchBackward (string term)
+                       {
+                               for (int i = 1; i < count; i++){
+                                       int slot = cursor-i;
+                                       if (slot < 0)
+                                               slot = history.Length-1;
+                                       if (history [slot] != null && history [slot].IndexOf (term) != -1){
+                                               cursor = slot;
+                                               return history [slot];
+                                       }
+
+                                       // Will the next hit tail?
+                                       slot--;
+                                       if (slot < 0)
+                                               slot = history.Length-1;
+                                       if (slot == tail)
+                                               break;
+                               }
+
+                               return null;
+                       }
+                       
+               }
+       }
+
+#if DEMO
+       class Demo {
+               static void Main ()
+               {
+                       LineEditor le = new LineEditor (null);
+                       string s;
+                       
+                       while ((s = le.Edit ("shell> ", "")) != null){
+                               Console.WriteLine ("----> [{0}]", s);
+                       }
+               }
+       }
+#endif
+}
+#endif
diff --git a/mcs/tools/csharp/repl.cs b/mcs/tools/csharp/repl.cs
new file mode 100644 (file)
index 0000000..e5a5b30
--- /dev/null
@@ -0,0 +1,242 @@
+//
+// repl.cs: Support for using the compiler in interactive mode (read-eval-print loop)
+//
+// Authors:
+//   Miguel de Icaza (miguel@gnome.org)
+//
+// Dual licensed under the terms of the MIT X11 or GNU GPL
+//
+// Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
+// Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
+//
+//
+// TODO:
+//   Do not print results in Evaluate, do that elsewhere in preparation for Eval refactoring.
+//   Driver.PartialReset should not reset the coretypes, nor the optional types, to avoid
+//      computing that on every call.
+//
+using System;
+using System.IO;
+using System.Text;
+using System.Globalization;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Threading;
+using Mono.CSharp;
+
+namespace Mono {
+
+       public static class CSharpShell {
+               static bool isatty = true;
+               
+               static Mono.Terminal.LineEditor editor;
+               static bool dumb;
+               static Thread invoke_thread;
+
+               static void ConsoleInterrupt (object sender, ConsoleCancelEventArgs a)
+               {
+                       // Do not about our program
+                       a.Cancel = true;
+
+                       Mono.CSharp.CSharpEvaluator.Interrupt ();
+               }
+               
+               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, "");
+                       }
+               }
+
+               delegate string ReadLiner (bool primary);
+
+               static void InitializeUsing ()
+               {
+                       Evaluate ("using System; using System.Linq; using System.Collections.Generic; using System.Collections;");
+               }
+
+               static void InitTerminal ()
+               {
+                       isatty = UnixUtils.isatty (0) && UnixUtils.isatty (1);
+
+                       // 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;
+                       SetupConsole ();
+
+                       if (isatty)
+                               Console.WriteLine ("Mono C# Shell, type \"help;\" for help\n\nEnter statements below.");
+
+               }
+
+               static void LoadStartupFiles ()
+               {
+                       string dir = Path.Combine (
+                               Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
+                               "csharp");
+                       if (!Directory.Exists (dir))
+                               return;
+
+                       foreach (string file in 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")){
+                                       CSharpEvaluator.LoadAssembly (file);
+                               }
+                       }
+               }
+
+               static void ReadEvalPrintLoopWith (ReadLiner readline)
+               {
+                       string expr = null;
+                       while (true){
+                               string input = readline (expr == null);
+                               if (input == null)
+                                       return;
+
+                               if (input == "")
+                                       continue;
+
+                               expr = expr == null ? input : expr + "\n" + input;
+                               
+                               expr = Evaluate (expr);
+                       } 
+               }
+
+               static public int ReadEvalPrintLoop ()
+               {
+                       InitTerminal ();
+
+                       InitializeUsing ();
+
+                       LoadStartupFiles ();
+                       ReadEvalPrintLoopWith (GetLine);
+
+                       return 0;
+               }
+
+               static string Evaluate (string input)
+               {
+                       bool result_set;
+                       object result;
+
+                       try {
+                               input = CSharpEvaluator.Evaluate (input, out result, out result_set);
+
+                               if (result_set){
+                                       PrettyPrint (result);
+                                       Console.WriteLine ();
+                               }
+                       } catch (Exception e){
+                               Console.WriteLine (e);
+                       }
+                       
+                       return input;
+               }
+
+               static void p (string s)
+               {
+                       Console.Write (s);
+               }
+
+               static string EscapeString (string s)
+               {
+                       return s.Replace ("\"", "\\\"");
+               }
+               
+               static void PrettyPrint (object result)
+               {
+                       if (result == null){
+                               p ("null");
+                               return;
+                       }
+                       
+                       if (result is Array){
+                               Array a = (Array) result;
+                               
+                               p ("{ ");
+                               int top = a.GetUpperBound (0);
+                               for (int i = a.GetLowerBound (0); i <= top; i++){
+                                       PrettyPrint (a.GetValue (i));
+                                       if (i != top)
+                                               p (", ");
+                               }
+                               p (" }");
+                       } else if (result is bool){
+                               if ((bool) result)
+                                       p ("true");
+                               else
+                                       p ("false");
+                       } else if (result is string){
+                               p (String.Format ("\"{0}\"", EscapeString ((string)result)));
+                       } else if (result is IDictionary){
+                               IDictionary dict = (IDictionary) result;
+                               int top = dict.Count, count = 0;
+                               
+                               p ("{");
+                               foreach (DictionaryEntry entry in dict){
+                                       count++;
+                                       p ("{ ");
+                                       PrettyPrint (entry.Key);
+                                       p (", ");
+                                       PrettyPrint (entry.Value);
+                                       if (count != top)
+                                               p (" }, ");
+                                       else
+                                               p (" }");
+                               }
+                               p ("}");
+                       } else if (result is IEnumerable) {
+                               int i = 0;
+                               p ("{ ");
+                               foreach (object item in (IEnumerable) result) {
+                                       if (i++ != 0)
+                                               p (", ");
+
+                                       PrettyPrint (item);
+                               }
+                               p (" }");
+                       } else {
+                               p (result.ToString ());
+                       }
+               }
+
+               static int Main (string [] args)
+               {
+                       try {
+                               CSharpEvaluator.Init (args);
+                       } catch {
+                               return 1;
+                       }
+                       
+                       return ReadEvalPrintLoop ();
+               }
+       }
+
+}
diff --git a/mcs/tools/csharp/repl.txt b/mcs/tools/csharp/repl.txt
new file mode 100644 (file)
index 0000000..b56a896
--- /dev/null
@@ -0,0 +1,117 @@
+Things to do for the REPL support in MCS:
+
+Documentation for the REPL mode for MCS can be found here:
+
+             http://mono-project.com/CsharpRepl
+
+* Embedding API
+
+       * Booting the compiler without Main ()
+       * Expose LoadAssembly/LoadPackage
+       * Register fields?
+       * Register a lookup function for fields?
+       * Register classes to expose to REPL
+
+* Embedded Library
+
+       * Run a REPL on a socket (from Joe Shaw)
+       * Host a REPL on XSP (from Nat).
+
+* TODO
+
+       Clear struct fields inside the clearing code.
+
+* Other ideas:
+
+       MD addin for "csharp"
+
+* Mix statements with other top-level declarations.
+
+csharp> class Y {static void Main () {Console.WriteLine ("Foo"); }}
+csharp> typeof (Y);
+Y
+csharp> Y.Main ();
+Exception caught by the compiler while compiling:
+   Block that caused the problem begin at: Internal(1,1):
+                     Block being compiled: [<interactive>(1,2):,<interactive>(1,11):]
+System.NotSupportedException: The invoked member is not supported in a dynamic module.
+Internal compiler error at Internal(1,1):: exception caught while emitting MethodBuilder [Class2::Host]
+System.NotSupportedException: The invoked member is not supported in a dynamic module.
+  at System.Reflection.Emit.AssemblyBuilder.get_Location () [0x00000] in /second/home/cvs/mcs/class/corlib/System.Reflection.Emit/AssemblyBuilder.cs:214 
+  at Mono.CSharp.Report.SymbolRelatedToPreviousError (System.Reflection.MemberInfo mi) [0x00036] in /second/home/cvs/mcs/mcs/report.cs:664 
+  at Mono.CSharp.Expression.Error_MemberLookupFailed (System.Type container_type, System.Type qualifier_type, System.Type queried_type, System.String name, System.String class_name, MemberTypes mt, BindingFlags bf) [0x00121] in /second/home/cvs/mcs/mcs/ecore.cs:857 
+  at Mono.CSharp.MemberAccess.DoResolve (Mono.CSharp.EmitContext ec, Mono.CSharp.Expression right_side) [0x00230] in /second/home/cvs/mcs/mcs/expression.cs:7426 
+  at Mono.CSharp.MemberAccess.DoResolve (Mono.CSharp.EmitContext ec) [0x00000] in /second/home/cvs/mcs/mcs/expression.cs:7494 
+  at Mono.CSharp.Expression.Resolve (Mono.CSharp.EmitContext ec, ResolveFlags flags) [0x00075] in /second/home/cvs/mcs/mcs/ecore.cs:479 
+  at Mono.CSharp.Invocation.DoResolve (Mono.CSharp.EmitContext ec) [0x0000d] in /second/home/cvs/mcs/mcs/expression.cs:4725 
+  at Mono.CSharp.Expression.Resolve (Mono.CSharp.EmitContext ec, ResolveFlags flags) [0x00075] in /second/home/cvs/mcs/mcs/ecore.cs:479 
+  at Mono.CSharp.Expression.Resolve (Mono.CSharp.EmitContext ec) [0x00000] in /second/home/cvs/mcs/mcs/ecore.cs:506 
+  at Mono.CSharp.OptionalAssign.DoResolve (Mono.CSharp.EmitContext ec) [0x00013] in /second/home/cvs/mcs/mcs/repl.cs:681 
+  at Mono.CSharp.Expression.Resolve (Mono.CSharp.EmitContext ec, ResolveFlags flags) [0x00075] in /second/home/cvs/mcs/mcs/ecore.cs:479 
+  at Mono.CSharp.Expression.Resolve (Mono.CSharp.EmitContext ec) [0x00000] in /second/home/cvs/mcs/mcs/ecore.cs:506 
+  at Mono.CSharp.ExpressionStatement.ResolveStatement (Mono.CSharp.EmitContext ec) [0x00000] in /second/home/cvs/mcs/mcs/ecore.cs:1307 
+  at Mono.CSharp.StatementExpression.Resolve (Mono.CSharp.EmitContext ec) [0x0000b] in /second/home/cvs/mcs/mcs/statement.cs:743 
+  at Mono.CSharp.Block.Resolve (Mono.CSharp.EmitContext ec) [0x000f0] in /second/home/cvs/mcs/mcs/statement.cs:2254 
+  at Mono.CSharp.ExplicitBlock.Resolve (Mono.CSharp.EmitContext ec) [0x00000] in /second/home/cvs/mcs/mcs/statement.cs:2550 
+  at Mono.CSharp.EmitContext.ResolveTopBlock (Mono.CSharp.EmitContext anonymous_method_host, Mono.CSharp.ToplevelBlock block, Mono.CSharp.Parameters ip, IMethodData md, System.Boolean& unreachable) [0x00087] in /second/home/cvs/mcs/mcs/codegen.cs:796 
+csharp>  
+
+* Another one:
+
+csharp> class X { X (){ Console.WriteLine ("Called"); } }              
+csharp> new X ();
+Exception caught by the compiler while compiling:
+   Block that caused the problem begin at: Internal(1,1):
+                     Block being compiled: [<interactive>(1,2):,<interactive>(1,10):]
+System.NotSupportedException: The invoked member is not supported in a dynamic module.
+Internal compiler error at Internal(1,1):: exception caught while emitting MethodBuilder [Class0::Host]
+System.NotSupportedException: The invoked member is not supported in a dynamic module.
+  at System.Reflection.Emit.AssemblyBuilder.get_Location () [0x00000] in /second/home/cvs/mcs/class/corlib/System.Reflection.Emit/AssemblyBuilder.cs:214 
+  at Mono.CSharp.Report.SymbolRelatedToPreviousError (System.Reflection.MemberInfo mi) [0x00036] in /second/home/cvs/mcs/mcs/report.cs:664 
+  at Mono.CSharp.Expression.Error_MemberLookupFailed (System.Type container_type, System.Type qualifier_type, System.Type queried_type, System.String name, System.String class_name, MemberTypes mt, BindingFlags bf) [0x00121] in /second/home/cvs/mcs/mcs/ecore.cs:857 
+  at Mono.CSharp.Expression.MemberLookupFinal (Mono.CSharp.EmitContext ec, System.Type qualifier_type, System.Type queried_type, System.String name, MemberTypes mt, BindingFlags bf, Location loc) [0x0002f] in /second/home/cvs/mcs/mcs/ecore.cs:804 
+  at Mono.CSharp.New.DoResolve (Mono.CSharp.EmitContext ec) [0x002ad] in /second/home/cvs/mcs/mcs/expression.cs:5486 
+  at Mono.CSharp.Expression.Resolve (Mono.CSharp.EmitContext ec, ResolveFlags flags) [0x00075] in /second/home/cvs/mcs/mcs/ecore.cs:479 
+  at Mono.CSharp.Expression.Resolve (Mono.CSharp.EmitContext ec) [0x00000] in /second/home/cvs/mcs/mcs/ecore.cs:506 
+  at Mono.CSharp.OptionalAssign.DoResolve (Mono.CSharp.EmitContext ec) [0x00013] in /second/home/cvs/mcs/mcs/repl.cs:687 
+  at Mono.CSharp.Expression.Resolve (Mono.CSharp.EmitContext ec, ResolveFlags flags) [0x00075] in /second/home/cvs/mcs/mcs/ecore.cs:479 
+  at Mono.CSharp.Expression.Resolve (Mono.CSharp.EmitContext ec) [0x00000] in /second/home/cvs/mcs/mcs/ecore.cs:506 
+  at Mono.CSharp.ExpressionStatement.ResolveStatement (Mono.CSharp.EmitContext ec) [0x00000] in /second/home/cvs/mcs/mcs/ecore.cs:1307 
+  at Mono.CSharp.StatementExpression.Resolve (Mono.CSharp.EmitContext ec) [0x0000b] in /second/home/cvs/mcs/mcs/statement.cs:743 
+  at Mono.CSharp.Block.Resolve (Mono.CSharp.EmitContext ec) [0x000f0] in /second/home/cvs/mcs/mcs/statement.cs:2254 
+  at Mono.CSharp.ExplicitBlock.Resolve (Mono.CSharp.EmitContext ec) [0x00000] in /second/home/cvs/mcs/mcs/statement.cs:2550 
+  at Mono.CSharp.EmitContext.ResolveTopBlock (Mono.CSharp.EmitContext anonymous_method_host, Mono.CSharp.ToplevelBlock block, Mono.CSharp.Parameters ip, IMethodData md, System.Boolean& unreachable) [0x00087] in /second/home/cvs/mcs/mcs/codegen.cs:796 
+csharp>  
+
+* Important: we need to replace TypeBuidlers with Types after things
+  have been emitted, or stuff like this happens:
+
+csharp> public class y  {}
+csharp> typeof (y); 
+Class1
+
+
+* Clearing data
+
+       TODO: when clearing data for variables that have been overwritten
+       we need to check for structs and clear all the fields that contain
+       reference types.
+
+* DEBATABLE: Implement auto-insert-semicolon
+
+       This is easy to implement, just retry the parse with a
+       semicolon, the question is whether this is a good idea to do
+       in the first place or not.
+
+* Tab Completion
+
+       Implement tab completion on names, variables and type lookups.
+
+       This could be implemented by having the TAB key force the
+       expression to be evaluated with a special COMPLETE token
+       at the end.
+
+       Then the various productions (one by one) would have to
+       add support for COMPLETE, and having Resolve methods be
+       aware of this.
+