Merge pull request #820 from brendanzagaeski/master
[mono.git] / mcs / mcs / eval.cs
index 6810507d063fb0ca79c5124042fa3943cce1d767..766bb05696b6f9e815d0b80ee621c3e1c54194f7 100644 (file)
@@ -131,6 +131,12 @@ namespace Mono.CSharp
                        Location.Initialize (ctx.SourceFiles);
                }
 
+               /// <summary>
+               /// When set evaluator will automatically wait on Task of async methods. When not
+               /// set it's called responsibility to handle Task execution
+               /// </summary>
+               public bool WaitOnTask { get; set; }
+
                /// <summary>
                ///   If true, turns type expressions into valid expressions
                ///   and calls the describe method on it
@@ -226,9 +232,16 @@ namespace Mono.CSharp
 
                                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;
-                                       parser = ParseString (ParseMode.Silent, input + ";", out 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;
@@ -357,8 +370,14 @@ namespace Mono.CSharp
                                if (parser == null){
                                        return null;
                                }
-                               
-                               Class parser_result = parser.InteractiveResult;
+
+                               Class host = parser.InteractiveResult;
+
+                               var base_class_imported = importer.ImportType (base_class);
+                               var baseclass_list = new List<FullNamedExpression> (1) {
+                                       new TypeExpression (base_class_imported, host.Location)
+                               };
+                               host.SetBaseTypes (baseclass_list);
 
 #if NET_4_0
                                var access = AssemblyBuilderAccess.RunAndCollect;
@@ -370,13 +389,15 @@ namespace Mono.CSharp
                                module.SetDeclaringAssembly (a);
 
                                // Need to setup MemberCache
-                               parser_result.CreateContainer ();
+                               host.CreateContainer ();
+                               // Need to setup base type
+                               host.DefineContainer ();
 
-                               var method = parser_result.Members[0] as Method;
+                               var method = host.Members[0] as Method;
                                BlockContext bc = new BlockContext (method, method.Block, ctx.BuiltinTypes.Void);
 
                                try {
-                                       method.Block.Resolve (null, bc, method);
+                                       method.Block.Resolve (bc, method);
                                } catch (CompletionResult cr) {
                                        prefix = cr.BaseText;
                                        return cr.Result;
@@ -422,7 +443,7 @@ namespace Mono.CSharp
                                throw new ArgumentException ("Syntax error on input: partial input");
                        
                        if (result_set == false)
-                               throw new ArgumentException ("The expression did not set a result");
+                               throw new ArgumentException ("The expression failed to resolve");
 
                        return result;
                }
@@ -446,8 +467,11 @@ namespace Mono.CSharp
                //
                InputKind ToplevelOrStatement (SeekableStreamReader seekable)
                {
-                       Tokenizer tokenizer = new Tokenizer (seekable, source_file, new ParserSession ());
+                       Tokenizer tokenizer = new Tokenizer (seekable, source_file, new ParserSession (), ctx.Report);
                        
+                       // Prefer contextual block keywords over identifiers
+                       tokenizer.parsing_block++;
+
                        int t = tokenizer.token ();
                        switch (t){
                        case Token.EOF:
@@ -579,6 +603,7 @@ namespace Mono.CSharp
 
                        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;
@@ -644,13 +669,49 @@ namespace Mono.CSharp
                                        new TypeExpression (base_class_imported, host.Location)
                                };
 
-                               host.AddBasesForPart (baseclass_list);
-
-                               host.CreateContainer ();
-                               host.DefineContainer ();
-                               host.Define ();
+                               host.SetBaseTypes (baseclass_list);
 
                                expression_method = (Method) host.Members[0];
+
+                               if ((expression_method.ModFlags & Modifiers.ASYNC) != 0) {
+                                       //
+                                       // Host method is async. When WaitOnTask is set we wrap it with wait
+                                       //
+                                       // void AsyncWait (ref object $retval) {
+                                       //      $retval = Host();
+                                       //      ((Task)$retval).Wait();  // When WaitOnTask is set
+                                       // }
+                                       //
+                                       var p = new ParametersCompiled (
+                                               new Parameter (new TypeExpression (module.Compiler.BuiltinTypes.Object, Location.Null), "$retval", Parameter.Modifier.REF, null, Location.Null)
+                                       );
+
+                                       var method = new Method(host, new TypeExpression(module.Compiler.BuiltinTypes.Void, Location.Null),
+                                               Modifiers.PUBLIC | Modifiers.STATIC, new MemberName("AsyncWait"), p, null);
+
+                                       method.Block = new ToplevelBlock(method.Compiler, p, Location.Null);
+                                       method.Block.AddStatement(new StatementExpression (new SimpleAssign(
+                                               new SimpleName(p [0].Name, Location.Null),
+                                               new Invocation(new SimpleName(expression_method.MemberName.Name, Location.Null), new Arguments(0)),
+                                               Location.Null), Location.Null));
+
+                                       if (WaitOnTask) {
+                                               var task = new Cast (expression_method.TypeExpression, new SimpleName (p [0].Name, Location.Null), Location.Null);
+
+                                               method.Block.AddStatement (new StatementExpression (new Invocation (
+                                                               new MemberAccess (task, "Wait", Location.Null),
+                                                       new Arguments (0)), Location.Null));
+                                       }
+
+                                       host.AddMember(method);
+
+                                       expression_method = method;
+                               }
+
+                               host.CreateContainer();
+                               host.DefineContainer();
+                               host.Define();
+
                        } else {
                                expression_method = null;
                        }
@@ -671,6 +732,7 @@ namespace Mono.CSharp
                        }
 
                        if (host != null){
+                               host.PrepareEmit ();
                                host.EmitContainer ();
                        }
                        
@@ -984,9 +1046,7 @@ namespace Mono.CSharp
                static public string help {
                        get {
                                return "Static methods:\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" +
@@ -1044,6 +1104,27 @@ namespace Mono.CSharp
 #endif
        }
 
+       class InteractiveMethod : Method
+       {
+               public InteractiveMethod(TypeDefinition parent, FullNamedExpression returnType, Modifiers mod, ParametersCompiled parameters)
+                       : base(parent, returnType, mod, new MemberName("Host"), parameters, null)
+               {
+               }
+
+               public void ChangeToAsync ()
+               {
+                       ModFlags |= Modifiers.ASYNC;
+                       ModFlags &= ~Modifiers.UNSAFE;
+                       type_expr = new TypeExpression(Module.PredefinedTypes.Task.TypeSpec, Location);
+                       parameters = ParametersCompiled.EmptyReadOnlyParameters;
+               }
+
+               public override string GetSignatureForError()
+               {
+                       return "InteractiveHost";
+               }
+       }
+
        class HoistedEvaluatorVariable : HoistedVariable
        {
                public HoistedEvaluatorVariable (Field field)
@@ -1064,11 +1145,17 @@ namespace Mono.CSharp
        ///    the return value for an invocation.
        /// </summary>
        class OptionalAssign : SimpleAssign {
-               public OptionalAssign (Expression t, Expression s, Location loc)
-                       : base (t, s, loc)
+               public OptionalAssign (Expression s, Location loc)
+                       : base (null, s, loc)
                {
                }
 
+               public override Location StartLocation {
+                       get {
+                               return Location.Null;
+                       }
+               }
+
                protected override Expression DoResolve (ResolveContext ec)
                {
                        Expression clone = source.Clone (new CloneContext ());
@@ -1081,7 +1168,7 @@ namespace Mono.CSharp
                        // A useful feature for the REPL: if we can resolve the expression
                        // as a type, Describe the type;
                        //
-                       if (ec.Module.Evaluator.DescribeTypeExpressions){
+                       if (ec.Module.Evaluator.DescribeTypeExpressions && !(ec.CurrentAnonymousMethod is AsyncInitializer)) {
                                var old_printer = ec.Report.SetPrinter (new SessionReportPrinter ());
                                Expression tclone;
                                try {
@@ -1107,17 +1194,34 @@ namespace Mono.CSharp
                        }
 
                        source = clone;
+
+                       var host = (Method) ec.MemberContext.CurrentMemberDefinition;
+
+                       if (host.ParameterInfo.IsEmpty) {
+                               eclass = ExprClass.Value;
+                               type = InternalType.FakeInternalType;
+                               return this;
+                       }
+
+                       target = new SimpleName (host.ParameterInfo[0].Name, Location);
+
                        return base.DoResolve (ec);
                }
+
+               public override void EmitStatement(EmitContext ec)
+               {
+                       if (target == null) {
+                               source.Emit (ec);
+                               return;
+                       }
+
+                       base.EmitStatement(ec);
+               }
        }
 
        public class Undo
        {
                List<Action> undo_actions;
-               
-               public Undo ()
-               {
-               }
 
                public void AddTypeContainer (TypeContainer current_container, TypeDefinition tc)
                {