2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / ComInvokeAction.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Microsoft Public License. A 
6  * copy of the license can be found in the License.html file at the root of this distribution. If 
7  * you cannot locate the  Microsoft Public License, please send an email to 
8  * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
9  * by the terms of the Microsoft Public License.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15 using System; using Microsoft;
16
17
18 #if !SILVERLIGHT
19
20 using System.Collections.ObjectModel;
21 using System.Diagnostics;
22 #if CODEPLEX_40
23 using System.Linq.Expressions;
24 #else
25 using Microsoft.Linq.Expressions;
26 #endif
27 using System.Runtime.CompilerServices;
28 #if !CODEPLEX_40
29 using Microsoft.Runtime.CompilerServices;
30 #endif
31
32
33 #if CODEPLEX_40
34 namespace System.Dynamic {
35 #else
36 namespace Microsoft.Scripting {
37 #endif
38     /// <summary>
39     /// Invokes the object. If it falls back, just produce an error.
40     /// </summary>
41     internal sealed class ComInvokeAction : InvokeBinder {
42         internal ComInvokeAction(CallInfo callInfo)
43             : base(callInfo) {
44         }
45
46         public override int GetHashCode() {
47             return base.GetHashCode();
48         }
49
50         public override bool Equals(object obj) {
51             return base.Equals(obj as ComInvokeAction);
52         }
53
54         public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion) {
55             return errorSuggestion ?? new DynamicMetaObject(
56                 Expression.Throw(
57                     Expression.New(
58                         typeof(NotSupportedException).GetConstructor(new[] { typeof(string) }),
59                         Expression.Constant(Strings.CannotCall)
60                     )
61                 ),
62                 target.Restrictions.Merge(BindingRestrictions.Combine(args))
63             );
64         }
65     }
66
67     /// <summary>
68     /// Splats the arguments to another nested dynamic site, which does the
69     /// real invocation of the IDynamicMetaObjectProvider. 
70     /// </summary>
71     internal sealed class SplatInvokeBinder : CallSiteBinder {
72         internal readonly static SplatInvokeBinder Instance = new SplatInvokeBinder();
73
74         // Just splat the args and dispatch through a nested site
75         public override Expression Bind(object[] args, ReadOnlyCollection<ParameterExpression> parameters, LabelTarget returnLabel) {
76             Debug.Assert(args.Length == 2);
77
78             int count = ((object[])args[1]).Length;
79             ParameterExpression array = parameters[1];
80
81             var nestedArgs = new ReadOnlyCollectionBuilder<Expression>(count + 1);
82             var delegateArgs = new Type[count + 3]; // args + target + returnType + CallSite
83             nestedArgs.Add(parameters[0]);
84             delegateArgs[0] = typeof(CallSite);
85             delegateArgs[1] = typeof(object);
86             for (int i = 0; i < count; i++) {
87                 nestedArgs.Add(Expression.ArrayAccess(array, Expression.Constant(i)));
88                 delegateArgs[i + 2] = typeof(object).MakeByRefType();
89             }
90             delegateArgs[delegateArgs.Length - 1] = typeof(object);
91
92             return Expression.IfThen(
93                 Expression.Equal(Expression.ArrayLength(array), Expression.Constant(count)),
94                 Expression.Return(
95                     returnLabel,
96                     Expression.MakeDynamic(
97                         Expression.GetDelegateType(delegateArgs),
98                         new ComInvokeAction(new CallInfo(count)),
99                         nestedArgs
100                     )
101                 )
102             );
103         }
104     }
105 }
106
107 #endif