5 // Marek Safar <marek.safar@gmail.com>
7 // Copyright (C) 2009 Novell, Inc (http://www.novell.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
31 using System
.Linq
.Expressions
;
32 using Compiler
= Mono
.CSharp
;
33 using System
.Reflection
;
34 using System
.Collections
.Generic
;
36 namespace Microsoft
.CSharp
.RuntimeBinder
40 static ConstructorInfo binder_exception_ctor
;
41 static object compiler_initializer
= new object ();
42 static object resolver
= new object ();
44 DynamicMetaObjectBinder binder
;
45 Compiler
.Expression expr
;
46 BindingRestrictions restrictions
;
47 DynamicMetaObject errorSuggestion
;
49 public CSharpBinder (DynamicMetaObjectBinder binder
, Compiler
.Expression expr
, DynamicMetaObject errorSuggestion
)
53 this.restrictions
= BindingRestrictions
.Empty
;
54 this.errorSuggestion
= errorSuggestion
;
57 public Compiler
.ResolveContext
.Options ResolveOptions { get; set; }
59 public void AddRestrictions (DynamicMetaObject arg
)
61 restrictions
= restrictions
.Merge (CreateRestrictionsOnTarget (arg
));
64 public void AddRestrictions (DynamicMetaObject
[] args
)
66 restrictions
= restrictions
.Merge (CreateRestrictionsOnTarget (args
));
69 public DynamicMetaObject
Bind (Type callingType
, DynamicMetaObject target
)
71 if (target
.Value
== null) {
72 if (errorSuggestion
!= null)
73 return errorSuggestion
;
75 var ex
= CreateBinderException ("Cannot perform member binding on `null' value");
76 return new DynamicMetaObject (ex
, restrictions
);
79 return Bind (callingType
);
82 public DynamicMetaObject
Bind (Type callingType
)
84 var ctx
= CreateDefaultCompilerContext ();
86 InitializeCompiler (ctx
);
90 var rc
= new Compiler
.ResolveContext (new RuntimeBinderContext (ctx
, callingType
), ResolveOptions
);
92 // Static typemanager and internal caches are not thread-safe
94 expr
= expr
.Resolve (rc
, Compiler
.ResolveFlags
.VariableOrValue
);
98 throw new RuntimeBinderInternalCompilerException ("Expression resolved to null");
100 res
= expr
.MakeExpression (new Compiler
.BuilderContext ());
101 } catch (RuntimeBinderException e
) {
102 if (errorSuggestion
!= null)
103 return errorSuggestion
;
105 res
= CreateBinderException (e
.Message
);
106 } catch (Exception
) {
107 if (errorSuggestion
!= null)
108 return errorSuggestion
;
113 return new DynamicMetaObject (res
, restrictions
);
116 Expression
CreateBinderException (string message
)
118 if (binder_exception_ctor
== null)
119 binder_exception_ctor
= typeof (RuntimeBinderException
).GetConstructor (new[] { typeof (string) }
);
122 // Uses target type to keep expressions composition working
124 return Expression
.Throw (Expression
.New (binder_exception_ctor
, Expression
.Constant (message
)), binder
.ReturnType
);
128 // Creates mcs expression from dynamic method object
130 public static Compiler
.Expression
CreateCompilerExpression (CSharpArgumentInfo info
, DynamicMetaObject
value)
132 if (value.Value
== null) {
133 if (value.LimitType
== typeof (object))
134 return new Compiler
.NullLiteral (Compiler
.Location
.Null
);
136 InitializeCompiler (null);
137 return Compiler
.Constant
.CreateConstantFromValue (value.LimitType
, null, Compiler
.Location
.Null
);
140 bool is_compile_time
;
143 if ((info
.Flags
& CSharpArgumentInfoFlags
.Constant
) != 0) {
144 InitializeCompiler (null);
145 return Compiler
.Constant
.CreateConstantFromValue (value.LimitType
, value.Value
, Compiler
.Location
.Null
);
148 if ((info
.Flags
& CSharpArgumentInfoFlags
.IsStaticType
) != 0)
149 return new Compiler
.TypeExpression ((Type
) value.Value
, Compiler
.Location
.Null
);
151 is_compile_time
= (info
.Flags
& CSharpArgumentInfoFlags
.UseCompileTimeType
) != 0;
153 is_compile_time
= false;
156 return new Compiler
.RuntimeValueExpression (value, is_compile_time
);
159 public static Compiler
.Arguments
CreateCompilerArguments (IEnumerable
<CSharpArgumentInfo
> info
, DynamicMetaObject
[] args
)
161 var res
= new Compiler
.Arguments (args
.Length
);
164 // enumerates over args
165 foreach (var item
in info
) {
166 var expr
= CreateCompilerExpression (item
, args
[pos
++]);
168 res
.Add (new Compiler
.NamedArgument (item
.Name
, Compiler
.Location
.Null
, expr
));
170 res
.Add (new Compiler
.Argument (expr
, item
.ArgumentModifier
));
173 if (pos
== args
.Length
)
180 public static Compiler
.CompilerContext
CreateDefaultCompilerContext ()
182 return new Compiler
.CompilerContext (
183 new Compiler
.Report (ErrorPrinter
.Instance
) {
186 IsRuntimeBinder
= true
190 static BindingRestrictions
CreateRestrictionsOnTarget (DynamicMetaObject arg
)
192 return arg
.HasValue
&& arg
.Value
== null ?
193 BindingRestrictions
.GetInstanceRestriction (arg
.Expression
, null) :
194 BindingRestrictions
.GetTypeRestriction (arg
.Expression
, arg
.LimitType
);
197 public static BindingRestrictions
CreateRestrictionsOnTarget (DynamicMetaObject
[] args
)
199 if (args
.Length
== 0)
200 return BindingRestrictions
.Empty
;
202 var res
= CreateRestrictionsOnTarget (args
[0]);
203 for (int i
= 1; i
< args
.Length
; ++i
)
204 res
= res
.Merge (CreateRestrictionsOnTarget (args
[i
]));
209 public static void InitializeCompiler (Compiler
.CompilerContext ctx
)
211 if (Compiler
.TypeManager
.object_type
!= null)
214 lock (compiler_initializer
) {
215 if (Compiler
.TypeManager
.object_type
!= null)
218 // I don't think dynamically loaded assemblies can be used as dynamic
219 // expression without static type be loaded first
220 // AppDomain.CurrentDomain.AssemblyLoad += (sender, e) => { throw new NotImplementedException (); };
222 // Import all currently loaded assemblies
223 foreach (System
.Reflection
.Assembly a
in AppDomain
.CurrentDomain
.GetAssemblies ())
224 Compiler
.GlobalRootNamespace
.Instance
.AddAssemblyReference (a
);
227 ctx
= CreateDefaultCompilerContext ();
229 Compiler
.TypeManager
.InitCoreTypes (ctx
);
230 Compiler
.TypeManager
.InitOptionalCoreTypes (ctx
);