Removed explicit casts
[mono.git] / mcs / mcs / eval.cs
index cd124dcc0aa0c59f00f7f6b9523872cd66b9ccfc..6782d573a406830981cd1b06a90daff32eae586c 100644 (file)
@@ -11,7 +11,7 @@
 //
 using System;
 using System.Threading;
-using System.Collections;
+using System.Collections.Generic;
 using System.Reflection;
 using System.Reflection.Emit;
 using System.IO;
@@ -37,20 +37,36 @@ namespace Mono.CSharp {
        /// </remarks>
        public class Evaluator {
 
+               enum ParseMode {
+                       // Parse silently, do not output any error messages
+                       Silent,
+
+                       // Report errors during parse
+                       ReportErrors,
+
+                       // Auto-complete, means that the tokenizer will start producing
+                       // GETCOMPLETIONS tokens when it reaches a certain point.
+                       GetCompletions
+               }
+
                static object evaluator_lock = new object ();
                
                static string current_debug_name;
                static int count;
                static Thread invoke_thread;
-               
-               static ArrayList using_alias_list = new ArrayList ();
-               static ArrayList using_list = new ArrayList ();
-               static Hashtable fields = new Hashtable ();
 
-               static Type   interactive_base_class = typeof (InteractiveBase);
+               static List<NamespaceEntry.UsingAliasEntry> using_alias_list = new List<NamespaceEntry.UsingAliasEntry> ();
+               internal static List<NamespaceEntry.UsingEntry> using_list = new List<NamespaceEntry.UsingEntry> ();
+               static Dictionary<string, Tuple<FieldSpec, FieldInfo>> fields = new Dictionary<string, Tuple<FieldSpec, FieldInfo>> ();
+
+               static TypeSpec interactive_base_class;
                static Driver driver;
                static bool inited;
 
+               static CompilerContext ctx;
+               
+               public static TextWriter MessageOutput = Console.Out;
+
                /// <summary>
                ///   Optional initialization for the Evaluator.
                /// </summary>
@@ -65,21 +81,62 @@ namespace Mono.CSharp {
                ///  interface.
                /// </remarks>
                public static void Init (string [] args)
+               {
+                       InitAndGetStartupFiles (args);
+               }
+
+               internal static ReportPrinter SetPrinter (ReportPrinter report_printer)
+               {
+                       return ctx.Report.SetPrinter (report_printer);
+               }                               
+
+               /// <summary>
+               ///   Optional initialization for the Evaluator.
+               /// </summary>
+               /// <remarks>
+               ///  Initializes the Evaluator with the command line
+               ///  options that would be processed by the command
+               ///  line compiler.  Only the first call to
+               ///  InitAndGetStartupFiles or 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.
+               ///
+               ///  This method return an array of strings that contains any
+               ///  files that were specified in `args'.
+               /// </remarks>
+               public static string [] InitAndGetStartupFiles (string [] args)
                {
                        lock (evaluator_lock){
                                if (inited)
-                                       return;
+                                       return new string [0];
                                
-                               RootContext.Version = LanguageVersion.Default;
-                               driver = Driver.Create (args, false);
+                               driver = Driver.Create (args, false, new ConsoleReportPrinter ());
                                if (driver == null)
                                        throw new Exception ("Failed to create compiler driver with the given arguments");
+
+                               RootContext.ToplevelTypes = new ModuleCompiled (ctx, true);
                                
                                driver.ProcessDefaultConfig ();
+
+                               var startup_files = new List<string> ();
+                               foreach (CompilationUnit file in Location.SourceFiles)
+                                       startup_files.Add (file.Path);
+                               
                                CompilerCallableEntryPoint.Reset ();
-                               Driver.LoadReferences ();
+                               RootContext.ToplevelTypes = new ModuleCompiled (ctx, true);
+                               /*var ctypes = */TypeManager.InitCoreTypes ();
+
+                               Import.Initialize ();
+                               driver.LoadReferences ();
+                               TypeManager.InitOptionalCoreTypes (ctx);
+
                                RootContext.EvalMode = true;
                                inited = true;
+
+                               return startup_files.ToArray ();
                        }
                }
 
@@ -91,22 +148,35 @@ namespace Mono.CSharp {
                static void Reset ()
                {
                        CompilerCallableEntryPoint.PartialReset ();
+                       RootContext.PartialReset ();
+                       
+                       // Workaround for API limitation where full message printer cannot be passed
+                       ReportPrinter printer;
+                       if (MessageOutput == Console.Out || MessageOutput == Console.Error){
+                               var console_reporter = new ConsoleReportPrinter (MessageOutput);
+                               console_reporter.Fatal = driver.fatal_errors;
+                               printer = console_reporter;
+                       } else
+                               printer = new StreamReportPrinter (MessageOutput);
+
+                       ctx = new CompilerContext (new Report (printer));
+                       RootContext.ToplevelTypes = new ModuleCompiled (ctx, true);
 
                        //
                        // PartialReset should not reset the core types, this is very redundant.
                        //
-                       if (!TypeManager.InitCoreTypes ())
-                               throw new Exception ("Failed to InitCoreTypes");
-                       TypeManager.InitOptionalCoreTypes ();
+//                     if (!TypeManager.InitCoreTypes (ctx, null))
+//                             throw new Exception ("Failed to InitCoreTypes");
+//                     TypeManager.InitOptionalCoreTypes (ctx);
                        
-                       Location.AddFile ("<interactive>");
+                       Location.AddFile (null, "{interactive}");
                        Location.Initialize ();
 
                        current_debug_name = "interactive" + (count++) + ".dll";
                        if (Environment.GetEnvironmentVariable ("SAVE") != null){
-                               CodeGen.Init (current_debug_name, current_debug_name, false);
+                               CodeGen.Init (current_debug_name, current_debug_name, false, ctx);
                        } else
-                               CodeGen.InitDynamic (current_debug_name);
+                               CodeGen.InitDynamic (ctx, current_debug_name);
                }
 
                /// <summary>
@@ -123,22 +193,26 @@ namespace Mono.CSharp {
                ///   base class and the static members that are
                ///   available to your evaluated code.
                /// </remarks>
-               static public Type InteractiveBaseClass {
+               static public TypeSpec InteractiveBaseClass {
                        get {
-                               return interactive_base_class;
+                               if (interactive_base_class != null)
+                                       return interactive_base_class;
+
+                               return Import.ImportType (typeof (InteractiveBase));
                        }
+               }
 
-                       set {
-                               if (value == null)
-                                       throw new ArgumentNullException ();
+               public static void SetInteractiveBaseClass (Type type)
+               {
+                       if (type == null)
+                               throw new ArgumentNullException ();
 
-                               lock (evaluator_lock)
-                                       interactive_base_class = value;
-                       }
+                       lock (evaluator_lock)
+                               interactive_base_class = Import.ImportType (type);
                }
 
                /// <summary>
-               ///   Interrupts the evaluation of an expression.
+               ///   Interrupts the evaluation of an expression executing in Evaluate.
                /// </summary>
                /// <remarks>
                ///   Use this method to interrupt long-running invocations.
@@ -152,6 +226,103 @@ namespace Mono.CSharp {
                                invoke_thread.Abort ();
                }
 
+               /// <summary>
+               ///   Compiles the input string and returns a delegate that represents the compiled code.
+               /// </summary>
+               /// <remarks>
+               ///
+               ///   Compiles the input string as a C# expression or
+               ///   statement, unlike the Evaluate method, the
+               ///   resulting delegate can be invoked multiple times
+               ///   without incurring in the compilation overhead.
+               ///
+               ///   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 string was partial and that the
+               ///   invoking code should provide more code before
+               ///   the code can be successfully compiled.
+               ///
+               ///   If you know that you will always get full expressions or
+               ///   statements and do not care about partial input, you can use
+               ///   the other Compile overload. 
+               ///
+               ///   On success, in addition to returning null, the
+               ///   compiled parameter will be set to the delegate
+               ///   that can be invoked to execute the code.
+               ///
+               /// </remarks>
+               static public string Compile (string input, out CompiledMethod compiled)
+               {
+                       if (input == null || input.Length == 0){
+                               compiled = null;
+                               return null;
+                       }
+                       
+                       lock (evaluator_lock){
+                               if (!inited)
+                                       Init ();
+                               
+                               bool partial_input;
+                               CSharpParser parser = ParseString (ParseMode.Silent, input, out partial_input);
+                               if (parser == null){
+                                       compiled = null;
+                                       if (partial_input)
+                                               return input;
+                                       
+                                       ParseString (ParseMode.ReportErrors, input, out partial_input);
+                                       return null;
+                               }
+                               
+                               object parser_result = parser.InteractiveResult;
+                               
+                               if (!(parser_result is Class)){
+                                       int errors = ctx.Report.Errors;
+                                       
+                                       NamespaceEntry.VerifyAllUsing ();
+                                       if (errors == ctx.Report.Errors)
+                                               parser.CurrentNamespace.Extract (using_alias_list, using_list);
+                               }
+
+                               compiled = CompileBlock (parser_result as Class, parser.undo, ctx.Report);
+                       }
+                       
+                       return null;
+               }
+
+               /// <summary>
+               ///   Compiles the input string and returns a delegate that represents the compiled code.
+               /// </summary>
+               /// <remarks>
+               ///
+               ///   Compiles the input string as a C# expression or
+               ///   statement, unlike the Evaluate method, the
+               ///   resulting delegate can be invoked multiple times
+               ///   without incurring in the compilation overhead.
+               ///
+               ///   This method can only deal with fully formed input
+               ///   strings and does not provide a completion mechanism.
+               ///   If you must deal with partial input (for example for
+               ///   interactive use) use the other overload. 
+               ///
+               ///   On success, a delegate is returned that can be used
+               ///   to invoke the method.
+               ///
+               /// </remarks>
+               static public CompiledMethod Compile (string input)
+               {
+                       CompiledMethod compiled;
+
+                       // Ignore partial inputs
+                       if (Compile (input, out compiled) != null){
+                               // Error, the input was partial.
+                               return null;
+                       }
+
+                       // Either null (on error) or the compiled method.
+                       return compiled;
+               }
+
                //
                // Todo: Should we handle errors, or expect the calling code to setup
                // the recording themselves?
@@ -181,43 +352,108 @@ namespace Mono.CSharp {
                /// </remarks>
                public static string Evaluate (string input, out object result, out bool result_set)
                {
-                       lock (evaluator_lock){
-                               result_set = false;
-                               result = null;
-                               
-                               if (input == null || input.Length == 0)
-                                       return null;
+                       CompiledMethod compiled;
+
+                       result_set = false;
+                       result = null;
+
+                       input = Compile (input, out compiled);
+                       if (input != null)
+                               return input;
+                       
+                       if (compiled == null)
+                               return null;
                                
+                       //
+                       // The code execution does not need to keep the compiler lock
+                       //
+                       object retval = typeof (NoValueSet);
+
+                       try {
+                               invoke_thread = System.Threading.Thread.CurrentThread;
+                               invoking = true;
+                               compiled (ref retval);
+                       } catch (ThreadAbortException e){
+                               Thread.ResetAbort ();
+                               Console.WriteLine ("Interrupted!\n{0}", e);
+                       } finally {
+                               invoking = false;
+                       }
+
+                       //
+                       // We use a reference to a compiler type, in this case
+                       // Driver as a flag to indicate that this was a statement
+                       //
+                       if (retval != typeof (NoValueSet)){
+                               result_set = true;
+                               result = retval; 
+                       }
+
+                       return null;
+               }
+
+               public static string [] GetCompletions (string input, out string prefix)
+               {
+                       prefix = "";
+                       if (input == null || input.Length == 0)
+                               return null;
+                       
+                       lock (evaluator_lock){
                                if (!inited)
                                        Init ();
                                
                                bool partial_input;
-                               CSharpParser parser = ParseString (true, input, out partial_input);
+                               CSharpParser parser = ParseString (ParseMode.GetCompletions, input, out partial_input);
                                if (parser == null){
-                                       if (partial_input)
-                                               return input;
-                                       
-                                       ParseString (false, input, out partial_input);
+                                       if (CSharpParser.yacc_verbose_flag != 0)
+                                               Console.WriteLine ("DEBUG: No completions available");
                                        return null;
                                }
                                
-                               object parser_result = parser.InteractiveResult;
-                               
-                               if (!(parser_result is Class))
-                                       parser.CurrentNamespace.Extract (using_alias_list, using_list);
+                               Class parser_result = parser.InteractiveResult as Class;
                                
-                               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;
+                               if (parser_result == null){
+                                       if (CSharpParser.yacc_verbose_flag != 0)
+                                               Console.WriteLine ("Do not know how to cope with !Class yet");
+                                       return null;
+                               }
+
+                               try {
+                                       RootContext.ResolveTree ();
+                                       if (ctx.Report.Errors != 0)
+                                               return null;
+                                       
+                                       RootContext.PopulateTypes ();
+                                       if (ctx.Report.Errors != 0)
+                                               return null;
+
+                                       MethodOrOperator method = null;
+                                       foreach (MemberCore member in parser_result.Methods){
+                                               if (member.Name != "Host")
+                                                       continue;
+                                               
+                                               method = (MethodOrOperator) member;
+                                               break;
+                                       }
+                                       if (method == null)
+                                               throw new InternalErrorException ("did not find the the Host method");
+
+                                       BlockContext bc = new BlockContext (method, method.Block, method.ReturnType);
+
+                                       try {
+                                               method.Block.Resolve (null, bc, method.ParameterInfo, method);
+                                       } catch (CompletionResult cr){
+                                               prefix = cr.BaseText;
+                                               return cr.Result;
+                                       } 
+                               } finally {
+                                       parser.undo.ExecuteUndo ();
+                               }
                                
-                               return null;
                        }
+                       return null;
                }
-                       
+               
                /// <summary>
                ///   Executes the given expression or statement.
                /// </summary>
@@ -264,7 +500,7 @@ namespace Mono.CSharp {
 
                        return result;
                }
-               
+       
                enum InputKind {
                        EOF,
                        StatementOrExpression,
@@ -284,7 +520,7 @@ namespace Mono.CSharp {
                //
                static InputKind ToplevelOrStatement (SeekableStreamReader seekable)
                {
-                       Tokenizer tokenizer = new Tokenizer (seekable, Location.SourceFiles [0]);
+                       Tokenizer tokenizer = new Tokenizer (seekable, (CompilationUnit) Location.SourceFiles [0], ctx);
                        
                        int t = tokenizer.token ();
                        switch (t){
@@ -386,25 +622,26 @@ namespace Mono.CSharp {
                // @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)
+               static CSharpParser ParseString (ParseMode mode, string input, out bool partial_input)
                {
                        partial_input = false;
                        Reset ();
                        queued_fields.Clear ();
+                       Tokenizer.LocatedToken.Initialize ();
 
                        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");
+                               if (mode == ParseMode.ReportErrors)
+                                       ctx.Report.Error (-25, "Detection Parsing Error");
                                partial_input = false;
                                return null;
                        }
 
                        if (kind == InputKind.EOF){
-                               if (silent == false)
+                               if (mode == ParseMode.ReportErrors)
                                        Console.Error.WriteLine ("Internal error: EOF condition should have been detected in a previous call with silent=true");
                                partial_input = true;
                                return null;
@@ -412,8 +649,7 @@ namespace Mono.CSharp {
                        }
                        seekable.Position = 0;
 
-                       CSharpParser parser = new CSharpParser (seekable, Location.SourceFiles [0]);
-                       parser.ErrorOutput = Report.Stderr;
+                       CSharpParser parser = new CSharpParser (seekable, (CompilationUnit) Location.SourceFiles [0], ctx);
 
                        if (kind == InputKind.StatementOrExpression){
                                parser.Lexer.putback_char = Tokenizer.EvalStatementParserCharacter;
@@ -429,51 +665,54 @@ namespace Mono.CSharp {
                                RootContext.StatementMode = false;
                        }
 
-                       if (silent)
-                               Report.DisableReporting ();
+                       if (mode == ParseMode.GetCompletions)
+                               parser.Lexer.CompleteOnEOF = true;
+
+                       ReportPrinter old_printer = null;
+                       if ((mode == ParseMode.Silent || mode == ParseMode.GetCompletions) && CSharpParser.yacc_verbose_flag == 0)
+                               old_printer = SetPrinter (new StreamReportPrinter (TextWriter.Null));
+
                        try {
                                parser.parse ();
                        } finally {
-                               if (Report.Errors != 0){
-                                       if (silent && parser.UnexpectedEOF)
+                               if (ctx.Report.Errors != 0){
+                                       if (mode != ParseMode.ReportErrors  && parser.UnexpectedEOF)
                                                partial_input = true;
 
                                        parser.undo.ExecuteUndo ();
                                        parser = null;
                                }
 
-                               if (silent)
-                                       Report.EnableReporting ();
+                               if (old_printer != null)
+                                       SetPrinter (old_printer);
                        }
                        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 List<Field> queued_fields = new List<Field> ();
                
                //static ArrayList types = new ArrayList ();
 
                static volatile bool invoking;
                
-               static object ExecuteBlock (Class host, Undo undo)
+               static CompiledMethod CompileBlock (Class host, Undo undo, Report Report)
                {
                        RootContext.ResolveTree ();
                        if (Report.Errors != 0){
                                undo.ExecuteUndo ();
-                               return typeof (NoValueSet);
+                               return null;
                        }
                        
                        RootContext.PopulateTypes ();
 
                        if (Report.Errors != 0){
                                undo.ExecuteUndo ();
-                               return typeof (NoValueSet);
+                               return null;
                        }
 
                        TypeBuilder tb = null;
@@ -496,70 +735,58 @@ namespace Mono.CSharp {
                        }
                        
                        RootContext.EmitCode ();
-                       if (Report.Errors != 0)
-                               return typeof (NoValueSet);
+                       if (Report.Errors != 0){
+                               undo.ExecuteUndo ();
+                               return null;
+                       }
                        
                        RootContext.CloseTypes ();
 
                        if (Environment.GetEnvironmentVariable ("SAVE") != null)
-                               CodeGen.Save (current_debug_name, false);
+                               CodeGen.Save (current_debug_name, false, Report);
 
                        if (host == null)
-                               return typeof (NoValueSet);
+                               return null;
                        
                        //
                        // 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);
+                       var 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];
+
+                               Tuple<FieldSpec, FieldInfo> old;
                                
                                // If a previous value was set, nullify it, so that we do
                                // not leak memory
-                               if (old != null){
-                                       if (old.FieldType.IsValueType){
+                               if (fields.TryGetValue (field.Name, out old)) {
+                                       if (old.Item1.MemberType.IsStruct) {
                                                //
                                                // TODO: Clear fields for structs
                                                //
                                        } else {
                                                try {
-                                                       old.SetValue (null, null);
+                                                       old.Item2.SetValue (null, null);
                                                } catch {
                                                }
                                        }
+
+                                       fields [field.Name] = Tuple.Create (old.Item1, fi);
+                               } else {
+                                       fields.Add (field.Name, Tuple.Create (field.Spec, fi));
                                }
-                               
-                               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;
+                       return (CompiledMethod) System.Delegate.CreateDelegate (typeof (CompiledMethod), mi);
                }
-
+               
                static internal void LoadAliases (NamespaceEntry ns)
                {
                        ns.Populate (using_alias_list, using_list);
@@ -574,10 +801,10 @@ namespace Mono.CSharp {
                public class NoValueSet {
                }
 
-               static internal FieldInfo LookupField (string name)
+               static internal Tuple<FieldSpec, FieldInfo> LookupField (string name)
                {
-                       FieldInfo fi =  (FieldInfo) fields [name];
-
+                       Tuple<FieldSpec, FieldInfo> fi;
+                       fields.TryGetValue (name, out fi);
                        return fi;
                }
 
@@ -620,30 +847,39 @@ namespace Mono.CSharp {
                        }
                }
 
+               static internal ICollection<string> GetUsingList ()
+               {
+                       var res = new List<string> (using_list.Count);
+                       foreach (object ue in using_list)
+                               res.Add (ue.ToString ());
+                       return res;
+               }
+               
+               static internal string [] GetVarNames ()
+               {
+                       lock (evaluator_lock){
+                               return new List<string> (fields.Keys).ToArray ();
+                       }
+               }
+               
                static public string GetVars ()
                {
                        lock (evaluator_lock){
                                StringBuilder sb = new StringBuilder ();
                                
-                               foreach (DictionaryEntry de in fields){
-                                       FieldInfo fi = LookupField ((string) de.Key);
-                                       object value = null;
-                                       bool error = false;
-                                       
+                               foreach (var de in fields){
+                                       var fi = LookupField (de.Key);
+                                       object value;
                                        try {
-                                               if (value == null)
-                                                       value = "null";
-                                               value = fi.GetValue (null);
+                                               value = fi.Item2.GetValue (null);
                                                if (value is string)
                                                        value = Quote ((string)value);
                                        } catch {
-                                               error = true;
+                                               value = "<error reading value>";
                                        }
-                                       
-                                       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));
+
+                                       sb.AppendFormat ("{0} {1} = {2}", fi.Item1.MemberType.GetSignatureForError (), de.Key, value);
+                                       sb.AppendLine ();
                                }
                                
                                return sb.ToString ();
@@ -656,8 +892,8 @@ namespace Mono.CSharp {
                static public void LoadAssembly (string file)
                {
                        lock (evaluator_lock){
-                               Driver.LoadAssembly (file, true);
-                               RootNamespace.ComputeNamespaces ();
+                               driver.LoadAssembly (file, false);
+                               GlobalRootNamespace.Instance.ComputeNamespaces (ctx);
                        }
                }
 
@@ -667,28 +903,82 @@ namespace Mono.CSharp {
                static public void ReferenceAssembly (Assembly a)
                {
                        lock (evaluator_lock){
-                               RootNamespace.Global.AddAssemblyReference (a);
-                               RootNamespace.ComputeNamespaces ();
+//                             GlobalRootNamespace.Instance.AddAssemblyReference (a);
+//                             GlobalRootNamespace.Instance.ComputeNamespaces (ctx);
+                               GlobalRootNamespace.Instance.ImportAssembly (a);
                        }
                }
-               
+
+               /// <summary>
+               ///   If true, turns type expressions into valid expressions
+               ///   and calls the describe method on it
+               /// </summary>
+               public static bool DescribeTypeExpressions;
        }
 
+       
+       /// <summary>
+       ///   A delegate that can be used to invoke the
+       ///   compiled expression or statement.
+       /// </summary>
+       /// <remarks>
+       ///   Since the Compile methods will compile
+       ///   statements and expressions into the same
+       ///   delegate, you can tell if a value was returned
+       ///   by checking whether the returned value is of type
+       ///   NoValueSet.   
+       /// </remarks>
+       
+       public delegate void CompiledMethod (ref object retvalue);
+
        /// <summary>
        ///   The default base class for every interaction line
        /// </summary>
+       /// <remarks>
+       ///   The expressions and statements behave as if they were
+       ///   a static method of this class.   The InteractiveBase class
+       ///   contains a number of useful methods, but can be overwritten
+       ///   by setting the InteractiveBaseType property in the Evaluator
+       /// </remarks>
        public class InteractiveBase {
+               /// <summary>
+               ///   Determines where the standard output of methods in this class will go. 
+               /// </summary>
                public static TextWriter Output = Console.Out;
+
+               /// <summary>
+               ///   Determines where the standard error of methods in this class will go. 
+               /// </summary>
                public static TextWriter Error = Console.Error;
+
+               /// <summary>
+               ///   The primary prompt used for interactive use.
+               /// </summary>
                public static string Prompt             = "csharp> ";
+
+               /// <summary>
+               ///   The secondary prompt used for interactive use (used when
+               ///   an expression is incomplete).
+               /// </summary>
                public static string ContinuationPrompt = "      > ";
 
+               /// <summary>
+               ///   Used to signal that the user has invoked the  `quit' statement.
+               /// </summary>
+               public static bool QuitRequested;
+               
+               /// <summary>
+               ///   Shows all the variables defined so far.
+               /// </summary>
                static public void ShowVars ()
                {
                        Output.Write (Evaluator.GetVars ());
                        Output.Flush ();
                }
 
+               /// <summary>
+               ///   Displays the using statements in effect at this point. 
+               /// </summary>
                static public void ShowUsing ()
                {
                        Output.Write (Evaluator.GetUsing ());
@@ -697,6 +987,9 @@ namespace Mono.CSharp {
 
                public delegate void Simple ();
                
+               /// <summary>
+               ///   Times the execution of the given delegate
+               /// </summary>
                static public TimeSpan Time (Simple a)
                {
                        DateTime start = DateTime.Now;
@@ -705,6 +998,14 @@ namespace Mono.CSharp {
                }
                
 #if !SMCS_SOURCE
+               /// <summary>
+               ///   Loads the assemblies from a package
+               /// </summary>
+               /// <remarks>
+               ///   Loads the assemblies from a package.   This is equivalent
+               ///   to passing the -pkg: command line flag to the C# compiler
+               ///   on the command line. 
+               /// </remarks>
                static public void LoadPackage (string pkg)
                {
                        if (pkg == null){
@@ -712,7 +1013,7 @@ namespace Mono.CSharp {
                                return;
                        }
 
-                       string pkgout = Driver.GetPackageFlags (pkg, false);
+                       string pkgout = Driver.GetPackageFlags (pkg, false, RootContext.ToplevelTypes.Compiler.Report);
                        if (pkgout == null)
                                return;
 
@@ -730,32 +1031,72 @@ namespace Mono.CSharp {
                }
 #endif
 
+               /// <summary>
+               ///   Loads the assembly
+               /// </summary>
+               /// <remarks>
+               ///   Loads the specified assembly and makes its types
+               ///   available to the evaluator.  This is equivalent
+               ///   to passing the -pkg: command line flag to the C#
+               ///   compiler on the command line.
+               /// </remarks>
                static public void LoadAssembly (string assembly)
                {
                        Evaluator.LoadAssembly (assembly);
                }
                
+               /// <summary>
+               ///   Returns a list of available static methods. 
+               /// </summary>
                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";
+                               return "Static methods:\n" +
+                                       "  Describe (object)       - Describes the object's type\n" +
+                                       "  LoadPackage (package);  - Loads the given Package (like -pkg:FILE)\n" +
+                                       "  LoadAssembly (assembly) - Loads the given assembly (like -r:ASSEMBLY)\n" +
+                                       "  ShowVars ();            - Shows defined local variables.\n" +
+                                       "  ShowUsing ();           - Show active using declarations.\n" +
+                                       "  Prompt                  - The prompt used by the C# shell\n" +
+                                       "  ContinuationPrompt      - The prompt for partial input\n" +
+                                       "  Time(() -> { })         - Times the specified code\n" +
+                                       "  quit;                   - You'll never believe it - this quits the repl!\n" +
+                                       "  help;                   - This help text\n";
                        }
                }
 
+               /// <summary>
+               ///   Indicates to the read-eval-print-loop that the interaction should be finished. 
+               /// </summary>
                static public object quit {
                        get {
-                               Environment.Exit (0);
+                               QuitRequested = true;
                                return null;
                        }
                }
+
+#if !NET_2_1
+               /// <summary>
+               ///   Describes an object or a type.
+               /// </summary>
+               /// <remarks>
+               ///   This method will show a textual representation
+               ///   of the object's type.  If the object is a
+               ///   System.Type it renders the type directly,
+               ///   otherwise it renders the type returned by
+               ///   invoking GetType on the object.
+               /// </remarks>
+               static public string Describe (object x)
+               {
+                       if (x == null)
+                               return "<null>";
+
+                       var type = x as Type ?? x.GetType ();
+
+                       StringWriter sw = new StringWriter ();
+                       new Outline (type, sw, true, false, false).OutlineType ();
+                       return sw.ToString ();
+               }
+#endif
        }
 
        //
@@ -770,8 +1111,8 @@ namespace Mono.CSharp {
                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)
+               public LocalVariableReferenceWithClassSideEffect (TypeContainer container, string name, Block current_block, string local_variable_id, LocalInfo li, Location loc)
+                       : base (current_block, local_variable_id, loc, li, false)
                {
                        this.container = container;
                        this.name = name;
@@ -794,7 +1135,7 @@ namespace Mono.CSharp {
                        return name.GetHashCode ();
                }
                
-               override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+               override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
                {
                        Expression ret = base.DoResolveLValue (ec, right_side);
                        if (ret == null)
@@ -802,7 +1143,7 @@ namespace Mono.CSharp {
 
                        Field f = new Field (container, new TypeExpression (ret.Type, Location),
                                             Modifiers.PUBLIC | Modifiers.STATIC,
-                                            name, null, Location);
+                                            new MemberName (name, Location), null);
                        container.AddField (f);
                        if (f.Define ())
                                Evaluator.QueueField (f);
@@ -823,15 +1164,39 @@ namespace Mono.CSharp {
                {
                }
 
-               public override Expression DoResolve (EmitContext ec)
+               protected override Expression DoResolve (ResolveContext ec)
                {
                        CloneContext cc = new CloneContext ();
                        Expression clone = source.Clone (cc);
 
-                       clone = clone.Resolve (ec);
-                       if (clone == null)
-                               return null;
-
+                       //
+                       // A useful feature for the REPL: if we can resolve the expression
+                       // as a type, Describe the type;
+                       //
+                       if (Evaluator.DescribeTypeExpressions){
+                               var old_printer = Evaluator.SetPrinter (new StreamReportPrinter (TextWriter.Null));
+                               clone = clone.Resolve (ec);
+                               if (clone == null){
+                                       clone = source.Clone (cc);
+                                       clone = clone.Resolve (ec, ResolveFlags.Type);
+                                       if (clone == null){
+                                               Evaluator.SetPrinter (old_printer);
+                                               clone = source.Clone (cc);
+                                               clone = clone.Resolve (ec);
+                                               return null;
+                                       }
+                                       
+                                       Arguments args = new Arguments (1);
+                                       args.Add (new Argument (new TypeOf ((TypeExpr) clone, Location)));
+                                       source = new Invocation (new SimpleName ("Describe", Location), args).Resolve (ec);
+                               }
+                               Evaluator.SetPrinter (old_printer);
+                       } else {
+                               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);
@@ -862,11 +1227,11 @@ namespace Mono.CSharp {
        }
 
        public class Undo {
-               ArrayList undo_types;
+               List<KeyValuePair<TypeContainer, TypeContainer>> undo_types;
                
                public Undo ()
                {
-                       undo_types = new ArrayList ();
+                       undo_types = new List<KeyValuePair<TypeContainer, TypeContainer>> ();
                }
 
                public void AddTypeContainer (TypeContainer current_container, TypeContainer tc)
@@ -875,10 +1240,11 @@ namespace Mono.CSharp {
                                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));
+                               undo_types = new List<KeyValuePair<TypeContainer, TypeContainer>> ();
+
+                       undo_types.Add (new KeyValuePair<TypeContainer, TypeContainer> (current_container, tc));
                }
 
                public void ExecuteUndo ()
@@ -886,14 +1252,14 @@ namespace Mono.CSharp {
                        if (undo_types == null)
                                return;
 
-                       foreach (Pair p in undo_types){
-                               TypeContainer current_container = (TypeContainer) p.First;
+                       foreach (var p in undo_types){
+                               TypeContainer current_container = p.Key;
 
-                               current_container.RemoveTypeContainer ((TypeContainer) p.Second);
+                               current_container.RemoveTypeContainer (p.Value);
                        }
                        undo_types = null;
                }
        }
        
 }
-       
\ No newline at end of file
+