2009-10-20 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) {
104                                 if ((info.Flags & CSharpArgumentInfoFlags.LiteralConstant) != 0) {
105                                         InitializeCompiler (null);
106                                         return Compiler.Constant.CreateConstant (value.RuntimeType ?? value.LimitType, value.Value, Compiler.Location.Null);
107                                 }
108
109                                 if ((info.Flags & CSharpArgumentInfoFlags.IsStaticType) != 0)
110                                         return new Compiler.TypeExpression ((Type) value.Value, Compiler.Location.Null);
111                         }
112
113                         return new Compiler.RuntimeValueExpression (value);
114                 }
115
116                 public static Compiler.Arguments CreateCompilerArguments (IEnumerable<CSharpArgumentInfo> info, DynamicMetaObject[] args)
117                 {
118                         var res = new Compiler.Arguments (args.Length);
119                         int pos = 0;
120                         foreach (var item in info) {
121                                 var expr = CreateCompilerExpression (item, args [pos]);
122                                 if (item.IsNamed) {
123                                         res.Add (new Compiler.NamedArgument (new Compiler.LocatedToken (Compiler.Location.Null, item.Name), expr));
124                                 } else {
125                                         res.Add (new Compiler.Argument (expr, item.ArgumentModifier));
126                                 }
127                         }
128
129                         return res;
130                 }
131
132                 static Compiler.CompilerContext CreateDefaultCompilerContext ()
133                 {
134                         return new Compiler.CompilerContext (
135                                 new Compiler.Report (ErrorPrinter.Instance) {
136                                         WarningLevel = 0 
137                                 }
138                         );
139                 }
140
141                 public static BindingRestrictions CreateRestrictionsOnTarget (DynamicMetaObject arg)
142                 {
143                         return arg.HasValue && arg.Value == null ?
144                                 BindingRestrictions.GetInstanceRestriction (arg.Expression, null) :
145                                 BindingRestrictions.GetTypeRestriction (arg.Expression, arg.LimitType);
146                 }
147
148                 public static BindingRestrictions CreateRestrictionsOnTarget (DynamicMetaObject[] args)
149                 {
150                         if (args.Length == 0)
151                                 return BindingRestrictions.Empty;
152
153                         var res = CreateRestrictionsOnTarget (args[0]);
154                         for (int i = 1; i < args.Length; ++i)
155                                 res = res.Merge (CreateRestrictionsOnTarget (args[i]));
156
157                         return res;
158                 }
159
160                 static void InitializeCompiler (Compiler.CompilerContext ctx)
161                 {
162                         if (Compiler.TypeManager.object_type != null)
163                                 return;
164
165                         lock (compiler_initializer) {
166                                 if (Compiler.TypeManager.object_type != null)
167                                         return;
168
169                                 // TODO: This smells like pretty big issue
170                                 // AppDomain.CurrentDomain.AssemblyLoad += (sender, e) => { throw new NotImplementedException (); };
171
172                                 // Add all currently loaded assemblies
173                                 foreach (System.Reflection.Assembly a in AppDomain.CurrentDomain.GetAssemblies ())
174                                         Compiler.GlobalRootNamespace.Instance.AddAssemblyReference (a);
175
176                                 if (ctx == null)
177                                         ctx = CreateDefaultCompilerContext ();
178
179                                 // FIXME: this is wrong
180                                 Compiler.RootContext.ToplevelTypes = new Compiler.ModuleContainer (ctx, true);
181
182                                 Compiler.TypeManager.InitCoreTypes (ctx);
183                                 Compiler.TypeManager.InitOptionalCoreTypes (ctx);
184                         }
185                 }
186
187                 public static DynamicMetaObject Bind (DynamicMetaObject target, DynamicMetaObject errorSuggestion, DynamicMetaObject[] args)
188                 {
189                         return Bind (target, errorSuggestion);
190                 }
191
192                 public static DynamicMetaObject Bind (DynamicMetaObject target, DynamicMetaObject errorSuggestion)
193                 {
194                         return errorSuggestion ??
195                                    new DynamicMetaObject (
196                                                    Expression.Constant (new object ()),
197                                                    target.Restrictions.Merge (
198                                                            BindingRestrictions.GetTypeRestriction (
199                                                                    target.Expression, target.LimitType)));
200                 }
201         }
202 }