2009-10-22 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / class / Microsoft.CSharp / Microsoft.CSharp.RuntimeBinder / CSharpBinder.cs
index 0dd545d3b4846bfb6fec088681c50f3e673bb8ba..4b5f01b36b3f74b441eb140d501dc953f9922efe 100644 (file)
@@ -31,28 +31,31 @@ using System.Dynamic;
 using System.Linq.Expressions;
 using Compiler = Mono.CSharp;
 using System.Reflection;
+using System.Collections.Generic;
 
 namespace Microsoft.CSharp.RuntimeBinder
 {
-       class CSharpBinder
+       static class CSharpBinder
        {
                static ConstructorInfo binder_exception_ctor;
-               static bool compiler_initialized;
                static object compiler_initializer = new object ();
                static object resolver = new object ();
 
-               public static DynamicMetaObject Bind (DynamicMetaObject target, Compiler.Expression expr, BindingRestrictions restrictions, DynamicMetaObject errorSuggestion)
+               public static DynamicMetaObject Bind (DynamicMetaObjectBinder binder, Compiler.Expression expr, BindingRestrictions restrictions, DynamicMetaObject errorSuggestion)
                {
-                       var report = new Compiler.Report (ErrorPrinter.Instance) { WarningLevel = 0 };
-                       var ctx = new Compiler.CompilerContext (report);
-                       Compiler.RootContext.ToplevelTypes = new Compiler.ModuleContainer (ctx, true);
+                       return Bind (binder, expr, null, restrictions, errorSuggestion);
+               }
+
+               public static DynamicMetaObject Bind (DynamicMetaObjectBinder binder, Compiler.Expression expr, Type callingType, BindingRestrictions restrictions, DynamicMetaObject errorSuggestion)
+               {
+                       var ctx = CreateDefaultCompilerContext ();
 
                        InitializeCompiler (ctx);
 
                        Expression res;
                        try {
                                // TODO: ResolveOptions
-                               Compiler.ResolveContext rc = new Compiler.ResolveContext (new RuntimeBinderContext (ctx));
+                               Compiler.ResolveContext rc = new Compiler.ResolveContext (new RuntimeBinderContext (ctx, callingType));
 
                                // Static typemanager and internal caches are not thread-safe
                                lock (resolver) {
@@ -67,10 +70,7 @@ namespace Microsoft.CSharp.RuntimeBinder
                                if (errorSuggestion != null)
                                        return errorSuggestion;
 
-                               if (binder_exception_ctor == null)
-                                       binder_exception_ctor = typeof (RuntimeBinderException).GetConstructor (new[] { typeof (string) });
-
-                               res = Expression.Throw (Expression.New (binder_exception_ctor, Expression.Constant (e.Message)));
+                               res = CreateBinderException (binder, e.Message);
                        } catch (Exception) {
                                if (errorSuggestion != null)
                                        return errorSuggestion;
@@ -81,30 +81,89 @@ namespace Microsoft.CSharp.RuntimeBinder
                        return new DynamicMetaObject (res, restrictions);
                }
 
+               public static Expression CreateBinderException (DynamicMetaObjectBinder binder, string message)
+               {
+                       if (binder_exception_ctor == null)
+                               binder_exception_ctor = typeof (RuntimeBinderException).GetConstructor (new[] { typeof (string) });
+
+                       //
+                       // Uses target type to keep expressions composition working
+                       //
+                       return Expression.Throw (Expression.New (binder_exception_ctor, Expression.Constant (message)), binder.ReturnType);
+               }
+
                //
                // Creates mcs expression from dynamic method object
                //
                public static Compiler.Expression CreateCompilerExpression (CSharpArgumentInfo info, DynamicMetaObject value)
                {
-                       if (info.IsNamed)
-                               throw new NotImplementedException ("IsNamed");
-
                        if (value.Value == null)
                                return new Compiler.NullLiteral (value.LimitType, Compiler.Location.Null);
 
-                       if ((info.Flags & CSharpArgumentInfoFlags.LiteralConstant) != 0)
-                               return Compiler.Constant.CreateConstant (value.RuntimeType ?? value.LimitType, value.Value, Compiler.Location.Null);
+                       if (info != null) {
+                               if ((info.Flags & CSharpArgumentInfoFlags.LiteralConstant) != 0) {
+                                       InitializeCompiler (null);
+                                       return Compiler.Constant.CreateConstant (value.RuntimeType ?? value.LimitType, value.Value, Compiler.Location.Null);
+                               }
+
+                               if ((info.Flags & CSharpArgumentInfoFlags.IsStaticType) != 0)
+                                       return new Compiler.TypeExpression ((Type) value.Value, Compiler.Location.Null);
+                       }
 
                        return new Compiler.RuntimeValueExpression (value);
                }
 
+               public static Compiler.Arguments CreateCompilerArguments (IEnumerable<CSharpArgumentInfo> info, DynamicMetaObject[] args)
+               {
+                       var res = new Compiler.Arguments (args.Length);
+                       int pos = 0;
+                       foreach (var item in info) {
+                               var expr = CreateCompilerExpression (item, args [pos]);
+                               if (item.IsNamed) {
+                                       res.Add (new Compiler.NamedArgument (new Compiler.LocatedToken (Compiler.Location.Null, item.Name), expr));
+                               } else {
+                                       res.Add (new Compiler.Argument (expr, item.ArgumentModifier));
+                               }
+                       }
+
+                       return res;
+               }
+
+               static Compiler.CompilerContext CreateDefaultCompilerContext ()
+               {
+                       return new Compiler.CompilerContext (
+                               new Compiler.Report (ErrorPrinter.Instance) {
+                                       WarningLevel = 0 
+                               }
+                       );
+               }
+
+               public static BindingRestrictions CreateRestrictionsOnTarget (DynamicMetaObject arg)
+               {
+                       return arg.HasValue && arg.Value == null ?
+                               BindingRestrictions.GetInstanceRestriction (arg.Expression, null) :
+                               BindingRestrictions.GetTypeRestriction (arg.Expression, arg.LimitType);
+               }
+
+               public static BindingRestrictions CreateRestrictionsOnTarget (DynamicMetaObject[] args)
+               {
+                       if (args.Length == 0)
+                               return BindingRestrictions.Empty;
+
+                       var res = CreateRestrictionsOnTarget (args[0]);
+                       for (int i = 1; i < args.Length; ++i)
+                               res = res.Merge (CreateRestrictionsOnTarget (args[i]));
+
+                       return res;
+               }
+
                static void InitializeCompiler (Compiler.CompilerContext ctx)
                {
-                       if (compiler_initialized)
+                       if (Compiler.TypeManager.object_type != null)
                                return;
 
                        lock (compiler_initializer) {
-                               if (compiler_initialized)
+                               if (Compiler.TypeManager.object_type != null)
                                        return;
 
                                // TODO: This smells like pretty big issue
@@ -114,9 +173,14 @@ namespace Microsoft.CSharp.RuntimeBinder
                                foreach (System.Reflection.Assembly a in AppDomain.CurrentDomain.GetAssemblies ())
                                        Compiler.GlobalRootNamespace.Instance.AddAssemblyReference (a);
 
+                               if (ctx == null)
+                                       ctx = CreateDefaultCompilerContext ();
+
+                               // FIXME: this is wrong
+                               Compiler.RootContext.ToplevelTypes = new Compiler.ModuleContainer (ctx, true);
+
                                Compiler.TypeManager.InitCoreTypes (ctx);
                                Compiler.TypeManager.InitOptionalCoreTypes (ctx);
-                               compiler_initialized = true;
                        }
                }