2010-02-06 Miguel de Icaza <miguel@novell.com>
[mono.git] / mcs / mcs / eval.cs
index 737307666b43ab9775be4e84c315172c0ca52afa..ced26cd301a4f763dcb9b43aa64f0839590c3040 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;
@@ -54,15 +54,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 List<NamespaceEntry.UsingAliasEntry> using_alias_list = new List<NamespaceEntry.UsingAliasEntry> ();
+               internal static List<NamespaceEntry.UsingEntry> using_list = new List<NamespaceEntry.UsingEntry> ();
+               static Dictionary<string, FieldInfo> fields = new Dictionary<string, FieldInfo> ();
 
                static Type   interactive_base_class = typeof (InteractiveBase);
                static Driver driver;
                static bool inited;
 
+               static CompilerContext ctx;
+               
+               public static TextWriter MessageOutput = Console.Out;
+
                /// <summary>
                ///   Optional initialization for the Evaluator.
                /// </summary>
@@ -81,7 +85,11 @@ namespace Mono.CSharp {
                        InitAndGetStartupFiles (args);
                }
 
-
+               internal static ReportPrinter SetPrinter (ReportPrinter report_printer)
+               {
+                       return ctx.Report.SetPrinter (report_printer);
+               }                               
+               
                /// <summary>
                ///   Optional initialization for the Evaluator.
                /// </summary>
@@ -105,22 +113,26 @@ namespace Mono.CSharp {
                                if (inited)
                                        return new string [0];
                                
-                               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 ();
 
-                               ArrayList startup_files = new ArrayList ();
+                               var startup_files = new List<string> ();
                                foreach (CompilationUnit file in Location.SourceFiles)
                                        startup_files.Add (file.Path);
                                
                                CompilerCallableEntryPoint.Reset ();
+                               RootContext.ToplevelTypes = new ModuleCompiled (ctx, true);
+
                                driver.LoadReferences ();
                                RootContext.EvalMode = true;
                                inited = true;
 
-                               return (string []) startup_files.ToArray (typeof (string));
+                               return startup_files.ToArray ();
                        }
                }
 
@@ -132,22 +144,34 @@ namespace Mono.CSharp {
                static void Reset ()
                {
                        CompilerCallableEntryPoint.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 ())
+                       if (!TypeManager.InitCoreTypes (ctx))
                                throw new Exception ("Failed to InitCoreTypes");
-                       TypeManager.InitOptionalCoreTypes ();
+                       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>
@@ -244,14 +268,14 @@ namespace Mono.CSharp {
                                object parser_result = parser.InteractiveResult;
                                
                                if (!(parser_result is Class)){
-                                       int errors = Report.Errors;
+                                       int errors = ctx.Report.Errors;
                                        
                                        NamespaceEntry.VerifyAllUsing ();
-                                       if (errors == Report.Errors)
+                                       if (errors == ctx.Report.Errors)
                                                parser.CurrentNamespace.Extract (using_alias_list, using_list);
                                }
 
-                               compiled = CompileBlock (parser_result as Class, parser.undo);
+                               compiled = CompileBlock (parser_result as Class, parser.undo, ctx.Report);
                        }
                        
                        return null;
@@ -289,7 +313,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 +359,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;
@@ -387,11 +411,11 @@ namespace Mono.CSharp {
 
                                try {
                                        RootContext.ResolveTree ();
-                                       if (Report.Errors != 0)
+                                       if (ctx.Report.Errors != 0)
                                                return null;
                                        
                                        RootContext.PopulateTypes ();
-                                       if (Report.Errors != 0)
+                                       if (ctx.Report.Errors != 0)
                                                return null;
 
                                        MethodOrOperator method = null;
@@ -412,7 +436,7 @@ namespace Mono.CSharp {
                                        } catch (CompletionResult cr){
                                                prefix = cr.BaseText;
                                                return cr.Result;
-                                       }
+                                       } 
                                } finally {
                                        parser.undo.ExecuteUndo ();
                                }
@@ -487,7 +511,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 +618,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 +626,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,8 +640,7 @@ namespace Mono.CSharp {
                        }
                        seekable.Position = 0;
 
-                       CSharpParser parser = new CSharpParser (seekable, (CompilationUnit) 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;
@@ -635,18 +659,14 @@ namespace Mono.CSharp {
                        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;
 
@@ -654,8 +674,8 @@ namespace Mono.CSharp {
                                        parser = null;
                                }
 
-                               if (disable_error_reporting)
-                                       Report.EnableReporting ();
+                               if (old_printer != null)
+                                       SetPrinter (old_printer);
                        }
                        return parser;
                }
@@ -665,13 +685,13 @@ 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)
+               static CompiledMethod CompileBlock (Class host, Undo undo, Report Report)
                {
                        RootContext.ResolveTree ();
                        if (Report.Errors != 0){
@@ -706,13 +726,15 @@ namespace Mono.CSharp {
                        }
                        
                        RootContext.EmitCode ();
-                       if (Report.Errors != 0)
+                       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 null;
@@ -728,11 +750,11 @@ namespace Mono.CSharp {
                        foreach (Field field in queued_fields){
                                FieldInfo fi = tt.GetField (field.Name);
                                
-                               FieldInfo old = (FieldInfo) fields [field.Name];
+                               FieldInfo old;
                                
                                // If a previous value was set, nullify it, so that we do
                                // not leak memory
-                               if (old != null){
+                               if (fields.TryGetValue (field.Name, out old)){
                                        if (TypeManager.IsStruct (old.FieldType)){
                                                //
                                                // TODO: Clear fields for structs
@@ -770,7 +792,9 @@ namespace Mono.CSharp {
 
                static internal FieldInfo LookupField (string name)
                {
-                       FieldInfo fi =  (FieldInfo) fields [name];
+                       FieldInfo fi;
+                       if (!fields.TryGetValue (name, out fi))
+                               return null;
 
                        return fi;
                }
@@ -814,9 +838,9 @@ namespace Mono.CSharp {
                        }
                }
 
-               static internal ICollection GetUsingList ()
+               static internal ICollection<string> GetUsingList ()
                {
-                       ArrayList res = new ArrayList (using_list.Count);
+                       var res = new List<string> (using_list.Count);
                        foreach (object ue in using_list)
                                res.Add (ue.ToString ());
                        return res;
@@ -825,7 +849,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,8 +858,8 @@ namespace Mono.CSharp {
                        lock (evaluator_lock){
                                StringBuilder sb = new StringBuilder ();
                                
-                               foreach (DictionaryEntry de in fields){
-                                       FieldInfo fi = LookupField ((string) de.Key);
+                               foreach (var de in fields){
+                                       FieldInfo fi = LookupField (de.Key);
                                        object value = null;
                                        bool error = false;
                                        
@@ -865,8 +889,8 @@ namespace Mono.CSharp {
                static public void LoadAssembly (string file)
                {
                        lock (evaluator_lock){
-                               Driver.LoadAssembly (file, false);
-                               GlobalRootNamespace.Instance.ComputeNamespaces ();
+                               driver.LoadAssembly (file, false);
+                               GlobalRootNamespace.Instance.ComputeNamespaces (ctx);
                        }
                }
 
@@ -877,10 +901,15 @@ namespace Mono.CSharp {
                {
                        lock (evaluator_lock){
                                GlobalRootNamespace.Instance.AddAssemblyReference (a);
-                               GlobalRootNamespace.Instance.ComputeNamespaces ();
+                               GlobalRootNamespace.Instance.ComputeNamespaces (ctx);
                        }
                }
-               
+
+               /// <summary>
+               ///   If true, turns type expressions into valid expressions
+               ///   and calls the describe method on it
+               /// </summary>
+               public static bool DescribeTypeExpressions;
        }
 
        
@@ -980,7 +1009,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;
 
@@ -1104,7 +1133,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)
@@ -1133,15 +1162,38 @@ namespace Mono.CSharp {
                {
                }
 
-               public override Expression DoResolve (EmitContext ec)
+               protected override Expression DoResolve (ResolveContext ec)
                {
                        CloneContext cc = new CloneContext ();
                        Expression clone = source.Clone (cc);
 
+                       var old_printer = Evaluator.SetPrinter (new StreamReportPrinter (TextWriter.Null));
                        clone = clone.Resolve (ec);
-                       if (clone == null)
-                               return null;
+                       if (clone == null){
+                               //
+                               // A useful feature for the REPL: if we can resolve the expression
+                               // as a type, Describe the type;
+                               //
+                               if (Evaluator.DescribeTypeExpressions){
+                                       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 (source, Location)));
+                                       source = new Invocation (new SimpleName ("Describe", Location), args).Resolve (ec);
+                               } else {
+                                       Evaluator.SetPrinter (old_printer);
+                                       return null;
+                               }
+                       }
+                       Evaluator.SetPrinter (old_printer);
+       
                        // This means its really a statement.
                        if (clone.Type == TypeManager.void_type){
                                source = source.Resolve (ec);
@@ -1172,11 +1224,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)
@@ -1185,10 +1237,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 ()
@@ -1196,10 +1249,10 @@ 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;
                }