2009-10-14 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / class / Microsoft.CSharp / Microsoft.CSharp.RuntimeBinder / CSharpBinder.cs
1 //
2 // CSharpBinder.cs
3 //
4 // Authors:
5 //      Marek Safar  <marek.safar@gmail.com>
6 //
7 // Copyright (C) 2009 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30 using System.Dynamic;
31 using System.Linq.Expressions;
32 using Compiler = Mono.CSharp;
33 using System.Reflection;
34 using System.Collections.Generic;
35
36 namespace Microsoft.CSharp.RuntimeBinder
37 {
38         static class CSharpBinder
39         {
40                 static ConstructorInfo binder_exception_ctor;
41                 static object compiler_initializer = new object ();
42                 static object resolver = new object ();
43
44                 public static DynamicMetaObject Bind (DynamicMetaObject target, Compiler.Expression expr, BindingRestrictions restrictions, DynamicMetaObject errorSuggestion)
45                 {
46                         return Bind (target, expr, null, restrictions, errorSuggestion);
47                 }
48
49                 public static DynamicMetaObject Bind (DynamicMetaObject target, Compiler.Expression expr, Type callingType, BindingRestrictions restrictions, DynamicMetaObject errorSuggestion)
50                 {
51                         var ctx = CreateDefaultCompilerContext ();
52
53                         InitializeCompiler (ctx);
54
55                         Expression res;
56                         try {
57                                 // TODO: ResolveOptions
58                                 Compiler.ResolveContext rc = new Compiler.ResolveContext (new RuntimeBinderContext (ctx, callingType));
59
60                                 // Static typemanager and internal caches are not thread-safe
61                                 lock (resolver) {
62                                         expr = expr.Resolve (rc);
63                                 }
64
65                                 if (expr == null)
66                                         throw new RuntimeBinderInternalCompilerException ("Expression resolved to null");
67
68                                 res = expr.MakeExpression (new Compiler.BuilderContext ());
69                         } catch (RuntimeBinderException e) {
70                                 if (errorSuggestion != null)
71                                         return errorSuggestion;
72
73                                 res = CreateBinderException (target, e.Message);
74                         } catch (Exception) {
75                                 if (errorSuggestion != null)
76                                         return errorSuggestion;
77
78                                 throw;
79                         }
80
81                         return new DynamicMetaObject (res, restrictions);
82                 }
83
84                 public static Expression CreateBinderException (DynamicMetaObject target, string message)
85                 {
86                         if (binder_exception_ctor == null)
87                                 binder_exception_ctor = typeof (RuntimeBinderException).GetConstructor (new[] { typeof (string) });
88
89                         //
90                         // Uses target type to keep expressions composition working
91                         //
92                         return Expression.Throw (Expression.New (binder_exception_ctor, Expression.Constant (message)), target.LimitType);
93                 }
94
95                 //
96                 // Creates mcs expression from dynamic method object
97                 //
98                 public static Compiler.Expression CreateCompilerExpression (CSharpArgumentInfo info, DynamicMetaObject value)
99                 {
100                         if (value.Value == null)
101                                 return new Compiler.NullLiteral (value.LimitType, Compiler.Location.Null);
102
103                         if (info != null && (info.Flags & CSharpArgumentInfoFlags.LiteralConstant) != 0) {
104                                 InitializeCompiler (null);
105                                 return Compiler.Constant.CreateConstant (value.RuntimeType ?? value.LimitType, value.Value, Compiler.Location.Null);
106                         }
107
108                         return new Compiler.RuntimeValueExpression (value);
109                 }
110
111                 public static Compiler.Arguments CreateCompilerArguments (IEnumerable<CSharpArgumentInfo> info, DynamicMetaObject[] args)
112                 {
113                         var res = new Compiler.Arguments (args.Length);
114                         int pos = 0;
115                         foreach (var item in info) {
116                                 var expr = CreateCompilerExpression (item, args [pos]);
117                                 if (item.IsNamed) {
118                                         res.Add (new Compiler.NamedArgument (new Compiler.LocatedToken (Compiler.Location.Null, item.Name), expr));
119                                 } else {
120                                         res.Add (new Compiler.Argument (expr, item.ArgumentModifier));
121                                 }
122                         }
123
124                         return res;
125                 }
126
127                 static Compiler.CompilerContext CreateDefaultCompilerContext ()
128                 {
129                         return new Compiler.CompilerContext (
130                                 new Compiler.Report (ErrorPrinter.Instance) {
131                                         WarningLevel = 0 
132                                 }
133                         );
134                 }
135
136                 public static BindingRestrictions CreateRestrictionsOnTarget (DynamicMetaObject arg)
137                 {
138                         return arg.HasValue && arg.Value == null ?
139                                 BindingRestrictions.GetInstanceRestriction (arg.Expression, null) :
140                                 BindingRestrictions.GetTypeRestriction (arg.Expression, arg.LimitType);
141                 }
142
143                 public static BindingRestrictions CreateRestrictionsOnTarget (DynamicMetaObject[] args)
144                 {
145                         var res = CreateRestrictionsOnTarget (args[0]);
146                         for (int i = 1; i < args.Length; ++i)
147                                 res = res.Merge (CreateRestrictionsOnTarget (args[i]));
148
149                         return res;
150                 }
151
152                 static void InitializeCompiler (Compiler.CompilerContext ctx)
153                 {
154                         if (Compiler.TypeManager.object_type != null)
155                                 return;
156
157                         lock (compiler_initializer) {
158                                 if (Compiler.TypeManager.object_type != null)
159                                         return;
160
161                                 // TODO: This smells like pretty big issue
162                                 // AppDomain.CurrentDomain.AssemblyLoad += (sender, e) => { throw new NotImplementedException (); };
163
164                                 // Add all currently loaded assemblies
165                                 foreach (System.Reflection.Assembly a in AppDomain.CurrentDomain.GetAssemblies ())
166                                         Compiler.GlobalRootNamespace.Instance.AddAssemblyReference (a);
167
168                                 if (ctx == null)
169                                         ctx = CreateDefaultCompilerContext ();
170
171                                 // FIXME: this is wrong
172                                 Compiler.RootContext.ToplevelTypes = new Compiler.ModuleContainer (ctx, true);
173
174                                 Compiler.TypeManager.InitCoreTypes (ctx);
175                                 Compiler.TypeManager.InitOptionalCoreTypes (ctx);
176                         }
177                 }
178
179                 public static DynamicMetaObject Bind (DynamicMetaObject target, DynamicMetaObject errorSuggestion, DynamicMetaObject[] args)
180                 {
181                         return Bind (target, errorSuggestion);
182                 }
183
184                 public static DynamicMetaObject Bind (DynamicMetaObject target, DynamicMetaObject errorSuggestion)
185                 {
186                         return errorSuggestion ??
187                                    new DynamicMetaObject (
188                                                    Expression.Constant (new object ()),
189                                                    target.Restrictions.Merge (
190                                                            BindingRestrictions.GetTypeRestriction (
191                                                                    target.Expression, target.LimitType)));
192                 }
193         }
194 }