Less static is good for my health
[mono.git] / mcs / mcs / eval.cs
index 48952b8187a007560c6146f48542e2091dbbd18d..121e61b1d96deea41a4288594b88723b6698e08d 100644 (file)
@@ -9,6 +9,7 @@
 // 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.Generic;
@@ -16,8 +17,10 @@ using System.Reflection;
 using System.Reflection.Emit;
 using System.IO;
 using System.Text;
+using System.Linq;
 
-namespace Mono.CSharp {
+namespace Mono.CSharp
+{
 
        /// <summary>
        ///   Evaluator: provides an API to evaluate C# statements and
@@ -54,8 +57,6 @@ namespace Mono.CSharp {
                static int count;
                static Thread invoke_thread;
 
-               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;
@@ -64,6 +65,7 @@ namespace Mono.CSharp {
 
                static CompilerContext ctx;
                static DynamicLoader loader;
+               static NamespaceEntry ns;
                
                public static TextWriter MessageOutput = Console.Out;
 
@@ -90,6 +92,11 @@ namespace Mono.CSharp {
                        return ctx.Report.SetPrinter (report_printer);
                }                               
 
+               public static string [] InitAndGetStartupFiles (string [] args)
+               {
+                       return InitAndGetStartupFiles (args, null);
+               }
+
                /// <summary>
                ///   Optional initialization for the Evaluator.
                /// </summary>
@@ -106,18 +113,33 @@ 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, new ConsoleReportPrinter ());
-                               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");
 
-                               ctx = driver.ctx;
+                               ctx = new CompilerContext (settings, r) {
+                                       IsEvalutor = true
+                               };
 
                                RootContext.ToplevelTypes = new ModuleContainer (ctx);
                                
@@ -125,17 +147,17 @@ namespace Mono.CSharp {
                                foreach (CompilationUnit file in Location.SourceFiles)
                                        startup_files.Add (file.Path);
                                
-                               CompilerCallableEntryPoint.Reset ();
+                               CompilerCallableEntryPoint.PartialReset ();
 
                                var importer = new ReflectionImporter (ctx.BuildinTypes);
                                loader = new DynamicLoader (importer, ctx);
 
-                               RootContext.ToplevelTypes.MakeExecutable ("temp");
+                               RootContext.ToplevelTypes.SetDeclaringAssembly (new AssemblyDefinitionDynamic (RootContext.ToplevelTypes, "temp"));
+
                                loader.LoadReferences (RootContext.ToplevelTypes);
-                               TypeManager.InitCoreTypes (RootContext.ToplevelTypes, ctx.BuildinTypes);
+                               ctx.BuildinTypes.CheckDefinitions (RootContext.ToplevelTypes);
                                RootContext.ToplevelTypes.InitializePredefinedTypes ();
 
-                               RootContext.EvalMode = true;
                                inited = true;
 
                                return startup_files.ToArray ();
@@ -185,6 +207,9 @@ namespace Mono.CSharp {
                        if (type == null)
                                throw new ArgumentNullException ();
 
+                       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);
                }
@@ -236,10 +261,12 @@ namespace Mono.CSharp {
                                compiled = null;
                                return null;
                        }
-                       
+
                        lock (evaluator_lock){
                                if (!inited)
                                        Init ();
+                               else
+                                       ctx.Report.Printer.Reset ();
 
                        //      RootContext.ToplevelTypes = new ModuleContainer (ctx);
 
@@ -254,20 +281,14 @@ namespace Mono.CSharp {
                                        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);
+#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>
@@ -390,18 +411,17 @@ 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 {
-                                       var a = RootContext.ToplevelTypes.MakeExecutable ("temp");
+                                       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;
                                        
@@ -425,13 +445,14 @@ namespace Mono.CSharp {
                                                return cr.Result;
                                        } 
                                } finally {
-                                       parser.undo.ExecuteUndo ();
+                                       if (parser.undo != null)
+                                               parser.undo.ExecuteUndo ();
                                }
                                
                        }
                        return null;
                }
-               
+
                /// <summary>
                ///   Executes the given expression or statement.
                /// </summary>
@@ -478,7 +499,7 @@ namespace Mono.CSharp {
 
                        return result;
                }
-       
+
                enum InputKind {
                        EOF,
                        StatementOrExpression,
@@ -627,20 +648,17 @@ namespace Mono.CSharp {
                        }
                        seekable.Position = 0;
 
-                       CSharpParser parser = new CSharpParser (seekable, Location.SourceFiles [0], RootContext.ToplevelTypes);
+                       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)
@@ -657,7 +675,9 @@ namespace Mono.CSharp {
                                        if (mode != ParseMode.ReportErrors  && parser.UnexpectedEOF)
                                                partial_input = true;
 
-                                       parser.undo.ExecuteUndo ();
+                                       if (parser.undo != null)
+                                               parser.undo.ExecuteUndo ();
+
                                        parser = null;
                                }
 
@@ -677,23 +697,39 @@ namespace Mono.CSharp {
                //static ArrayList types = new ArrayList ();
 
                static volatile bool invoking;
-               
+#if !STATIC            
                static CompiledMethod CompileBlock (Class host, Undo undo, Report Report)
                {
-                       AssemblyDefinition assembly;
+                       AssemblyDefinitionDynamic assembly;
+                       AssemblyBuilderAccess access;
 
                        if (Environment.GetEnvironmentVariable ("SAVE") != null) {
-                               assembly = RootContext.ToplevelTypes.MakeExecutable (current_debug_name, current_debug_name);
+                               access = AssemblyBuilderAccess.RunAndSave;
+                               assembly = new AssemblyDefinitionDynamic (RootContext.ToplevelTypes, current_debug_name, current_debug_name);
                                assembly.Importer = loader.Importer;
                        } else {
-                               assembly = RootContext.ToplevelTypes.MakeExecutable (current_debug_name);
+#if NET_4_0
+                               access = AssemblyBuilderAccess.RunAndCollect;
+#else
+                               access = AssemblyBuilderAccess.Run;
+#endif
+                               assembly = new AssemblyDefinitionDynamic (RootContext.ToplevelTypes, current_debug_name);
                        }
 
-                       assembly.Create (AppDomain.CurrentDomain, AssemblyBuilderAccess.RunAndSave);
+                       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;
                        }
 
@@ -714,17 +750,22 @@ namespace Mono.CSharp {
 
                                if (mb == null)
                                        throw new Exception ("Internal error: did not find the method builder for the generated method");
+
+                               host.EmitType ();
                        }
                        
                        RootContext.ToplevelTypes.Emit ();
                        if (Report.Errors != 0){
-                               undo.ExecuteUndo ();
+                               if (undo != null)
+                                       undo.ExecuteUndo ();
                                return null;
                        }
 
                        RootContext.ToplevelTypes.CloseType ();
+                       if (host != null)
+                               host.CloseType ();
 
-                       if (Environment.GetEnvironmentVariable ("SAVE") != null)
+                       if (access == AssemblyBuilderAccess.RunAndSave)
                                assembly.Save ();
 
                        if (host == null)
@@ -757,23 +798,17 @@ namespace Mono.CSharp {
                                                }
                                        }
 
-                                       fields [field.Name] = Tuple.Create (old.Item1, fi);
+                                       fields [field.Name] = Tuple.Create (field.Spec, fi);
                                } else {
                                        fields.Add (field.Name, Tuple.Create (field.Spec, 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
@@ -817,13 +852,18 @@ 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 ();
                        }
@@ -831,8 +871,9 @@ namespace Mono.CSharp {
 
                static internal ICollection<string> GetUsingList ()
                {
-                       var res = new List<string> (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;
                }
@@ -874,7 +915,7 @@ namespace Mono.CSharp {
                static public void LoadAssembly (string file)
                {
                        lock (evaluator_lock){
-                               var a = loader.LoadAssemblyFile (file, false);
+                               var a = loader.LoadAssemblyFile (file);
                                if (a != null)
                                        loader.Importer.ImportAssembly (a, RootContext.ToplevelTypes.GlobalRootNamespace);
                        }
@@ -978,7 +1019,7 @@ namespace Mono.CSharp {
                        return DateTime.Now - start;
                }
                
-#if !SMCS_SOURCE
+#if !STATIC
                /// <summary>
                ///   Loads the assemblies from a package
                /// </summary>
@@ -1012,6 +1053,7 @@ namespace Mono.CSharp {
                }
 #endif
 
+#if !STATIC
                /// <summary>
                ///   Loads the assembly
                /// </summary>
@@ -1025,6 +1067,17 @@ 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. 
@@ -1040,6 +1093,7 @@ namespace Mono.CSharp {
                                        "  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";
                        }
@@ -1153,12 +1207,12 @@ namespace Mono.CSharp {
                }
        }
 
-       public class Undo {
-               List<KeyValuePair<TypeContainer, TypeContainer>> undo_types;
+       public class Undo
+       {
+               List<Action> undo_actions;
                
                public Undo ()
                {
-                       undo_types = new List<KeyValuePair<TypeContainer, TypeContainer>> ();
                }
 
                public void AddTypeContainer (TypeContainer current_container, TypeContainer tc)
@@ -1168,25 +1222,29 @@ namespace Mono.CSharp {
                                return;
                        }
 
-                       if (undo_types == null)
-                               undo_types = new List<KeyValuePair<TypeContainer, TypeContainer>> ();
+                       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_types.Add (new KeyValuePair<TypeContainer, TypeContainer> (current_container, tc));
+                       undo_actions.Add (() => current_container.RemoveTypeContainer (tc));
                }
 
                public void ExecuteUndo ()
                {
-                       if (undo_types == null)
+                       if (undo_actions == null)
                                return;
 
-                       foreach (var p in undo_types){
-                               TypeContainer current_container = p.Key;
-
-                               current_container.RemoveTypeContainer (p.Value);
+                       foreach (var p in undo_actions){
+                               p ();
                        }
-                       undo_types = null;
+
+                       undo_actions = null;
                }
        }
        
 }
-