Less static is good for my health
[mono.git] / mcs / mcs / eval.cs
index 737307666b43ab9775be4e84c315172c0ca52afa..121e61b1d96deea41a4288594b88723b6698e08d 100644 (file)
@@ -9,16 +9,18 @@
 // 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.Collections.Generic;
 using System.Reflection;
 using System.Reflection.Emit;
 using System.IO;
-using System.Globalization;
 using System.Text;
+using System.Linq;
 
-namespace Mono.CSharp {
+namespace Mono.CSharp
+{
 
        /// <summary>
        ///   Evaluator: provides an API to evaluate C# statements and
@@ -54,15 +56,19 @@ namespace Mono.CSharp {
                static string current_debug_name;
                static int count;
                static Thread invoke_thread;
-               
-               static ArrayList using_alias_list = new ArrayList ();
-               internal static ArrayList using_list = new ArrayList ();
-               static Hashtable fields = new Hashtable ();
 
-               static Type   interactive_base_class = typeof (InteractiveBase);
+               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;
+               static DynamicLoader loader;
+               static NamespaceEntry ns;
+               
+               public static TextWriter MessageOutput = Console.Out;
+
                /// <summary>
                ///   Optional initialization for the Evaluator.
                /// </summary>
@@ -81,6 +87,15 @@ namespace Mono.CSharp {
                        InitAndGetStartupFiles (args);
                }
 
+               internal static ReportPrinter SetPrinter (ReportPrinter report_printer)
+               {
+                       return ctx.Report.SetPrinter (report_printer);
+               }                               
+
+               public static string [] InitAndGetStartupFiles (string [] args)
+               {
+                       return InitAndGetStartupFiles (args, null);
+               }
 
                /// <summary>
                ///   Optional initialization for the Evaluator.
@@ -98,29 +113,54 @@ namespace Mono.CSharp {
                ///
                ///  This method return an array of strings that contains any
                ///  files that were specified in `args'.
+               ///
+               ///  If the unknownOptionParser is not null, this function is invoked
+               ///  with the current args array and the index of the option that is not
+               ///  known.  A value of true means that the value was processed, otherwise
+               ///  it will be reported as an error
                /// </remarks>
-               public static string [] InitAndGetStartupFiles (string [] args)
+               public static string [] InitAndGetStartupFiles (string [] args, Func<string [], int, int> unknownOptionParser)
                {
                        lock (evaluator_lock){
                                if (inited)
                                        return new string [0];
-                               
-                               driver = Driver.Create (args, false);
-                               if (driver == null)
+
+                               CompilerCallableEntryPoint.Reset ();
+                               var r = new Report (new ConsoleReportPrinter ());
+                               var cmd = new CommandLineParser (r);
+                               if (unknownOptionParser != null)
+                                       cmd.UnknownOptionHandler += unknownOptionParser;
+
+                               var settings = cmd.ParseArguments (args);
+
+                               // TODO: Should use ReportPrinter with throw instead of this
+                               if (settings == null || r.Errors > 0)
                                        throw new Exception ("Failed to create compiler driver with the given arguments");
-                               
-                               driver.ProcessDefaultConfig ();
 
-                               ArrayList startup_files = new ArrayList ();
+                               ctx = new CompilerContext (settings, r) {
+                                       IsEvalutor = true
+                               };
+
+                               RootContext.ToplevelTypes = new ModuleContainer (ctx);
+                               
+                               var startup_files = new List<string> ();
                                foreach (CompilationUnit file in Location.SourceFiles)
                                        startup_files.Add (file.Path);
                                
-                               CompilerCallableEntryPoint.Reset ();
-                               driver.LoadReferences ();
-                               RootContext.EvalMode = true;
+                               CompilerCallableEntryPoint.PartialReset ();
+
+                               var importer = new ReflectionImporter (ctx.BuildinTypes);
+                               loader = new DynamicLoader (importer, ctx);
+
+                               RootContext.ToplevelTypes.SetDeclaringAssembly (new AssemblyDefinitionDynamic (RootContext.ToplevelTypes, "temp"));
+
+                               loader.LoadReferences (RootContext.ToplevelTypes);
+                               ctx.BuildinTypes.CheckDefinitions (RootContext.ToplevelTypes);
+                               RootContext.ToplevelTypes.InitializePredefinedTypes ();
+
                                inited = true;
 
-                               return (string []) startup_files.ToArray (typeof (string));
+                               return startup_files.ToArray ();
                        }
                }
 
@@ -132,22 +172,11 @@ namespace Mono.CSharp {
                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.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);
-                       } else
-                               CodeGen.InitDynamic (current_debug_name);
                }
 
                /// <summary>
@@ -164,18 +193,25 @@ 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 loader.Importer.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;
-                       }
+                       if (!inited)
+                               throw new Exception ("Evaluator has to be initiated before seting custom InteractiveBase class");
+
+                       lock (evaluator_lock)
+                               interactive_base_class = loader.Importer.ImportType (type);
                }
 
                /// <summary>
@@ -225,11 +261,15 @@ namespace Mono.CSharp {
                                compiled = null;
                                return null;
                        }
-                       
+
                        lock (evaluator_lock){
                                if (!inited)
                                        Init ();
-                               
+                               else
+                                       ctx.Report.Printer.Reset ();
+
+                       //      RootContext.ToplevelTypes = new ModuleContainer (ctx);
+
                                bool partial_input;
                                CSharpParser parser = ParseString (ParseMode.Silent, input, out partial_input);
                                if (parser == null){
@@ -241,20 +281,14 @@ namespace Mono.CSharp {
                                        return null;
                                }
                                
-                               object parser_result = parser.InteractiveResult;
-                               
-                               if (!(parser_result is Class)){
-                                       int errors = Report.Errors;
-                                       
-                                       NamespaceEntry.VerifyAllUsing ();
-                                       if (errors == Report.Errors)
-                                               parser.CurrentNamespace.Extract (using_alias_list, using_list);
-                               }
-
-                               compiled = CompileBlock (parser_result as Class, parser.undo);
+#if STATIC
+                               throw new NotSupportedException ();
+#else
+                               Class parser_result = parser.InteractiveResult;
+                               compiled = CompileBlock (parser_result, parser.undo, ctx.Report);
+                               return null;
+#endif
                        }
-                       
-                       return null;
                }
 
                /// <summary>
@@ -289,7 +323,7 @@ namespace Mono.CSharp {
                        // 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?
@@ -335,7 +369,7 @@ namespace Mono.CSharp {
                        // The code execution does not need to keep the compiler lock
                        //
                        object retval = typeof (NoValueSet);
-                       
+
                        try {
                                invoke_thread = System.Threading.Thread.CurrentThread;
                                invoking = true;
@@ -377,23 +411,20 @@ namespace Mono.CSharp {
                                        return null;
                                }
                                
-                               Class parser_result = parser.InteractiveResult as Class;
-                               
-                               if (parser_result == null){
-                                       if (CSharpParser.yacc_verbose_flag != 0)
-                                               Console.WriteLine ("Do not know how to cope with !Class yet");
-                                       return null;
-                               }
+                               Class parser_result = parser.InteractiveResult;
 
                                try {
-                                       RootContext.ResolveTree ();
-                                       if (Report.Errors != 0)
+                                       var a = new AssemblyDefinitionDynamic (RootContext.ToplevelTypes, "temp");
+                                       a.Create (AppDomain.CurrentDomain, AssemblyBuilderAccess.Run);
+                                       RootContext.ToplevelTypes.SetDeclaringAssembly (a);
+                                       RootContext.ToplevelTypes.CreateType ();
+                                       RootContext.ToplevelTypes.Define ();
+
+                                       parser_result.CreateType ();
+                                       parser_result.Define ();
+                                       if (ctx.Report.Errors != 0)
                                                return null;
                                        
-                                       RootContext.PopulateTypes ();
-                                       if (Report.Errors != 0)
-                                               return null;
-
                                        MethodOrOperator method = null;
                                        foreach (MemberCore member in parser_result.Methods){
                                                if (member.Name != "Host")
@@ -408,19 +439,20 @@ namespace Mono.CSharp {
                                        BlockContext bc = new BlockContext (method, method.Block, method.ReturnType);
 
                                        try {
-                                               method.Block.Resolve (null, bc, method.ParameterInfo, method);
+                                               method.Block.Resolve (null, bc, method);
                                        } catch (CompletionResult cr){
                                                prefix = cr.BaseText;
                                                return cr.Result;
-                                       }
+                                       } 
                                } finally {
-                                       parser.undo.ExecuteUndo ();
+                                       if (parser.undo != null)
+                                               parser.undo.ExecuteUndo ();
                                }
                                
                        }
                        return null;
                }
-               
+
                /// <summary>
                ///   Executes the given expression or statement.
                /// </summary>
@@ -467,7 +499,7 @@ namespace Mono.CSharp {
 
                        return result;
                }
-       
+
                enum InputKind {
                        EOF,
                        StatementOrExpression,
@@ -487,7 +519,7 @@ namespace Mono.CSharp {
                //
                static InputKind ToplevelOrStatement (SeekableStreamReader seekable)
                {
-                       Tokenizer tokenizer = new Tokenizer (seekable, (CompilationUnit) Location.SourceFiles [0]);
+                       Tokenizer tokenizer = new Tokenizer (seekable, (CompilationUnit) Location.SourceFiles [0], ctx);
                        
                        int t = tokenizer.token ();
                        switch (t){
@@ -594,6 +626,7 @@ namespace Mono.CSharp {
                        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);
@@ -601,7 +634,7 @@ namespace Mono.CSharp {
                        InputKind kind = ToplevelOrStatement (seekable);
                        if (kind == InputKind.Error){
                                if (mode == ParseMode.ReportErrors)
-                                       Report.Error (-25, "Detection Parsing Error");
+                                       ctx.Report.Error (-25, "Detection Parsing Error");
                                partial_input = false;
                                return null;
                        }
@@ -615,47 +648,41 @@ namespace Mono.CSharp {
                        }
                        seekable.Position = 0;
 
-                       CSharpParser parser = new CSharpParser (seekable, (CompilationUnit) Location.SourceFiles [0]);
-                       parser.ErrorOutput = Report.Stderr;
+                       if (ns == null)
+                               ns = new NamespaceEntry (RootContext.ToplevelTypes, null, Location.SourceFiles[0], null);
+
+                       CSharpParser parser = new CSharpParser (seekable, Location.SourceFiles [0], RootContext.ToplevelTypes, ns);
 
                        if (kind == InputKind.StatementOrExpression){
                                parser.Lexer.putback_char = Tokenizer.EvalStatementParserCharacter;
-                               RootContext.StatementMode = true;
+                               ctx.Settings.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;
+                               parser.Lexer.putback_char = Tokenizer.EvalCompilationUnitParserCharacter;
+                               ctx.Settings.StatementMode = false;
                        }
 
                        if (mode == ParseMode.GetCompletions)
                                parser.Lexer.CompleteOnEOF = true;
 
-                       bool disable_error_reporting;
+                       ReportPrinter old_printer = null;
                        if ((mode == ParseMode.Silent || mode == ParseMode.GetCompletions) && CSharpParser.yacc_verbose_flag == 0)
-                               disable_error_reporting = true;
-                       else
-                               disable_error_reporting = false;
-                       
-                       if (disable_error_reporting)
-                               Report.DisableReporting ();
+                               old_printer = SetPrinter (new StreamReportPrinter (TextWriter.Null));
+
                        try {
                                parser.parse ();
                        } finally {
-                               if (Report.Errors != 0){
+                               if (ctx.Report.Errors != 0){
                                        if (mode != ParseMode.ReportErrors  && parser.UnexpectedEOF)
                                                partial_input = true;
 
-                                       parser.undo.ExecuteUndo ();
+                                       if (parser.undo != null)
+                                               parser.undo.ExecuteUndo ();
+
                                        parser = null;
                                }
 
-                               if (disable_error_reporting)
-                                       Report.EnableReporting ();
+                               if (old_printer != null)
+                                       SetPrinter (old_printer);
                        }
                        return parser;
                }
@@ -665,24 +692,44 @@ namespace Mono.CSharp {
                // 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 CompiledMethod CompileBlock (Class host, Undo undo)
+#if !STATIC            
+               static CompiledMethod CompileBlock (Class host, Undo undo, Report Report)
                {
-                       RootContext.ResolveTree ();
-                       if (Report.Errors != 0){
-                               undo.ExecuteUndo ();
-                               return null;
+                       AssemblyDefinitionDynamic assembly;
+                       AssemblyBuilderAccess access;
+
+                       if (Environment.GetEnvironmentVariable ("SAVE") != null) {
+                               access = AssemblyBuilderAccess.RunAndSave;
+                               assembly = new AssemblyDefinitionDynamic (RootContext.ToplevelTypes, current_debug_name, current_debug_name);
+                               assembly.Importer = loader.Importer;
+                       } else {
+#if NET_4_0
+                               access = AssemblyBuilderAccess.RunAndCollect;
+#else
+                               access = AssemblyBuilderAccess.Run;
+#endif
+                               assembly = new AssemblyDefinitionDynamic (RootContext.ToplevelTypes, current_debug_name);
                        }
-                       
-                       RootContext.PopulateTypes ();
+
+                       assembly.Create (AppDomain.CurrentDomain, access);
+
+                       if (host != null) {
+                               host.CreateType ();
+                               host.Define ();
+                       }
+
+                       RootContext.ToplevelTypes.CreateType ();
+                       RootContext.ToplevelTypes.Define ();
 
                        if (Report.Errors != 0){
-                               undo.ExecuteUndo ();
+                               if (undo != null)
+                                       undo.ExecuteUndo ();
+
                                return null;
                        }
 
@@ -703,16 +750,23 @@ namespace Mono.CSharp {
 
                                if (mb == null)
                                        throw new Exception ("Internal error: did not find the method builder for the generated method");
+
+                               host.EmitType ();
                        }
                        
-                       RootContext.EmitCode ();
-                       if (Report.Errors != 0)
+                       RootContext.ToplevelTypes.Emit ();
+                       if (Report.Errors != 0){
+                               if (undo != null)
+                                       undo.ExecuteUndo ();
                                return null;
-                       
-                       RootContext.CloseTypes ();
+                       }
+
+                       RootContext.ToplevelTypes.CloseType ();
+                       if (host != null)
+                               host.CloseType ();
 
-                       if (Environment.GetEnvironmentVariable ("SAVE") != null)
-                               CodeGen.Save (current_debug_name, false);
+                       if (access == AssemblyBuilderAccess.RunAndSave)
+                               assembly.Save ();
 
                        if (host == null)
                                return null;
@@ -721,44 +775,40 @@ namespace Mono.CSharp {
                        // 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 = 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 (TypeManager.IsStruct (old.FieldType)){
+                               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 (field.Spec, fi);
+                               } else {
+                                       fields.Add (field.Name, Tuple.Create (field.Spec, fi));
                                }
-                               
-                               fields [field.Name] = fi;
                        }
-                       //types.Add (tb);
-
                        queued_fields.Clear ();
                        
                        return (CompiledMethod) System.Delegate.CreateDelegate (typeof (CompiledMethod), mi);
                }
-               
-               static internal void LoadAliases (NamespaceEntry ns)
-               {
-                       ns.Populate (using_alias_list, using_list);
-               }
-               
+#endif
+
                /// <summary>
                ///   A sentinel value used to indicate that no value was
                ///   was set by the compiled function.   This is used to
@@ -768,10 +818,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;
                }
 
@@ -802,22 +852,28 @@ namespace Mono.CSharp {
                static public string GetUsing ()
                {
                        lock (evaluator_lock){
+                               if (ns == null)
+                                       return null;
+
                                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));
+                               // TODO:
+                               //foreach (object x in ns.using_alias_list)
+                               //    sb.AppendFormat ("using {0};\n", x);
+
+                               foreach (var ue in ns.Usings) {
+                                       sb.AppendFormat ("using {0};", ue.ToString ());
+                                       sb.Append (Environment.NewLine);
+                               }
                                
                                return sb.ToString ();
                        }
                }
 
-               static internal ICollection GetUsingList ()
+               static internal ICollection<string> GetUsingList ()
                {
-                       ArrayList res = new ArrayList (using_list.Count);
-                       foreach (object ue in using_list)
+                       var res = new List<string> ();
+
+                       foreach (var ue in ns.Usings)
                                res.Add (ue.ToString ());
                        return res;
                }
@@ -825,7 +881,7 @@ namespace Mono.CSharp {
                static internal string [] GetVarNames ()
                {
                        lock (evaluator_lock){
-                               return (string []) new ArrayList (fields.Keys).ToArray (typeof (string));
+                               return new List<string> (fields.Keys).ToArray ();
                        }
                }
                
@@ -834,25 +890,19 @@ namespace Mono.CSharp {
                        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 ();
@@ -865,8 +915,9 @@ namespace Mono.CSharp {
                static public void LoadAssembly (string file)
                {
                        lock (evaluator_lock){
-                               Driver.LoadAssembly (file, false);
-                               GlobalRootNamespace.Instance.ComputeNamespaces ();
+                               var a = loader.LoadAssemblyFile (file);
+                               if (a != null)
+                                       loader.Importer.ImportAssembly (a, RootContext.ToplevelTypes.GlobalRootNamespace);
                        }
                }
 
@@ -876,11 +927,15 @@ namespace Mono.CSharp {
                static public void ReferenceAssembly (Assembly a)
                {
                        lock (evaluator_lock){
-                               GlobalRootNamespace.Instance.AddAssemblyReference (a);
-                               GlobalRootNamespace.Instance.ComputeNamespaces ();
+                               loader.Importer.ImportAssembly (a, RootContext.ToplevelTypes.GlobalRootNamespace);
                        }
                }
-               
+
+               /// <summary>
+               ///   If true, turns type expressions into valid expressions
+               ///   and calls the describe method on it
+               /// </summary>
+               public static bool DescribeTypeExpressions;
        }
 
        
@@ -964,7 +1019,7 @@ namespace Mono.CSharp {
                        return DateTime.Now - start;
                }
                
-#if !SMCS_SOURCE
+#if !STATIC
                /// <summary>
                ///   Loads the assemblies from a package
                /// </summary>
@@ -980,7 +1035,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;
 
@@ -998,6 +1053,7 @@ namespace Mono.CSharp {
                }
 #endif
 
+#if !STATIC
                /// <summary>
                ///   Loads the assembly
                /// </summary>
@@ -1011,23 +1067,35 @@ namespace Mono.CSharp {
                {
                        Evaluator.LoadAssembly (assembly);
                }
+
+               static public void print (string obj)
+               {
+                       Output.WriteLine (obj);
+               }
+
+               static public void print (string fmt, params object [] args)
+               {
+                       Output.WriteLine (fmt, args);
+               }
+#endif
                
                /// <summary>
                ///   Returns a list of available static methods. 
                /// </summary>
                static public string help {
                        get {
-                               return  "Static methods:\n"+
-                                       "  Describe(obj)      - Describes the object's type\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" +
+                                       "  print (obj)             - Shorthand for Console.WriteLine\n" +
+                                       "  quit;                   - You'll never believe it - this quits the repl!\n" +
+                                       "  help;                   - This help text\n";
                        }
                }
 
@@ -1037,7 +1105,9 @@ namespace Mono.CSharp {
                static public object quit {
                        get {
                                QuitRequested = true;
-                               return null;
+
+                               // To avoid print null at the exit
+                               return typeof (Evaluator.NoValueSet);
                        }
                }
 
@@ -1055,69 +1125,31 @@ namespace Mono.CSharp {
                static public string Describe (object x)
                {
                        if (x == null)
-                               return "";
-                       
-                       Type t = x as Type;
-                       if (t == null)
-                               t = x.GetType ();
+                               return "<null>";
+
+                       var type = x as Type ?? x.GetType ();
 
                        StringWriter sw = new StringWriter ();
-                       new Outline (t, sw, true, false, false).OutlineType ();
+                       new Outline (type, sw, true, false, false).OutlineType ();
                        return sw.ToString ();
                }
 #endif
        }
 
-       //
-       // 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, LocalInfo li, Location loc)
-                       : base (current_block, local_variable_id, loc, li, false)
+       class HoistedEvaluatorVariable : HoistedVariable
+       {
+               public HoistedEvaluatorVariable (Field field)
+                       : base (null, field)
                {
-                       this.container = container;
-                       this.name = name;
                }
 
-               public override bool Equals (object obj)
+               public override void EmitSymbolInfo ()
                {
-                       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 ()
+               protected override FieldExpr GetFieldExpression (EmitContext ec)
                {
-                       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,
-                                            new MemberName (name, Location), null);
-                       container.AddField (f);
-                       if (f.Define ())
-                               Evaluator.QueueField (f);
-                       
-                       return ret;
+                       return new FieldExpr (field, field.Location);
                }
        }
 
@@ -1133,50 +1165,54 @@ 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);
-                               target = null;
-                               type = TypeManager.void_type;
-                               eclass = ExprClass.Value;
-                               return this;
+                       if (clone.Type == TypeManager.void_type || clone is DynamicInvocation || clone is Assign) {
+                               return clone;
                        }
 
                        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 class Undo
+       {
+               List<Action> undo_actions;
                
                public Undo ()
                {
-                       undo_types = new ArrayList ();
                }
 
                public void AddTypeContainer (TypeContainer current_container, TypeContainer tc)
@@ -1185,25 +1221,30 @@ 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));
+
+                       if (undo_actions == null)
+                               undo_actions = new List<Action> ();
+
+                       var existing = current_container.Types.FirstOrDefault (l => l.MemberName.Basename == tc.MemberName.Basename);
+                       if (existing != null) {
+                               current_container.RemoveTypeContainer (existing);
+                               undo_actions.Add (() => current_container.AddTypeContainer (existing));
+                       }
+
+                       undo_actions.Add (() => current_container.RemoveTypeContainer (tc));
                }
 
                public void ExecuteUndo ()
                {
-                       if (undo_types == null)
+                       if (undo_actions == null)
                                return;
 
-                       foreach (Pair p in undo_types){
-                               TypeContainer current_container = (TypeContainer) p.First;
-
-                               current_container.RemoveTypeContainer ((TypeContainer) p.Second);
+                       foreach (var p in undo_actions){
+                               p ();
                        }
-                       undo_types = null;
+
+                       undo_actions = null;
                }
        }
        
 }
-