System.Runtime.Serialization.DateTimeFormat
[mono.git] / mcs / mcs / eval.cs
index 61aee92b88c20152fcef9ec530756d620ec21ee0..bb0260575a4a47839914da95df46a96d86cf4227 100644 (file)
@@ -9,6 +9,7 @@
 //
 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
 // Copyright 2004-2011 Novell, Inc
+// Copyright 2011 Xamarin Inc
 //
 
 using System;
@@ -55,31 +56,37 @@ namespace Mono.CSharp
                static object evaluator_lock = new object ();
                static volatile bool invoking;
                
+#if !STATIC
                static int count;
+#endif
                static Thread invoke_thread;
 
                readonly Dictionary<string, Tuple<FieldSpec, FieldInfo>> fields;
 
                Type base_class;
                bool inited;
+               int startup_files;
 
                readonly CompilerContext ctx;
                readonly ModuleContainer module;
                readonly ReflectionImporter importer;
-
-               // TODO: somehow merge with module
-               NamespaceEntry ns;
+               readonly CompilationSourceFile source_file;
                
-               public Evaluator (CompilerSettings settings, Report report)
+               public Evaluator (CompilerContext ctx)
                {
-                       ctx = new CompilerContext (settings, report);
+                       this.ctx = ctx;
 
                        module = new ModuleContainer (ctx);
                        module.Evaluator = this;
 
+                       source_file = new CompilationSourceFile (module, null);
+                       module.AddTypeContainer (source_file);
+
+                       startup_files = ctx.SourceFiles.Count;
+
                        // FIXME: Importer needs this assembly for internalsvisibleto
                        module.SetDeclaringAssembly (new AssemblyDefinitionDynamic (module, "evaluator"));
-                       importer = new ReflectionImporter (module, ctx.BuildinTypes);
+                       importer = new ReflectionImporter (module, ctx.BuiltinTypes);
 
                        InteractiveBaseClass = typeof (InteractiveBase);
                        fields = new Dictionary<string, Tuple<FieldSpec, FieldInfo>> ();
@@ -97,18 +104,31 @@ namespace Mono.CSharp
                        //    startup_files.Add (file.Path);
 
                        loader.LoadReferences (module);
-                       ctx.BuildinTypes.CheckDefinitions (module);
+                       ctx.BuiltinTypes.CheckDefinitions (module);
                        module.InitializePredefinedTypes ();
 
                        inited = true;
                }
 
-               static void Reset ()
+               void ParseStartupFiles ()
+               {
+                       Driver d = new Driver (ctx);
+
+                       Location.Initialize (ctx.SourceFiles);
+
+                       var parser_session = new ParserSession ();
+                       for (int i = 0; i < startup_files; ++i) {
+                               var sf = ctx.SourceFiles [i];
+                               d.Parse (sf, module, parser_session, ctx.Report);
+                       }
+               }
+
+               void Reset ()
                {
                        CompilerCallableEntryPoint.PartialReset ();
                        
-                       Location.AddFile (null, "{interactive}");
-                       Location.Initialize ();
+                       Location.Reset ();
+                       Location.Initialize (ctx.SourceFiles);
                }
 
                /// <summary>
@@ -117,6 +137,11 @@ namespace Mono.CSharp
                /// </summary>
                public bool DescribeTypeExpressions;
 
+               /// <summary>
+               ///   Whether the evaluator will use terse syntax, and the semicolons at the end are optional
+               /// </summary>
+               public bool Terse = true;
+
                /// <summary>
                ///   The base class for the classes that host the user generated code
                /// </summary>
@@ -183,7 +208,7 @@ namespace Mono.CSharp
                ///   compiled parameter will be set to the delegate
                ///   that can be invoked to execute the code.
                ///
-           /// </remarks>
+               /// </remarks>
                public string Compile (string input, out CompiledMethod compiled)
                {
                        if (input == null || input.Length == 0){
@@ -192,13 +217,26 @@ namespace Mono.CSharp
                        }
 
                        lock (evaluator_lock){
-                               if (!inited)
+                               if (!inited) {
                                        Init ();
-                               else
+                                       ParseStartupFiles ();
+                               } else {
                                        ctx.Report.Printer.Reset ();
+                               }
 
                                bool partial_input;
                                CSharpParser parser = ParseString (ParseMode.Silent, input, out partial_input);
+
+                               // Terse mode, try to provide the trailing semicolon automatically.
+                               if (parser == null && Terse && partial_input){
+                                       bool ignore;
+
+                                       // check if the source would compile with a block, if so, we should not
+                                       // add the semicolon.
+                                       var needs_block = ParseString (ParseMode.Silent, input + "{}", out ignore) != null;
+                                       if (!needs_block)
+                                               parser = ParseString (ParseMode.Silent, input + ";", out ignore);
+                               }
                                if (parser == null){
                                        compiled = null;
                                        if (partial_input)
@@ -324,8 +362,6 @@ namespace Mono.CSharp
                                bool partial_input;
                                CSharpParser parser = ParseString (ParseMode.GetCompletions, input, out partial_input);
                                if (parser == null){
-                                       if (CSharpParser.yacc_verbose_flag != 0)
-                                               Console.WriteLine ("DEBUG: No completions available");
                                        return null;
                                }
                                
@@ -341,10 +377,10 @@ namespace Mono.CSharp
                                module.SetDeclaringAssembly (a);
 
                                // Need to setup MemberCache
-                               parser_result.CreateType ();
+                               parser_result.CreateContainer ();
 
-                               var method = parser_result.Methods[0] as Method;
-                               BlockContext bc = new BlockContext (method, method.Block, TypeManager.void_type);
+                               var method = parser_result.Members[0] as Method;
+                               BlockContext bc = new BlockContext (method, method.Block, ctx.BuiltinTypes.Void);
 
                                try {
                                        method.Block.Resolve (null, bc, method);
@@ -417,8 +453,11 @@ namespace Mono.CSharp
                //
                InputKind ToplevelOrStatement (SeekableStreamReader seekable)
                {
-                       Tokenizer tokenizer = new Tokenizer (seekable, (CompilationUnit) Location.SourceFiles [0], ctx);
+                       Tokenizer tokenizer = new Tokenizer (seekable, source_file, new ParserSession ());
                        
+                       // Prefer contextual block keywords over identifiers
+                       tokenizer.parsing_block++;
+
                        int t = tokenizer.token ();
                        switch (t){
                        case Token.EOF:
@@ -523,10 +562,10 @@ namespace Mono.CSharp
                {
                        partial_input = false;
                        Reset ();
-                       Tokenizer.LocatedToken.Initialize ();
 
-                       Stream s = new MemoryStream (Encoding.Default.GetBytes (input));
-                       SeekableStreamReader seekable = new SeekableStreamReader (s, Encoding.Default);
+                       var enc = ctx.Settings.Encoding;
+                       var s = new MemoryStream (enc.GetBytes (input));
+                       SeekableStreamReader seekable = new SeekableStreamReader (s, enc);
 
                        InputKind kind = ToplevelOrStatement (seekable);
                        if (kind == InputKind.Error){
@@ -545,13 +584,12 @@ namespace Mono.CSharp
                        }
                        seekable.Position = 0;
 
-                       if (ns == null)
-                               ns = new NamespaceEntry (module, null, Location.SourceFiles[0], null);
-
-                       CSharpParser parser = new CSharpParser (seekable, Location.SourceFiles [0], module, ns);
+                       source_file.DeclarationFound = false;
+                       CSharpParser parser = new CSharpParser (seekable, source_file, new ParserSession ());
 
                        if (kind == InputKind.StatementOrExpression){
                                parser.Lexer.putback_char = Tokenizer.EvalStatementParserCharacter;
+                               parser.Lexer.parsing_block++;
                                ctx.Settings.StatementMode = true;
                        } else {
                                parser.Lexer.putback_char = Tokenizer.EvalCompilationUnitParserCharacter;
@@ -562,7 +600,7 @@ namespace Mono.CSharp
                                parser.Lexer.CompleteOnEOF = true;
 
                        ReportPrinter old_printer = null;
-                       if ((mode == ParseMode.Silent || mode == ParseMode.GetCompletions) && CSharpParser.yacc_verbose_flag == 0)
+                       if ((mode == ParseMode.Silent || mode == ParseMode.GetCompletions))
                                old_printer = ctx.Report.SetPrinter (new StreamReportPrinter (TextWriter.Null));
 
                        try {
@@ -586,11 +624,12 @@ namespace Mono.CSharp
 
                CompiledMethod CompileBlock (Class host, Undo undo, Report Report)
                {
-                       string current_debug_name = "eval-" + count + ".dll";
-                       ++count;
 #if STATIC
                        throw new NotSupportedException ();
 #else
+                       string current_debug_name = "eval-" + count + ".dll";
+                       ++count;
+
                        AssemblyDefinitionDynamic assembly;
                        AssemblyBuilderAccess access;
 
@@ -616,18 +655,23 @@ namespace Mono.CSharp
                                        new TypeExpression (base_class_imported, host.Location)
                                };
 
-                               host.AddBasesForPart (host, baseclass_list);
+                               host.AddBasesForPart (baseclass_list);
 
-                               host.CreateType ();
-                               host.DefineType ();
+                               host.CreateContainer ();
+                               host.DefineContainer ();
                                host.Define ();
 
-                               expression_method = (Method) host.Methods[0];
+                               expression_method = (Method) host.Members[0];
                        } else {
                                expression_method = null;
                        }
 
-                       module.CreateType ();
+                       module.CreateContainer ();
+
+                       // Disable module and source file re-definition checks
+                       module.EnableRedefinition ();
+                       source_file.EnableRedefinition ();
+
                        module.Define ();
 
                        if (Report.Errors != 0){
@@ -638,19 +682,19 @@ namespace Mono.CSharp
                        }
 
                        if (host != null){
-                               host.EmitType ();
+                               host.EmitContainer ();
                        }
                        
-                       module.Emit ();
+                       module.EmitContainer ();
                        if (Report.Errors != 0){
                                if (undo != null)
                                        undo.ExecuteUndo ();
                                return null;
                        }
 
-                       module.CloseType ();
+                       module.CloseContainer ();
                        if (host != null)
-                               host.CloseType ();
+                               host.CloseContainer ();
 
                        if (access == AssemblyBuilderAccess.RunAndSave)
                                assembly.Save ();
@@ -663,36 +707,38 @@ namespace Mono.CSharp
                        // work from MethodBuilders.   Retarded, I know.
                        //
                        var tt = assembly.Builder.GetType (host.TypeBuilder.Name);
-                       var mi = tt.GetMethod (expression_method.Name);
-
-                       if (host.Fields != null) {
-                               //
-                               // We need to then go from FieldBuilder to FieldInfo
-                               // or reflection gets confused (it basically gets confused, and variables override each
-                               // other).
-                               //
-                               foreach (Field field in host.Fields) {
-                                       var fi = tt.GetField (field.Name);
-
-                                       Tuple<FieldSpec, FieldInfo> old;
-
-                                       // If a previous value was set, nullify it, so that we do
-                                       // not leak memory
-                                       if (fields.TryGetValue (field.Name, out old)) {
-                                               if (old.Item1.MemberType.IsStruct) {
-                                                       //
-                                                       // TODO: Clear fields for structs
-                                                       //
-                                               } else {
-                                                       try {
-                                                               old.Item2.SetValue (null, null);
-                                                       } catch {
-                                                       }
+                       var mi = tt.GetMethod (expression_method.MemberName.Name);
+
+                       //
+                       // We need to then go from FieldBuilder to FieldInfo
+                       // or reflection gets confused (it basically gets confused, and variables override each
+                       // other).
+                       //
+                       foreach (var member in host.Members) {
+                               var field = member as Field;
+                               if (field == null)
+                                       continue;
+
+                               var fi = tt.GetField (field.Name);
+
+                               Tuple<FieldSpec, FieldInfo> old;
+
+                               // If a previous value was set, nullify it, so that we do
+                               // not leak memory
+                               if (fields.TryGetValue (field.Name, out old)) {
+                                       if (old.Item1.MemberType.IsStruct) {
+                                               //
+                                               // TODO: Clear fields for structs
+                                               //
+                                       } else {
+                                               try {
+                                                       old.Item2.SetValue (null, null);
+                                               } catch {
                                                }
                                        }
-
-                                       fields[field.Name] = Tuple.Create (field.Spec, fi);
                                }
+
+                               fields[field.Name] = Tuple.Create (field.Spec, fi);
                        }
                        
                        return (CompiledMethod) System.Delegate.CreateDelegate (typeof (CompiledMethod), mi);
@@ -724,15 +770,12 @@ namespace Mono.CSharp
 
                public string GetUsing ()
                {
-                       if (ns == null)
-                               return null;
-
                        StringBuilder sb = new StringBuilder ();
                        // TODO:
                        //foreach (object x in ns.using_alias_list)
                        //    sb.AppendFormat ("using {0};\n", x);
 
-                       foreach (var ue in ns.Usings) {
+                       foreach (var ue in source_file.Usings) {
                                sb.AppendFormat ("using {0};", ue.ToString ());
                                sb.Append (Environment.NewLine);
                        }
@@ -740,12 +783,17 @@ namespace Mono.CSharp
                        return sb.ToString ();
                }
 
-               internal ICollection<string> GetUsingList ()
+               internal List<string> GetUsingList ()
                {
                        var res = new List<string> ();
 
-                       foreach (var ue in ns.Usings)
-                               res.Add (ue.ToString ());
+                       foreach (var ue in source_file.Usings) {
+                               if (ue.Alias != null || ue.ResolvedExpression == null)
+                                       continue;
+
+                               res.Add (ue.NamespaceExpression.Name);
+                       }
+
                        return res;
                }
                
@@ -786,7 +834,7 @@ namespace Mono.CSharp
                public void LoadAssembly (string file)
                {
                        var loader = new DynamicLoader (importer, ctx);
-                       var assembly = loader.LoadAssemblyFile (file);
+                       var assembly = loader.LoadAssemblyFile (file, false);
                        if (assembly == null)
                                return;
 
@@ -931,7 +979,7 @@ namespace Mono.CSharp
                        Evaluator.LoadAssembly (assembly);
                }
 
-               static public void print (string obj)
+               static public void print (object obj)
                {
                        Output.WriteLine (obj);
                }
@@ -947,17 +995,19 @@ namespace Mono.CSharp
                static public string help {
                        get {
                                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";
+#if !NET_2_1
+                                       "  Describe (object);       - Describes the object's type\n" +
+#endif
+                                       "  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";
                        }
                }
 
@@ -973,6 +1023,13 @@ namespace Mono.CSharp
                        }
                }
 
+               /// <summary>
+               ///   Same as quit - useful in script scenerios
+               /// </summary>
+               static public void Quit () {
+                       QuitRequested = true;
+               }
+
 #if !NET_2_1
                /// <summary>
                ///   Describes an object or a type.
@@ -1005,10 +1062,6 @@ namespace Mono.CSharp
                {
                }
 
-               public override void EmitSymbolInfo ()
-               {
-               }
-
                protected override FieldExpr GetFieldExpression (EmitContext ec)
                {
                        return new FieldExpr (field, field.Location);
@@ -1029,8 +1082,11 @@ namespace Mono.CSharp
 
                protected override Expression DoResolve (ResolveContext ec)
                {
-                       CloneContext cc = new CloneContext ();
-                       Expression clone = source.Clone (cc);
+                       Expression clone = source.Clone (new CloneContext ());
+
+                       clone = clone.Resolve (ec);
+                       if (clone == null)
+                               return null;
 
                        //
                        // A useful feature for the REPL: if we can resolve the expression
@@ -1038,35 +1094,30 @@ namespace Mono.CSharp
                        //
                        if (ec.Module.Evaluator.DescribeTypeExpressions){
                                var old_printer = ec.Report.SetPrinter (new SessionReportPrinter ());
+                               Expression tclone;
                                try {
-                                       clone = clone.Resolve (ec);
-                                       if (clone == null) {
-                                               clone = source.Clone (cc);
-                                               clone = clone.Resolve (ec, ResolveFlags.Type);
-                                               if (clone == null) {
-                                                       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);
-                                       }
+                                       // Note: clone context cannot be shared otherwise block mapping would leak
+                                       tclone = source.Clone (new CloneContext ());
+                                       tclone = tclone.Resolve (ec, ResolveFlags.Type);
+                                       if (ec.Report.Errors > 0)
+                                               tclone = null;
                                } finally {
                                        ec.Report.SetPrinter (old_printer);
                                }
-                       } else {
-                               clone = clone.Resolve (ec);
-                               if (clone == null)
-                                       return null;
+
+                               if (tclone is TypeExpr) {
+                                       Arguments args = new Arguments (1);
+                                       args.Add (new Argument (new TypeOf ((TypeExpr) clone, Location)));
+                                       return new Invocation (new SimpleName ("Describe", Location), args).Resolve (ec);
+                               }
                        }
-       
+
                        // This means its really a statement.
-                       if (clone.Type == TypeManager.void_type || clone is DynamicInvocation || clone is Assign) {
+                       if (clone.Type.Kind == MemberKind.Void || clone is DynamicInvocation || clone is Assign) {
                                return clone;
                        }
 
+                       source = clone;
                        return base.DoResolve (ec);
                }
        }
@@ -1079,7 +1130,7 @@ namespace Mono.CSharp
                {
                }
 
-               public void AddTypeContainer (TypeContainer current_container, TypeContainer tc)
+               public void AddTypeContainer (TypeContainer current_container, TypeDefinition tc)
                {
                        if (current_container == tc){
                                Console.Error.WriteLine ("Internal error: inserting container into itself");
@@ -1089,13 +1140,13 @@ namespace Mono.CSharp
                        if (undo_actions == null)
                                undo_actions = new List<Action> ();
 
-                       var existing = current_container.Types.FirstOrDefault (l => l.MemberName.Basename == tc.MemberName.Basename);
+                       var existing = current_container.Containers.FirstOrDefault (l => l.Basename == tc.Basename);
                        if (existing != null) {
-                               current_container.RemoveTypeContainer (existing);
+                               current_container.RemoveContainer (existing);
                                undo_actions.Add (() => current_container.AddTypeContainer (existing));
                        }
 
-                       undo_actions.Add (() => current_container.RemoveTypeContainer (tc));
+                       undo_actions.Add (() => current_container.RemoveContainer (tc));
                }
 
                public void ExecuteUndo ()